4 puan yazan GN⁺ 18 시간 전 | 2 yorum | WhatsApp'ta paylaş
  • JWT, kullanıcıyı oturum açmış durumda tutmak için uygun değildir; bu amaç için normal çerez oturumu daha uygundur
  • JWT spesifikasyonu, yaklaşık 5 dakika veya daha kısa ömürlü kısa süreli token varsayımıyla tasarlanmıştır; oturumların ise bundan daha uzun ömürlü olması gerekir
  • Güvenli durumsuz kimlik doğrulamayı gerçekleştirmek zordur ve token’ları güvenli şekilde ele almak için sonuçta bir miktar durum saklama alanı gerekir
  • Yalnızca basit oturum token’ı taşıyan JWT’ler, normal oturum çerezlerinden daha verimsiz ve daha az esnektir; ayrıca kimlik doğrulama bilgilerinin localStorage veya sessionStorage içinde saklanmaması gerekir
  • Kısa ömürlü imzalı token’lara ihtiyaç duyulduğunda, güvenlik için tasarlanmış PASETO daha iyi bir seçimdir; ancak oturum amacıyla kullanılmamalıdır

Temel özet

  • JWT, kullanıcıyı oturum açmış durumda tutmak için kullanılmamalıdır; bu amaç için normal çerez oturumları daha iyi bir araçtır
  • JWT bu amaç için tasarlanmamıştır ve güvenli değildir; oturum açma oturumlarını sürdürmek için standart çerez oturumları daha uygundur
  • İlgili bir konu olarak, JWT token’ları da dahil olmak üzere kimlik doğrulama bilgileri localStorage veya sessionStorage içinde saklanmamalıdır
  • Konuyla ilgili sunumlar izlenebilir, ancak CSRF koruması gibi diğer başlıklar genelde kısaca ele alındığı için bunların ayrıca başka kaynaklardan öğrenilmesi gerekir
  • Videonun son kısmındaki “geçerli” JWT kullanım senaryoları da daha iyi ve daha güvenli araçlarla kolayca çözülebilir; özellikle PASETO buna karşılık gelir

JWT’den neden kaçınılmalı

  • JWT spesifikasyonu, yalnızca yaklaşık 5 dakika veya daha kısa ömürlü çok kısa süreli token’lar için tasarlanmıştır; oturumların ise bundan daha uzun ömürlü olması gerekir
  • Güvenli bir durumsuz kimlik doğrulama biçimi mümkün değildir; token’ları güvenli şekilde işlemek için mutlaka bir miktar durum gerekir
    • Bir veri deposu gerekecekse, yalnızca token durumunun bir kısmını yönetmek yerine tüm veriyi saklamak daha iyidir
    • İlgili sorunlar http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-for-sessions/ adresinde daha ayrıntılı ele alınır
    • Gerçekte JWT’yi bu şekilde kullanan uygulamalar vardır, ancak bu uygulamalar kusurludur; bu yüzden aynı hatayı tekrarlamamak gerekir
  • Sadece basit bir oturum token’ı saklayan JWT’ler, normal oturum çerezlerinden daha verimsiz ve daha az esnektir; ek bir fayda da sağlamaz
  • JWT spesifikasyonunun kendisi güvenlik uzmanları tarafından güvenilir bulunmadığından, güvenlik ve kimlik doğrulama ile ilgili tüm kullanım alanlarından dışlanmalıdır

