OAuth 2.0, web kaynaklarına erişim yetkilendirmesini kökten değiştirdi ancak önemli bir güvenlik açığı getirdi: token çalınması. Bir saldırgan geçerli bir erişim tokenı ele geçirdiğinde, token süresi dolana kadar kullanıcı yerine geçmek için bunu sıklıkla kullanabilir; bu durum, tokenın orijinal güvenli kanal üzerinden iletilip iletilmediğinden bağımsızdır. Taşıma Katmanı Güvenliği (TLS) tokenları iletim sırasında korur, ancak bunları onlara verilen belirli istemciyle bağlamaz. İşte burada Delegation of Proof-of-Possession (DPoP) devreye girer.
RFC 9449'da standartlaştırılan DPoP, OAuth 2.0'ı, erişim tokenlarının bunları tutan istemcinin genel anahtarına kriptografik olarak bağlanmasını sağlayarak genişletir. Bu blog yazısı, DPoP'un mekaniklerini inceleyecek ve API güvenlik duruşunu geliştirmek isteyen ara ve ileri düzey geliştiriciler için pratik bir uygulama rehberi sunacaktır.
DPoP Mekanizmasını Anlamak
DPoP'nin temel kavramı basit ancak güçlüdür: İstemci, istekte gönderilen genel anahtara karşılık gelen özel anahtara sahip olduğunu kanıtlamalıdır. İstemci tokenı sadece göndermek yerine, özel anahtarı kullanarak bir JSON Web Token (JWT) oluşturur. DPoP kanıtı olarak bilinen bu JWT, erişim tokenı ile birlikte özel bir üst bilgi (header) içinde gönderilir.
DPoP akışının temel bileşenleri şunlardır:
- DPoP Anahtar Oluşturma: İstemci bir anahtar çifti oluşturur (genellikle Ed25519 veya RSA).
- DPoP Kanıtı Oluşturma: Genel anahtarı, geçerli zaman damgasını ve token URL'sini içeren bir JWT imzalanır.
- Üst Bilgi Enjeksiyonu: Kanıt
DPoPüst bilgisi içinde gönderilir ve genel anahtar parmak iziDPOPüst bilgisi içinde gönderilir. - Sunucu Doğrulaması: Kaynak sunucusu imzayı doğrular, zaman damgalarını kontrol eder ve tokenın aynı uç noktada kullanıldığından emin olur.
Node.js'de İstemci Tarafı Uygulaması
Node.js ve popüler axios kütüphanesini kullanarak pratik bir örneğe bakalım. İlk olarak, JWT oluşturma ve kriptografik imzalama işlemlerini yöneten bir kütüphaneye ihtiyacınız vardır. Bu örnek için JWT işlemleri için jose kütüphanesinin kullanılacağını varsayacağız.
İşte bir DPoP kanıtı oluşturup bir API isteğine eklemenizin yolu:
const jose = require('jose');
const axios = require('axios');
async function makeDPOPRequest() {
// 1. Bir Anahtar Çifti Oluşturun (Ed25519 önerilir)
const { publicKey, privateKey } = await jose.generateKeyPair('EdDSA');
// 2. DPoP JWT Üst Bilgisini Oluşturun
const publicKeyJWK = await jose.exportJWK(publicKey);
const dpopHeader = {
typ: 'dpop+jwt',
alg: 'EdDSA',
jwk: publicKeyJWK
};
// 3. DPoP JWT Yükünü (Payload) Oluşturun
const url = 'https://api.example.com/resource';
const now = Math.floor(Date.now() / 1000);
const payload = {
iss: 'client_id',
jti: crypto.randomUUID(),
aud: url, // API uç noktası
iat: now,
exp: now + 60 // Kısa ömürlü, genellikle 60 saniye
};
// 4. JWT'yi Özel Anahtarla İmzalayın
const signer = await jose.importJWK(publicKeyJWK, 'EdDSA'); // Not: jose, türetilmiş veya geçirilen özel anahtarla imzalama işlemini yönetir
// İmzalama için özel anahtarı doğru şekilde içe aktarma:
const dpopSignedJwt = await new jose.SignJWT(payload)
.setProtectedHeader(dpopHeader)
.setIssuedAt()
.setExpirationTime('2m')
.sign(privateKey);
// 5. Genel Anahtarın Parmak İzi Hesaplaması
const thumbprint = await jose.calculateJwkThumbprint(publicKeyJWK, 'sha256');
// 6. HTTP İsteğini Yapın
const response = await axios.get(url, {
headers: {
'Authorization': 'Bearer ACCESS_TOKEN',
'DPoP': dpopSignedJwt,
'DPOP': thumbprint
}
});
return response.data;
}
Sunucu Tarafı Doğrulama Gereksinimleri
İstemciyi uygulamak savaşın sadece yarısıdır. Kaynak sunucusu da DPoP kanıtlarını doğrulamak için yapılandırılmalıdır. Sunucu bir DPOP üst bilgisi içeren bir istek aldığında, aşağıdaki kontrolleri gerçekleştirmelidir:
- İmza Doğrulaması:
DPoPüst bilgisi içindeki JWT'yi çözün vejwktalebinde sağlanan genel anahtarı kullanarak imzayı doğrulayın. - Zaman Damgası Doğrulaması: Replay saldırılarını önlemek için
iat(issued at) talebinin çok eski olmadığını (genellikle 60 saniye içinde) emin olun. - URL Eşleştirme:
audtalebinin kaynak sunucusunun URL'siyle eşleştiğini doğrulayın. - Token Bağlama: Erişim tokenını genel anahtara bağlayın. Erişim tokenı bir bağlama parametresi ile verilmişse, sunucunun DPoP kanıtındaki genel anahtarın beklenen bağlamayla eşleştiğinden emin olması gerekir.
Auth0, Keycloak ve Microsoft Identity Web gibi çoğu modern kimlik sağlayıcıları artık DPoP'u varsayılan olarak desteklemektedir. Özel uygulamalar için passport-oauth2-provider veya Owin.Security.Providers gibi kütüphaneler, DPoP doğrulaması için deneysel veya kararlı destek eklemiştir.
Sonuç
DPoP aracılığıyla OAuth2 Token Bağlama uygulamak, saldırganlar için barı önemli ölçüde yükseltir. Çalınan tokenların, karşılık gelen özel anahtar olmadan işe yaramaz hale getirilmesini sağlayarak token replay ve çalınma riskini azaltırsınız. Hem istemci hem de sunucu taraflarındaki uygulama karmaşıklığı biraz artsa da, yüksek değerli API'ler için güvenlik faydaları büyüktür. Web ekosistemi sıfır güven (zero-trust) mimarilerine doğru ilerledikçe, DPoP'u benimsemek artık sadece bir en iyi uygulama değil; aynı zamanda bir zorunluluk haline gelmektedir.