JWT güvenli derken güvenlik açığı oluşturmayın

Sanılanın aksine eğer bilinçli uygulanmazsa JWT güvenilir değildir. Bu yazıda JWT’yi yanlış anlayarak güvenlik açığı oluşturmamak için farkında olmamız gerekenler nelerdir? Gelin bu yazıda inceleyelim…


JWT güvenli derken güvenlik açığı oluşturmayın

Öncellikle, Json Web Token, sık kullanılan adı ile JWT adını duyamayanlar için kısa bir özet geçerek başlayalım, fakat yazının asıl amacı “JWT nedir?”i anlatmaktan ziyade, “JWT ne değildir?” i anlatmak.

JWT access token’ler (erişim jetonları) oluşturmayı sağlayan bir standart. Bu token genellikle sunucu tarafında oluşturularak (şart değil) istemciye gönderilir. Taraflar sunucunun özel anahtarı ile şifrelenen bu token’i doğrulayarak içindeki verinin gerçekten sunucu tarafından oluşturulduğuna emin olabilirler.

JWT imzalanırken sunucunun özel anahtarı ile imzalandığı için bu anahtara sahip olmayan kimse bu bilgiyi değiştiremez. Yani istemcinin gönderdiği JWT token sunucu tarafından doğrulanıyorsa içerisindeki “kullanıciadi”=”evrenbal” bilgiside güvenilirdir. JWT içerisinde “dogumyili”=”1980” bilgisi varsa veritabanına bağlanıp “evrenbal” ın doğum tarihini getirmemiz gerekmez, bu işlemi daha önce yapıp o token içerisine “1980” yazanın sunucumuz olduğundan emin olabiliriz.

JWT ne değildir?

Sanılanın aksine eğer bilinçli uygulanmazsa JWT güvenilir değildir. JWT kritik durumlarda kimlik doğrulama için kullanılamaz.

JWT’nin içindeki bilgiler güvenilir. Token içinde “evrenbal” kullanıcı adı var, demek ki bu kişi daha önce siteye giriş yapmış, sunucum onun “evrenbal” olduğunu doğrulamış.

Peki ya “evrenbal” şifresinin çalındığını veya internet cafede kullandığı bilgisayardan çıkış yapmadığını farkederse? Muhtemelen hemen sayfaya girip şifresini değiştirir ve sorunu çözdüğünü düşünür. Fakat küçük bir sorun var, siz token’i kontrol ederken şifre kontrolü yapmıyorsunuz! Şimdi ne olacak, tokenden “evrenbal” kullanıcı adı gelmeye devam edeceğine göre kullanıcı adını mı değiştireceğiz?

JWT’nin geçerlilik süresini ayarlayabiliyorum. Kısa bir süre belirlerim, olur biter.

JWT’nin geçerlilik süresini kısa tutup (Örneğin bir kaç saat), daha uzun süreli (Örneğin bir kaç ay) bir “refresh token” oluşturmak güzel bir seçenek olabilir.

Böylelikle bir “access token”in birkaç saat sonra etkisiz hale gelmesini sağlarken, 1 gün aradan sonra tekrar sitenize girmek isteyen kullanıcıya da tekrar giriş yaptırmadan yeni bir access token’i otomatik olarak oluşturabilirsiniz. Bu durumda ise şöyle bir handikap var, uzun süreli refresh token’i doğrulayabilmek için veritabanında saklamanız gerekiyor.

Gönderilen refresh token hala geçerli ve veritabanındaki ile uyumlu ise kullanıcıya tekrar sormadan access token oluşturabilirsiniz. Eğer kullanıcı şifresini değiştirdiyse veritabanındaki refresh token’i sıfırlayarak daha önce oluşturduğunuz tokenlerin geçersiz olmasını da sağlamış oldunuz. Hatta kullanıcı şifre değiştirirken bunu ona sorabiliriz bile.

Bulduğumuz çözüm gerçekten harika mı acaba? Hayır malesef değil, çünkü access token geçerlilik süresi boyunca, o birkaç saat içerisinde hesabı kullanan kişinin yetkisiz olduğunu anlama şansımız yok. Ne zamanki access token süresi dolar ve yenilenmesi gerekir, sunucumuz duruma ancak o zaman uyanacaktır.

Çözüm olarak birkaç saat değil, birkaç dakikalık acess token’ler kullanırım diyebilirsiniz. Bu durumda da hem hala birkaç dakika gecikme yaşayacak, hem de aslında sürekli veritabanı sorgusu yaparak JWT’yi düşündüğünüz şekilde kullanmıyor olacaksınız.

O zaman JWT’yi nasıl kullanacağım?

Yukarıdaki örnek için daha güvenli çözümler düşünmeye çalışalım.

Her iki senaryoda da; kullanıcımız hesap şifresini çaldırmış veya internet cafe’de çıkış yapmadan hesabını açık bırakıp gitmiş olsun.