İtirazlar

  • “Google da JWT kullanıyor” itirazı, tarayıcıdaki kullanıcı oturumları için geçerli değildir
    • Google, tarayıcı kullanıcı oturumları için JWT kullanmaz; normal çerez oturumları kullanır
    • JWT, yalnızca bir sunucu veya host üzerindeki oturum açma oturumunu başka bir sunucu veya host üzerindeki oturuma aktarmak için bir Single Sign On taşıma aracı olarak kullanılır
    • Bu kullanım biçimi, JWT’nin makul kullanım senaryoları kapsamına girer
    • Google, daha güvenli bir JWT uygulaması oluşturup sürdürmek için gerekli güvenlik uzmanı kaynaklarına sahiptir
    • Google’ın JWT’si fiilen başka yerlerdeki JWT’lerle aynı değildir
  • “Durumsuz olmak daha iyidir” itirazı, güvenli kimlik doğrulama gereksinimleriyle uyuşmaz
    • Çok büyük kaynaklar olmadan gerçekten durumsuz kimlik doğrulamayı güvenli şekilde işletmek mümkün değildir
    • İlgili tartışma için Stateless is a lie bağlantısına bakılabilir
  • “Oturumun nasıl kurulacağını bilmiyorum” sorunu, çoğu web sunucusu framework’ünün dokümantasyonu ve uygulamalarıyla çözülebilir
    • Oturum teknolojisi özellikle yeni olmadığı için, oturumları açıklayan yazılarla sık karşılaşılmaz
    • Oturum uygulamasının dokümantasyonu bile kurulum sürecini izlemek için yeterli olmalıdır
    • Neredeyse tüm web sunucusu framework’lerinde oturum uygulaması bulunur; varsayılan olarak etkin olmasa bile genelde kolayca etkinleştirilebilir
    • Express ve diğer Node.js framework’leri, yüksek modülerlikleri ve tek amaca odaklı yapıları nedeniyle bir ölçüde istisnadır
    • Express’te express-session middleware’i ve kullanılan depoya uygun store connector yeterlidir
    • Postgres, MySQL veya mümkünse SQLite ile birlikte connect-session-knex kullanılması önerilir

Kısa süreli token’lar

  • Herhangi bir kullanım için kısa ömürlü imzalı token’lara ihtiyaç varsa, güvenlik için tasarlanmış PASETO adlı daha iyi bir spesifikasyon vardır
  • PASETO kullanılsa bile oturum amacıyla kullanılmamalıdır

Oturumlar nasıl çalışır

2 yorum

 
shj5508 9 시간 전
  1. JWT, token şifreleme ve DB sorgularını azaltma yöntemidir; çerez tabanlı kimlik doğrulamanın karşısında konumlanan bir kavram değildir. JWT’yi secure cookie içinde saklarsanız, ele geçirilme riski legacy cookie kimlik doğrulama yöntemiyle aynıdır.

  2. JWT’yi expired yapmak için bir son kullanma listesi yönetmek, performans açısından avantaj sağlar. Yalnızca son kullanma bilgisini Redis’ten sorgulamakla tüm üyeler için DB sorgusu yapmak arasında maliyet farkı vardır.

On binlerce kez 100 bin üyelik satır üzerinde indeks tabanlı sorgu (legacy cookie yöntemi)
vs
On binlerce kez Redis’te 50 kayıtlık son kullanma listesi sorgusu (JWT anında expire etme yöntemi)

