Çerez ve oturum
- Çerezin ve oturumun nasıl çalıştığını, Set-Cookie niteliklerini, oturum sabitlemeyi ve JWT hatalarını tespit ve savunmasıyla öğrenirsin.
- HTTP her isteği sıfırdan okur. Sunucu seni bir önceki istekten hatırlamaz.
- Çerez bu boşluğu kapatır: sunucu küçük bir kâğıt verir, tarayıcı her istekte geri gösterir.
- O kâğıt çalınırsa parola gereksiz kalır. Bu yüzden çerez bayrakları ciddiye alınır.
Puan bütün etkinlikleri cevaplayınca hesaba yazılır. Bu dersi tamamlayınca +55 XP alacaksın. Giriş yapmadan ilerlersen puan yalnız bu tarayıcıda durur.
HTTP durumsuzdur. Her istek kendi başına gelir ve sunucu önceki isteği hatırlamaz. Oysa bir alışveriş sitesinde giriş yaptıktan sonra sepete ürün eklersin, siparişlerini görürsün, adresini değiştirirsin.
Her tıklamada parolanı yeniden yazmazsın. Bu konfor çerezden gelir. Sunucu giriş anında sana bir kimlik kartı verir, tarayıcın o kartı her istekte geri gösterir.
Kart çalınırsa parolanın bir önemi kalmaz, saldırgan senin yerine geçer. Bu derste çerezin nasıl yazıldığını, hangi bayrakların onu koruduğunu, oturumun nasıl ele geçirildiğini ve JWT'nin nerede kolaylık, nerede risk getirdiğini göreceksin.
Durumsuz HTTP'de oturum
Çözüm basittir. Sunucu giriş sonrası rastgele bir oturum kimliği üretir. Bunu Set-Cookie başlığıyla tarayıcıya yollar. Tarayıcı değeri saklar ve aynı siteye giden her istekte Cookie başlığında geri yollar.
RFC 6265 bu iki başlığın kurallarını tanımlar. Sunucu tarafında o kimliğin karşısında bir kayıt durur: kullanıcı numarası, rol, son işlem zamanı. Yani çerez kimliği taşır, veriyi değil. Aşağıdaki akışta önce giriş yanıtını, sonra tarayıcının bir sonraki isteğini görüyorsun.
# 1. Giriş yanıtı: sunucu kimliği verir HTTP/1.1 302 Found Location: /panel Set-Cookie: oturum=9f3b7c21ae4d0b58e6a1c7f24d93b1e0; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=3600 # 2. Sonraki istek: tarayıcı kimliği geri gösterir GET /panel HTTP/1.1 Host: hedef.example Cookie: oturum=9f3b7c21ae4d0b58e6a1c7f24d93b1e0
İlk parçada sunucu girişi onayladı ve seni 302 ile panele yönlendirdi. Aynı yanıtta Set-Cookie satırı oturum adlı çerezi yazdı. Değer anlamsız görünür, çünkü öyle olmalıdır: sunucudaki kaydın rastgele anahtarıdır.
İkinci parçada tarayıcı panel sayfasını ister ve Cookie başlığına aynı değeri ekler. Sen bir şey yapmazsın, tarayıcı bunu kendiliğinden yapar. Sunucu değeri kendi kayıtlarında arar, bulursa isteği o kullanıcıya bağlar.
Dikkat et: Cookie başlığı yalnız ad ve değeri taşır. Bayraklar tarayıcıya verilen talimattır ve sunucuya geri yollanmaz.
Bazı uygulamalar sunucuda kayıt tutmak istemez ve veriyi doğrudan çerezin içine paketler. Paketi de çoğu zaman Base64 ile kodlar. Base64 geri çevrilebilir bir kodlamadır, şifreleme değildir. Değeri gören herkes çözer, değiştirir ve yeniden kodlar.
Aşağıdaki örnekte çerezin içinde müşteri numarası ve rol yazıyor. Kullanıcı rolü admin yapıp çerezi geri yollarsa ve sunucu değere körü körüne güvenirse, yönetici paneli açılır. Doğru tasarımda rol sunucudaki kayıtta durur. Veri çerezde taşınacaksa sunucunun gizli anahtarıyla imzalanır ve imza her istekte doğrulanır.
$ echo 'eyJubyI6MTA0Miwicm9sIjoibXVzdGVyaSJ9' | base64 -d
{"no":1042,"rol":"musteri"}Etkinlik 1 / 8
Bir çerez değerini Base64 çözdüğünde altta ne yazıyor? Uygulamanın hatasını gör.
Araçları sırayla dene. Yanlış araç bozuk çıktı verir.
Oturum kimliği, sabitleme ve çıkış
Oturum kimliğinin kendisi de önemlidir. Tahmin edilebilir bir sayaç kullanırsan saldırgan komşu kimlikleri dener. 1041 numaralı oturumu gören kişi 1042'yi de dener. OWASP kimliğin en az 64 bit entropi taşımasını ister ve bunun için kriptografik olarak güvenli bir rastgele sayı üreteci kullanılmasını şart koşar.
Kendi üretecini yazma, çatının oturum yöneticisini kullan. Kimliği URL'de de taşıma. Adres çubuğundaki kimlik tarayıcı geçmişine, sunucu loglarına ve başka siteye giden Referer başlığına sızar. Kimliğin tek yeri çerezdir.
Oturum sabitleme (session fixation) saldırısı da bu alanda durur. Saldırgan önce siteden kendisi bir oturum kimliği alır. Sonra bu kimliği kurbana kabul ettirir; örneğin kimliği URL'de taşıyan bir bağlantı yollar. Kurban o bağlantıyla giriş yapınca aynı kimlik yetkili duruma geçer.
Saldırgan kimliği zaten bildiği için içeri düşer. Çözüm tek satırdır: girişten hemen sonra eski kimliği at, yenisini üret. OWASP bunu yetki seviyesinin değiştiği her an için ister. Parola değişimi ve yönetici moduna geçiş de buna dahildir.
<?php // Parola doğrulandıktan hemen sonra session_regenerate_id(true); // eski kimliği sil, yenisini üret $_SESSION["kullanici_no"] = $kullanici["no"]; $_SESSION["giris_zamani"] = time();
Oturumun sonu da başı kadar önemlidir. Çıkış düğmesi yalnız tarayıcıdaki çerezi silmekle kalmamalı, sunucudaki kaydı da yok etmelidir. Aksi hâlde kopyalanmış çerez çıkıştan sonra da çalışır. İki zaman sınırı daha koy.
Boşta kalma süresi, kullanıcı bir süre işlem yapmazsa oturumu kapatır. Mutlak süre ise kullanıcı ne kadar etkin olursa olsun oturumu belli bir anda bitirir. Bu sınırları sunucuda uygula. Çalınan çerezi saldırgan, Max-Age dolduktan sonra da elle yollayabilir.
Etkinlik 4 / 8
Hangi davranış oturumu korur, hangisi zayıflatır?
Önce bir seçeneğe, sonra aşağıdaki uygun kutuya bas. İstersen seçeneği kutuya sürükleyip bırak. Yerini değiştirmek için aynı işlemi tekrarla.
0/5 seçenek yerleşti.
JWT: kendini taşıyan jeton
Son yıllarda JWT (JSON Web Token) yaygınlaştı. Jeton üç parçadan oluşur ve noktayla ayrılır: başlık, yük ve imza. Başlık hangi algoritmanın kullanıldığını, yük kullanıcıya dair iddiaları taşır.
İlk iki parça Base64URL ile kodlanır, şifrelenmez. Yani jetonun içindeki veriyi herkes okur, yalnız imzayı bozmadan değiştiremez. RFC 7519 bu yapıyı tanımlar.
Jeton çoğu zaman çerezde değil, Authorization: Bearer başlığında taşınır. Aşağıdaki komutlar bir jetonun ilk iki parçasını komut satırında çözer.
$ TOKEN='eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMDQyIiwicm9sIjoicGVyc29uZWwiLCJleHAiOjE4MzAwMDAwMDB9.q3XG8b2rVn0cJt5WfL1yPzA7kE9mHs4uD6oRi2TwYeM'
$ echo "$TOKEN" | cut -d. -f1 | base64 -d
{"alg":"HS256","typ":"JWT"}
$ echo "$TOKEN" | cut -d. -f2 | base64 -d
{"sub":"1042","rol":"personel","exp":1830000000}cut komutu jetonu noktalardan böler ve istenen parçayı alır. Birinci parça başlıktır: HS256, yani paylaşılan bir gizli anahtarla HMAC-SHA256 imzası. İkinci parça yüktür. sub kullanıcının kimliğini, rol yetkisini, exp ise jetonun bitiş anını Unix zaman damgası olarak verir.
Üçüncü parça imzadır ve çözülünce okunur bir metin çıkmaz. Sunucu ilk iki parçayı kendi anahtarıyla yeniden imzalar ve sonucu üçüncü parçayla karşılaştırır. Yükte tek bir harf değişirse imza tutmaz. Yüke parola ya da kimlik numarası gibi gizli veri koyma, çünkü herkes okur.
JWT hataları çoğu zaman doğrulama adımında doğar. En eskisi alg alanına none yazmaktır; bazı kütüphaneler bu değeri görünce imzayı hiç denetlemez. İkincisi algoritma karışıklığıdır: doğrulayan taraf algoritmayı jetonun kendi başlığından okur.
Üçüncüsü zayıf gizli anahtardır. HS256 anahtarı kısa bir kelimeyse jeton çevrim dışı kırılır. Dördüncüsü, jetonu doğrulamadan yalnız çözmektir.
Bazı kütüphanelerde imza denetimi tek bir seçenekle kapanır; kod incelemesinde bu seçeneği ara. RFC 8725 çözümü net koyar: kabul edilen algoritmayı jetonun başlığı değil, sunucu belirler. exp, iss ve aud alanları da her istekte denetlenir.
Derinleş:Algoritmayı kim seçer
JWT standardı birçok imza algoritmasını destekler. HS256 simetriktir: aynı gizli değer hem imzalar hem doğrular. RS256 asimetriktir: sunucu gizli anahtarla imzalar, herkes açık anahtarla doğrular.
Jetonun başlığındaki alg alanı hangi algoritmanın kullanıldığını söyler, ama bu alan da jetonu getiren kişinin elindedir. Kök hata, doğrulayan tarafın algoritma kararını bu alana bırakmasıdır. O zaman doğrulama, sunucunun hiç öngörmediği bir algoritmayla ya da imzasız hâlde yapılabilir.
RFC 8725 bu yüzden iki kural koyar. Kabul edilen algoritma listesini uygulama belirler ve listede olmayanı reddeder. Her anahtar da tek bir algoritmaya bağlanır.
Güncel kütüphaneler bu kuralı zorlar. Örneğin Python'un PyJWT kütüphanesi 2.0 sürümünden beri doğrulamada algorithms parametresini açıkça ister. Kod incelemesinde doğrulama çağrısını bul ve algoritma listesinin sabit yazıldığını gör.
Etkinlik 5 / 8
Bu işlev jetondan kullanıcıyı okuyor. Hangi satır herkesin kendine istediği rolü yazmasına yol açar?
Jeton kullanıcı bilgisini imzalı olarak kendi içinde taşır. Sunucu kayıt tutmaz, yalnız imzayı doğrular. Bu hızlıdır ve birçok sunucuya dağılmış sistemlerde işi kolaylaştırır.
Bedeli iptaldir. Çalınan jeton, süresi dolana kadar geçerli kalır, çünkü sunucu onu ayrıca tanımaz.
Pratikte üç önlem birlikte kullanılır. Erişim jetonunun ömrünü dakikalarla sınırla. Uzun ömürlü yenileme jetonunu sunucuda kayıtlı tut. Acil durumlar için iptal edilen jetonların kimliklerini bir kara listede sakla.
Etkinlik 6 / 8
Doğru mu, yanlış mı?
Sunucu tabanlı oturuma göre, durumsuz bir JWT'yi çalındığında iptal etmek daha zordur.
Ele geçirmeyi görmek, savunmayı kurmak
Çalınan bir oturumu nasıl fark edersin? İyi bir uygulama oturum kimliğinin tamamını değil, kısa bir parmak izini loglar. Aynı parmak izinin birkaç saniye arayla iki farklı IP adresinden ve iki farklı istemci imzasından gelmesi güçlü bir işarettir. Bir kaynaktan art arda gelen geçersiz kimlikler tahmin denemesini gösterir.
Oturum açıldıktan hemen sonra e-posta ya da parola değiştiren istekler de dikkat ister. Saldırgan hesabı kalıcı olarak ele geçirmek için ilk bunu yapar. Aşağıdaki log parçasında bu işaretleri ara.
Etkinlik 7 / 8
Uygulama logunda oturum ele geçirme ve kimlik tahmini izlerini işaretle.
Şüpheli satırlara tıkla. Birden fazla olabilir.
Savunmayı katmanlarla kur. Kimliği güçlü rastgelelikle üret ve girişte yenile. Çerezi __Host- önekiyle, HttpOnly, Secure ve SameSite bayraklarıyla yaz.
Çıkışta ve zaman aşımında kaydı sunucudan sil. Şüpheli kullanımda oturumu düşür ve kullanıcıdan yeniden giriş iste.
Şimdi bu bilgiyi bir tasarım kararına taşı. Bir ekip yeni oturum çerezini yazıyor ve tek bir ek bayrak seçebiliyor. Amaç, başka siteden tetiklenen isteklerde çerezin otomatik eklenmemesi. Hangi bayrak bu işi görür ve karşılığında hangi saldırıyı zorlaştırır?
Etkinlik 8 / 8
Bir oturum çerezinde SameSite=Lax ayarı hangi saldırıyı zorlaştırır?
Okumayı istediğin sırayla sürdürebilirsin. Ders, bütün etkinlikleri cevapladığında tamamlanır.
- Etkinlik 1· Durumsuz HTTP'de oturum
- Etkinlik 2· Set-Cookie nitelikleri
- Etkinlik 3· Set-Cookie nitelikleri
- Etkinlik 4· Oturum kimliği, sabitleme ve çıkış
- Etkinlik 5· JWT: kendini taşıyan jeton
- Etkinlik 6· JWT: kendini taşıyan jeton
- Etkinlik 7· Ele geçirmeyi görmek, savunmayı kurmak
- Etkinlik 8· Ele geçirmeyi görmek, savunmayı kurmak