Kısa çözüm:

JWT token’imizde bir değişiklik yapmadan kullanalım. Fakat her istekte “evrenbal” ın son şifre değiştirme tarihini kontrol edelim (veri tabanından, hafızadan, redis vb. bir çözümle, orası istediğiniz performansa kalmış). Eğer JWT oluşturulduktan sonra şifre değiştirildiyse isteği reddedelim.

Sonuç: Hesap çalındı veya Internet cafede açık unutuldu, şifre değiştirildiği anda sorun ortadan kalkar, fakat “evrenbal” iş yerindeki bilgisayarından, mobil telefonundan, evdeki bilgisayardan hepsinden tekrar giriş yapmak zorunda kalır. JWT token içerisinde sakladığımız başka bilgiler de varsa onları da otomatik reddetmiş oluruz.

Uzun ama daha etkili çözüm:

Kullanıcı her login olduğunda giriş yaptığı cihaz için benzersiz bir ID oluşturalım. Örneğin bu ID “ABCDE” olsun.

Sunucu session (oturum) bilgilerinde, veri tabanında veya performans açısından hafıza veya redis gibi bir çözümde “ABCDE” bilgisini saklayalım. Benzersiz ID ile beraber cihaza ilişkin bazı ek bilgileri de isteğe bağlı saklayabilirsiniz. (Örneğin şu IP’li, şu işletim sistemli, şu browser kullanan cihaz gibi)

İstemciye göndereceğimiz JWT içerisinde “ABCDE” bilgisini gönderelim. Ve token bize her gönderildiğinde “ABCDE” cihazını sunucu tarafında kontrol edelim.

Sonuç: Diyelim ki kullanıcı şifresini değiştirdi; daha önce giriş yaptığı cihazları sunucudan sildiğimizde, daha önce servis edilen bütün JWT’ler geçersiz hale gelecektir. Veya buna gerek kalmadan kullanıcı sayfasında “oturum açmış cihazlar” başlıklı bir bölüm yapıp, tanımadığı cihazların oturumunu kapatarak bu sorunu çözmesini sağlayabiliriz. (Örneğin Internet cafede açık bıraktıysa son giriş yaptığı cihazı silmek gibi)

Bütün bunlara gerek var mıydı?

Peki JWT ile bu kadar uğraştıktan sonra JWT içerisinde sadece cihaz bilgisi olan “ABCDE” yi saklayacaksak acaba gerçketen JWT’ye gerek var mıydı? Aslında hayır, bu bilgiyi bir çerez (cookie) içerisinde, çok daha düşük boyutla, ekstra bir JWT kütüphanesine gerek duymadan, bütünleşik çözümlerle halledebilirdik.

Evet JWT çok güzel bir teknoloji ve özellikle ilk öğrendiğinizde her şeyi JWT kullanarak yapmak istiyorsunuz, ama bir projede JWT entegrasyonu yapmadan önce, kısa bir duraksayıp “gerçekten gerek var mı, aynı güvenilirlikte ve daha basit halledilebilir mi” diye kendimize sormamız gerekiyor.

Bir soru, öneri ya da yorumunuz mu var?

Evren Bal

Ben Evren BAL

1996'dan beri ‘Internet canlısıyım!’

Evren Bal Hakkında daha fazla bilgi.

Tanışmak isterseniz hemen sosyal medyadan iletişime geçebilirsiniz.

Bana Ulaşın

Bana Ulaşın

  • Bir sorunuz mu var?
  • Yazıda bir hata mı farkettiniz?
  • Sayfa ile ilgili bir öneriniz mi var?
  • Yazmamı önereceğiniz bir konu mu var?

Lütfen iletişim formunu kullanarak veya sosyal medya hesaplarımdan bana ulaşın.

Digital Ocean Logo

VPS sunucusu denemek ister misiniz?

Digital Ocean'a referans bağlantımdan kayıt olarak yeni oluşturacağınız hesabınızı 60 gün geçerli 100$ kredi ile açabilirsiniz. Bu miktar yüksek performanslı VPS'leri bile denemeniz için yeterlidir.

Yapacağınız onca kurulumun boşa gitmemesi için benim tavsiyem uzun vadede kullanabileceğiniz özellik ve maliyetlerde bir sunucu oluşturmanızdır.

Ücretsiz 100$ kredi bağlantısı

60 günlük denemeniz sonunda eğer devam etmek istemezseniz hiç bir ücret ödemeyeceksiniz. Hizmeti kullanmaya devam etmek isterseniz harcamanız 25$'a ulaştığında benim hesabıma da 25$ kredi yüklenecektir.

Diğer bir deyişle, siz 100$ ücretsiz krediyi her halükarda kazanırken, daha sonra ücretli devam etmeye karar verirseniz ben de 25$ kredi kazanacağım.

Copyright © 2022 - Evren BAL