Bir JSON Web Token gerçekte ne içerir
Bir JSON Web Token (JWT), noktalarla birleştirilmiş üç metin parçasıdır. Her parça Base64url ile kodlanmıştır ve ilk ikisi düpedüz JSON'dur. Tokena sahip olan herkes içindekini okuyabilir. Normal bir JWT'de hiçbir şey şifreli değildir.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 <- header
eyJzdWIiOiIxMjM0NSIsIm5hbWUiOiJBbGV4In0 <- payload
dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFW <- signature
Noktalarla birleştirildiğinde bu, bir isteğe yapıştırdığınız tokendır. İlk iki parçayı çözün, karşınıza sıradan JSON çıkar:
{ "alg": "HS256", "typ": "JWT" }
{ "sub": "12345", "name": "Alex" }
Gerçek bir yük genellikle zaman damgaları ve bir hedef kitle de taşır:
{
"iss": "https://auth.example.com",
"sub": "12345",
"aud": "api.example.com",
"iat": 1756000000,
"exp": 1756003600,
"roles": ["editor"]
}
Başlık
Başlık, tokenın nasıl imzalandığını tarif eder. En çok iki alan önem taşır:
alg, imzalama algoritmasının adıdır; örneğinHS256(ortak bir sırla, SHA-256 üzerinden HMAC) ya daRS256(SHA-256 ile RSA imzası; özel anahtarla imzalanır, açık anahtarla denetlenir).- Anahtar kimliği olan
kidisteğe bağlıdır ve alıcıya birkaç anahtardan hangisinin kullanıldığını söyler; böylece var olan tokenları kırmadan anahtarlar döndürülebilir.
typ genellikle yalnızca JWT değerini taşır ve güvenlik açısından bir anlamı yoktur.
Yük ve talepleri
Yük, taleplerden oluşan bir JSON nesnesidir; talep, şartnamenin tokenın öznesi hakkındaki ifadelere verdiği addan başka bir şey değildir. Bazı talep adları standartta kayıtlıdır ve hepsi kısadır:
| Talep | Adı | Ne tutar |
|---|---|---|
iss | Veren | Tokenı kimin oluşturduğu, genellikle bir URL ya da hizmet adı |
sub | Özne | Tokenın kim hakkında olduğu, genellikle sabit bir kullanıcı kimliği |
aud | Hedef kitle | Tokenın kimin için tasarlandığı; böylece bir hizmet başkası için verilmiş tokenları reddedebilir |
exp | Son geçerlilik zamanı | Tokenın bundan sonra reddedilmesi gereken an |
nbf | Şundan önce değil | Tokenın bundan önce reddedilmesi gereken an |
iat | Verilme zamanı | Tokenın ne zaman oluşturulduğu |
jti | JWT kimliği | Benzersiz bir tanımlayıcı; tek tek tokenları izlemek ya da engellemek için işe yarar |
exp, nbf ve iat değerlerinin hepsi NumericDate değerleridir, yani 1 Ocak 1970 UTC tarihinden bu yana geçen saniye sayısıdır. Bunlar saniyedir, milisaniye değil. Bir zaman damgası 57.000 yılına denk gelen bir tarihe çözülüyorsa milisaniye okuyorsunuz demektir ve bine bölmeniz gerekir.
Yükteki diğer her şey, tokenı verenin oraya koyduğu şeydir: roller, izinler, bir e-posta adresi, bir kiracı kimliği. Özel bir talep adı bir gün kayıtlı bir adla çakışabileceği için, token verenler kendi adlarını çoğu zaman URL benzeri bir önekle ad alanına alır.
İmza
İmza, ilk iki parçanın nokta ile birleştirilmiş tam metni üzerinden, başlıktaki algoritma ve bir anahtar kullanılarak hesaplanır. Başlığın ya da yükün tek bir karakterini değiştirin, imza artık tutmaz.
HS256 ile aynı sır hem imzalar hem doğrular, dolayısıyla bir tokenı denetleyebilen herkes yenisini de basabilir. RS256 ya da ES256 ile özel anahtar imzalar, açık anahtar doğrular; bir kimlik sağlayıcının, hiçbir sır tutmadan birçok ayrı hizmetin doğrulayabileceği tokenlar dağıtmasını sağlayan da budur.
Base64url şifreleme değildir
Base64url, Base64 ile aynı fikirdir ve iki farkı vardır: sonuç URL'lerde güvenli olsun diye + ve / yerine - ve _ kullanır ve sondaki = dolgusu genellikle atılır. Bir kodlamadır, yani baytları metin olarak yazmanın geri alınabilir bir yoludur. Hiçbir biçimde gizlilik sağlamaz.
Bu yüzden bir JWT yüküne asla hassas bir şey koymayın: parola yok, kart numarası yok, kullanıcı hakkında iç notlar yok. Tokenı elinde tutan kişinin ve onu bir günlük dosyasından ya da tarayıcı deposundan okuyan herkesin her alanı görebildiğini varsayın.
Yükü gerçekten şifreleyen ayrı bir biçim vardır, adı JWE'dir ve üç değil beş parçalıdır. Tokenınız üç parçalıysa imzalanmıştır ve okunabilirdir.
Çözmek doğrulamak değildir
Asıl önemli nokta budur. Bir çözücü size tokenın ne dediğini gösterir. Tokenın gerçek olup olmadığını söylemez. Doğrulama ayrı bir adımdır ve anahtar gerektirir.
Bir tokena gerçekten güvenmek için sunucunun şunları yapması gerekir:
- İmzayı doğru anahtara karşı denetlemek.
- Tokenın içindeki
algalanına güvenmek yerine beklediği algoritmada ısrar etmek. Bunu atlamaktan iki klasik saldırı doğar:algalanınınoneyapıp imzayı silmek ve bir hizmetin RSA açık anahtarını alıp onu bir HMAC sırrı olarak kullanarakRS256doğrulayıcısınıHS256çalıştırmaya kandırmak. expalanını, varsanbfalanını denetlemek ve küçük bir saat kaymasına izin vermek.issveaudalanlarının bu hizmetin beklediğiyle uyuştuğunu denetlemek.
Talepler ancak bundan sonra bir anlam taşır. O ana kadar yük, ağ üzerinden gelmiş, doğrulanmamış bir dizeden ibarettir.
Pratik notlar
- Tokenlar genellikle bir HTTP başlığında
Authorization: Bearer <token>biçiminde gönderilir, o yüzden yükü küçük tutun. Eklediğiniz her talep her istekle birlikte gönderilir. - İmzalanmış bir token süresi dolana kadar geçerli kalır. Bir tokenı iptal etmenin yerleşik bir yolu yoktur; erişim tokenlarının kısa, çoğu zaman dakikalarla ölçülen ömürleri olmasının ve yenilerini almak için ayrı bir yenileme tokenı kullanılmasının nedeni budur.
- Bir token bozuk görünüyorsa önce noktaları sayın. İki nokta ve üç parça normal, imzalanmış bir JWT demektir. Bir terminalden yapıştırılmış kırpılmış bir token, "geçersiz imza" hatasının çok yaygın bir nedenidir.
- Hata ayıklarken bir tokenı, süresini, öznesini ya da rollerini okumak için çözmek tümüyle güvenlidir ve hiçbir sır gerektirmez. Yükün varlık nedeni tam olarak budur.