JWT’nin avantajları vardır. Sadece küçük ölçekli ortamlarda fark daha az hissedilir.

 
Hacker News görüşleri
  • Gerekli ipucu eksik: Konu tarayıcı tabanlı kullanıcı oturumları hakkında
    Servisler arası iletişimde JWT’nin gayet iyi kullanılabildiği birçok durum var
    Ek olarak, bağlantı verilen yazının bir kısmını okudum; örneğin https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-ba... gibi bir yazı var. JWT gerçekten bu kadar korkunç derecede güvensiz bir standartsa AWS STS’nin AssumeRoleWithWebIdentity özelliğini nasıl hackleyeceğini açıklayabilir ya da açıklamayıp Fortune 500 şirketlerinin prodüksiyon AWS hesaplarının her birinde kripto madencisi çalıştırabilirsin. JWT madem bu kadar güvensiz, başarırsan haber ver /alay

    • Bu tam olarak makul sonuç. JWT’nin tarayıcıdaki kullanıcı oturumu için yanlış araç olduğuna katılıyorum
      JWT’nin imza/şifreleme tarafı karmaşık ve yaygın JWT kütüphaneleri ancak sonradan büyük ölçüde akıllandı; eskiden durum böyle değildi. "none" algoritmasını kabul eden çok sayıda kütüphane vardı [1], ayrıca açık anahtarı paylaşılan sır gibi kullanıp saldırganın token sahtelemesine izin veren örnekler de oldu [2]. Bağlantı verilen yazının eleştirdiği karmaşıklığın doğrudan sonucu bunlar
      JWT bazen kullanıcı oturumlarında istenen işlevi de sağlayamıyor. Bir yerde iptal listesi tutmadan geçersiz kılamazsın. Ama her istekte tanımlayıcıyı iptal listesiyle karşılaştıracaksan, bunun yerine opak bir oturum kimliği kullanıp her istekte onu sorgulayabilirsin. Elbette kısa ömürlü token kullanıp sürekli yenileyebilirsin, ama zaten durum tutan sıradan uygulamalarda bunu yapmak için güçlü bir neden yok
      Öte yandan dağıtık sistemlerde veya makineler arası iletişimde imzalı tokenların faydalı olabildiğine tamamen katılıyorum. Bu iki durumu birbirine karıştırmamak gerekiyor
      [1] https://nvd.nist.gov/vuln/detail/cve-2022-23540
      [2] https://nvd.nist.gov/vuln/detail/CVE-2024-54150
    • Eskiden JWT’de asıl sorun kötü varsayılanlara sahip kütüphanelerdi. Birkaç yıl önce downgrade saldırıları da oldukça yaygındı
      Şimdi çeşitli dillerdeki ana kütüphaneler daha düzgün varsayılanlara sahip olduğu için, bugünlerde pratikte epey güvenli hale geldiğini düşünüyorum
    • JOSE doğru uygulanırsa güvenli olsa bile yine de sorun çıkarabilir. İlgili API yüzeyi çoğu zaman pek iyi değil
      “Doğru tutup kullanırsan güvenlidir” demek otomatik olarak iyi tasarım anlamına geliyorsa, aynı şey X.509 için de söylenebilir
      Çoğu durumda daha iyi alternatifler var. Standart oturum tokenları veya API anahtarları büyük web sitelerinin çoğunda yaygın biçimde kullanılıyor ve çoğu kullanım senaryosuna neredeyse kusursuz uyuyor
      Bu standartların hiçbir değeri yok demiyorum. En iyi yanları, ASN.1 kodlaması gibi şeyler olmadan bir şeyleri alışveriş etmeye yarayan temel bir standart sunmaları; ASN.1 tarafındaki araçlar ise çok kırılgan ve hataya açık görünüyor
    • İlk kısma katılıyorum ama eklediğin bölüm mantık hatası. Bir şeye güvensiz diyebilmek için onu mutlaka hackleyebiliyor olman gerekmez
      Örneğin SAML’nin nasıl istismar edileceğini bilmiyorum ama tüm XML ayrıştırıcısını saldırı yüzeyine çevirdiği için korkunç bir standart olduğunu biliyorum. Güvenlik araştırmacısı değilim, XML ayrıştırıcısında zafiyet bulmayı da bilmiyorum; ama saldırı yüzeyinin büyük olmasının kötü olduğunu anlayabiliyorum
    • Gerçek uygulamalarda JWT kaynaklı uzun bir zafiyet geçmişi var
  • JWT’nin güvensiz olduğunu mu söylüyorsunuz; güvenilir RSA/açık anahtar tabanlı imza kullanıldığında bile mi? Paylaşılan sır olmasa da?
    JWT’nin fazla uzun ömürlü olduğu iddiası da garip. JWT ömrünü sınırlayıp yetkilendirme kurumu için bir yenileme modeli kurabilirsin. Çerez tabanlı oturum kullansan bile sonuçta bir yerde bir şey depoluyorsun. JWT’yi sadece 5–15 dakika geçerli yapabilirsin; 15 dakika, Entra dahil birçok yetkilendirme sisteminin önbellek süresine benziyor. 5 dakikalık tokenlar bile yenileme sistemi varsa tarayıcıda gayet kullanılabilir
    Son olarak, kimlik/doğrulamayı uygulama ve API servislerinden ayırmayı tercih ediyorum. Bağlamı dışsallaştırabiliyorsun ve her istekte JWT işleme yaklaşımı, ara sıra başarısız olabilen paylaşımlı önbellek/durum sistemlerinden daha kolay yönetiliyor. İmzalı tokenlar için imza bilinen bir otoriteye karşı doğrulanabiliyor

    • JWT 30 saniye sonra, hatta 1 saniye sonra bile geçersiz olacak şekilde ayarlanabilir. JWT oluştururken audience ayarlaman gerekir
      Bunun dışında imza kriptografik olarak geçerlidir. Tüm JWT’leri kısa ömürlü yapıp her seferinde doğrulayabilirsin
      Bilgi olsun diye: OIDC tokenlarının hepsi JWT’dir
  • Oturum ile JWT iptal listesini karşılaştırınca, JWT iptal listesi lehine bir mantık da var. JWT’nin sınırlı bir son kullanma zamanı olduğundan, iptal listesini yalnızca süresi henüz dolmamış tokenlar için tutmak yeterlidir
    Dolaşımdaki geçerli JWT’lere kıyasla iptal edilmiş JWT’ler muhtemelen küçük bir alt küme olacağından, her istekte çok küçük bir veri kümesini sorgulaman yeterli olur
    Oturum kullanırsan geçerli oturum listesi iptal listesinden birkaç büyüklük mertebesi daha büyük olabilir; dolayısıyla durum saklamanın sorgu maliyeti ve depolama maliyeti daha yüksektir
    Ayrıca yazı JWT’nin durumsuz olduğunu söylüyor ama çoğu zaman öyle değil. Genelde sadece JWT doğrulamazsın; her istekte eşleşen kimlik nesnesini, yani kullanıcı ayrıntılarını çekip kullanıcının hâlâ aktif olup olmadığını ve o işlemi yapma yetkisine sahip olup olmadığını da kontrol edersin. Kullanıcı bazlı iptal listeleri veya minimum_issued_at gibi bir değer kullanarak JWT’deki iat alanını doğrulayabilirsin. Bu sayede “tüm cihazlarda çıkış yap” deseni de mümkün olur; bu işlem kullanıcının minimum_issued_at değerini $NOW yapınca önceki tüm tokenlar geçersiz hale gelir. Tek tek iptal listesi sorgusu gerekmez

    • Kullanıcı nesnesini sorgulaman gerektiği anda JWT’nin ana avantajı ortadan kalkar; o noktada bırak gitsin
    • Oturum verisi sorgulamak, veritabanında indeks kullanan tek bir selecttir ve 0–1 satır döndürür. Çoğu durumda dert edilecek bir şey değil
    • Oturumların da son kullanma zamanı vardır ve bunu istediğin gibi ayarlayabilirsin
  • Bu yazı, “neden” kısmının büyük bölümünü başka blog yazılarına linkleyerek açıklıyor; o blog yazıları da genel olarak “tekil JWT token’ları geçersiz kılamazsınız” diye şikâyet ediyor gibi görünüyor
    Benim bir şey implemente ettiğim her seferde genel kural, bir yerlerde geçersiz kılınmış nonce’u kontrol etmekti; bu da o yazının ikinci iddiasını çözüyor
    “JWT spesifikasyonunun kendisine güvenlik uzmanları güvenmiyor” iddiası, tek bir blog yazısından daha fazla dayanak gerektiriyor gibi duruyor. Ayrıca o yazı daha çok kötü implementasyonları suçluyor gibi; ama hangi standart olursa olsun kötü implementasyon sorunu peşinizi bırakmaz
    Genel olarak, rastgele bir gist linkine tıklarken ne beklediğimi bilmiyorum

    • İlk implementasyonlardan bazılarında header’a herhangi bir issuer koyulmasına izin verilip buna güveniliyordu; bu zaten en baştan yanlış bir yaklaşımdı. Yalnızca güvenilen ya da “bilinen” issuer’lara izin verirseniz bağlama ilişkin kaygıların çoğu ortadan kalkar
      Bunun dışında tarayıcıda daha kısa ömürlü JWT’leri rahatlıkla kullanabilir ve agent’ın bunları kendi kendine yenilemesini sağlayabilirsiniz. Azure Entra veya başka birçok sağlayıcı kullanırsanız pratikte zaten böyle çalışır. JWT’yi nispeten kısa, yaklaşık 5–15 dakika tutabilir ve jti iptal durumunu da kontrol edebilirsiniz
      JWT, yetki veren otoriteyi uygulama/API sisteminden ayırıp yeniden kullanmak için çok kullanışlıdır. Saldırı yüzeyini taşırsınız ama güvenilir bir şekilde taşırsınız. Dünya genelinde SSH dahil birçok yerde açık anahtar yaklaşımı kullanılıyor. Paylaşılan sırlar veya uzun ömürlü token’lar kullanmazdım ama doğrulanmış ve bilinen kaynaklardan gelen kısa ömürlü, açık anahtarla imzalanmış token’lar çoğunlukla sorun değildir
      Hatta pratikte asıl sorun çoğu zaman API key’ler oluyor. Az önce bir tane implemente etmem gerekti; benim durumda API key’i de Bearer token gibi görünecek şekilde yaptım: kısa bir sak. öneki, ardından kimlik kısmı (base64url UUID baytları), sonra da gizli değer (base64url baytları). Veritabanında UUID ile gizli değerden üretilmiş passphrase düzeyinde bir salt+hash saklıyorum. Dolayısıyla üretilen API key gizli kabul edilmeli ve veritabanında sadece tek yönlü olarak tutuluyor; böylece DB ihlali doğrudan kimlik doğrulama ihlaline dönüşmüyor
      Buna rağmen, düzgün implemente edilmiş bir JWT çözümünde sorun çıkmasından çok API key sızıntısı yaşanması daha olası
    • “Tekil JWT token’ları geçersiz kılamazsınız” iddiasına %100 katılmıyorum. İmplementasyon yaparken geçersiz kılınmış nonce’u bir yerden kontrol etmek benim için sağduyu seviyesinde bir şey ve insanların bunu yapmadığını yeniden öğrendikçe şaşırıyorum
  • Bu yazıya tesadüfen denk geldim ve geçmişte bu konuda çok çalıştığım için yeniden gündem olması ilginç geldi. Sonra tıklayıp bakınca yazarın benim bazı materyallerime link verdiğini gördüm. Çok eski anılar canlandı
    Her neyse, benden çok daha zeki insanlar bu konuyu yıllardır geniş biçimde ele aldı ama 2026’da bile JWT’nin web kimlik doğrulaması için yanlış araç olduğunu düşünüyorum. Servisler arası kullanım için uygun ama seçme şansınız varsa doğrudan PASETO kullanmak daha iyi. Birçok sorunu çözüyor

  • Şu anda web sitesine bildirim push’u için RabbitMQ ekliyorum. İstemcinin nerede ne okuyabileceğini kontrol etmek için JWT kimlik doğrulaması kullanıyorum; kısa ömür ve düzenli token yenilemesi de var
    Bu kurulumun kolaylığına yaklaşan başka bir yapı pek bilmiyorum. Geçerli oturuma JWT token veren tek bir endpoint eklemek yetiyor ve kullanıcı bazlı yetkilendirme de mümkün oluyor

  • JWT kullanmamanız gerektiğini anlatan bağlantılı yazılardan biri, iyi niyetle bakılsa bile tuhaf
    https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-ba...
    Özetle “bazı kütüphanelerde bug vardı” diyor, ardından da libsodium getirip işi kendiniz yapmanızı öneriyor. Bu, ciddiye alınması zor, saçma bir tavsiye. Her yazılımda bug olur. Heartbleed sırasında bütün internet ayağa kalkmıştı ama biz hâlâ TLS ve OpenSSL kullanıyoruz
    “JWT spesifikasyonu özellikle çok kısa ömürlü token’lar, yani kabaca 5 dakika ve altı için tasarlanmıştır” ifadesini ilk kez duyuyorum ve bunu destekleyen bir kaynak da bulamıyorum. RFC 7519’da böyle bir iddia yok

  • Genelde JWT’yi bir kimlik doğrulama önbelleği gibi kullanıyorum. Kimlik doğrulama servisinden bir auth token alıyorsunuz ve bu token başka servislere yetki veriyor
    Bunun çeşitli avantajları var ama ana fikir şu: alt servislerin ne kimlik doğrulama veritabanıyla etkileşmesi gerekiyor ne de token üretme yetkisine sahip olmaları gerekiyor. Burada HMAC değil RS256 kullanıldığı varsayımı var. Dolayısıyla alt servis ele geçirilse bile, bu, kimlik doğrulama veritabanına erişebilen bir servisin ele geçirilmesi kadar yıkıcı olmuyor
    Token içinde hassas veri varsa JWE kullanmanız gerekir ama bu da her kullanımda özel anahtara sahip bir iç servisten token’ı çözmesini istemeniz gerektiği için pek iyi sayılmaz
    Benim sık kullandığım yapı {"id": (uuid), "scopes": ["scope:read/write"]} şeklinde
    SPA için de oldukça iyi. Çünkü statik site sunucusu, resource’ları servis etmeden önce JWE’yi açık anahtarla doğrulayabiliyor. Benim yöntemimde statik siteyi /(scope)/path biçiminde derliyorum ve statik servis, erişimi olmayan sayfaları baştan hiç sunmuyor. Özellikle yönetim paneli gibi, backend’in sahip olduğu yetenekleri veya saldırılabilir iç servis yollarını kullanıcıya göstermek istemediğiniz durumlarda çok kullanışlı
    “Backend erişimi” için JWT ömrü yaklaşık 5 dakika ve /me gibi şeyleri, /refresh localStorage önbelleğinin atılmasını açıkça söylemediği sürece localStorage’da cache’liyorum. SPA uygulamasının request handler’ı “yenileme gerekli” durumunu algılayıp token’ı yeniliyor
    Bunun sorumluluğunun büyük kısmının node/next ve Python kütüphanelerinde olduğunu düşünüyorum. Backend’i güçlü tipli bir dille yazıyor, frontend’i ise her zaman önceden derlenmiş statik sayfalar olarak üretiyorum. Şu anki frontend kurulumunda VITE kullanıyorum; landing kısmı önceden render edilmiş sayfalardan, uygulama kısmı ise normal bir SPA’dan oluşuyor
    Bütün bunları hesaba katsam bile bu gist’in tamamına güçlü biçimde katılmıyorum. JWT’yi istediğiniz kadar güvenli hâle getirebilirsiniz

  • JWT gayet uygun; başlık ise biraz sansasyonel duruyor
    Bunun yerine konuşmaya daha değer konular var: şifrelenmiş değerlerin (simetrik veya asimetrik), rastgele ama gizli değerlerin, imzalı değerlerin (okunabilir ama değiştirilemez değerler) ne zaman kullanılması gerektiği; bunların nereye konulacağı (bellek, localStorage, cookie); değerlerin sonsuza kadar yaşamamasını nasıl sağlayacağınız ve doğal sona erme zamanından önce iptal edilmelerinin gerekip gerekmediği gibi şeyler