Ana içeriğe geç

Bölüm 14: Durum, Çerez ve Oturum

11 dakikalık okumaGüncelleme:

Ağlar'a “Sen”i Katmak kitabının bir bölümü: adres çubuğuna yazdığın tek bir isteğin peşinden bakırla fiberin fiziğine inip karşı taraftan geri dönen uzun bir teknik yolculuk.

Kısım 3: İstek Yazılıyor (Bölüm 13-17)

Tüm bölümler
  1. Giriş
  2. Adres Çubuğundan İsteğe
  3. Paket Anahtarlamalı Yol
  4. İsimden Adrese
  5. DNS Kayıtları
  6. Önbellek, Tazelik ve Güven
  7. Port Numarası ve Soket
  8. Bağlantısız Taşıma: UDP
  9. Üç Adımlı El Sıkışma
  10. Simetrik Şifreleme
  11. Açık Anahtarlı Kriptografi
  12. TLS El Sıkışması
  13. Sertifika Zinciri
  14. HTTP Mesajının Anatomisi
  15. Durum, Çerez ve Oturum
  16. HTTP/2'den HTTP/3'e
  17. İçerik Dağıtım Ağları
  18. Diğer Uygulama Protokolleri
  19. Katmanlı Mimari
  20. Hizmet ve Protokol
  21. Encapsulation ve Başlıklar
  22. Paket Yakalama ve Çözümleme
  23. Ağ Interface Kartı
  24. Fiziksel Adresleme
  25. Hata Sezme ve CRC
  26. Adres Çözümleme: ARP
  27. Ortam Erişimi: CSMA/CD
  28. Switch'ler
  29. Ağ Topolojileri
  30. Sanal Yerel Ağlar
  31. Kablosuz Erişim: 802.11
  32. Radyo Kanalı ve Kapasite
  33. Kablosuz Ağ Güvenliği
  34. Hücresel Ağlar
  35. Spektrum ve Kuşaklar
  36. Hareketlilik ve Aktarma
  37. Adres Kiralama: DHCP
  38. Adresin Anatomisi
  39. Adres Tükenmesi ve IPv6
  40. Router Mimarisi
  41. Kuyruk Yönetimi
  42. Cihaz Yapılandırma
  43. Routing Protokolleri
  44. Kontrol Düzlemi ve SDN
  45. Ağ İzleme ve Yönetimi
  46. Alanlar Arası Routing
  47. Adres Çevirisi
  48. Ara Kutular
  49. Tünelleme ve IPsec
  50. Firewall'lar
  51. Ağ Saldırıları
  52. Operatör ve Metro Ağları
  53. Bitten Sinyale
  54. Sembol Hızı ve Kanal Kapasitesi
  55. Multiplexing Teknikleri
  56. İletim Ortamları
  57. Bakır Kablo Sonlandırma
  58. Fiber Sonlandırma
  59. Fiber Optik İletim
  60. Bakır Erişim Ağı: DSL
  61. DSL'de Hız ve Mesafe
  62. Pasif Optik Ağlar
  63. Kablo Erişim Ağları
  64. Kablo Modem ve CMTS
  65. Denizaltı Kabloları
  66. Veri Merkezi Ağları
  67. Encapsulation Çözme
  68. Güvenilir Aktarım
  69. Tıkanıklık Denetimi
  70. Trafik Çözümleme
  71. Gecikme Bütçesi
  72. Soket Programlama
  73. Eşten Eşe ve Protokol Tasarımı
  74. Uyarlanır Video Akışı
  75. Gerçek Zamanlı Ses ve Görüntü
  76. Kablosuz Sensör Ağlarının Mimarisi
  77. Sensör Ağlarında Ortam Erişimi
  78. Sensör Ağlarında Yönlendirme ve IP
  79. Zaman Eşitleme ve Konum Bulma
  80. Sensör Ağı Uygulamaları
  81. Mobil Kablosuz Sensör Ağları
  82. Son Söz

Bir önceki bölümde yazdığın istekte seni tanıtan tek bir alan yoktu. Sunucu da geçmişi tutmuyor.

Yine de siteler seni hatırlıyor. Bunu yapan şey sunucunun belleği değil, geçen sefer verdiği kâğıdı geri götürmen. O kâğıt neye benziyor?

Sunucu neden hiçbir şey tutmuyor?

Her HTTP isteği ötekilerden bağımsız okunuyor. Bunun protokoldeki adı durumsuzluk. Çok adımlı işlem diye bir kavram yok; adımları birbirine bağlama işi protokolün dışında kalıyor.

Durumu bir yerde tutmanın iki yolu var ve ikisi de bu kitapta karşına çıkıyor. Birincisi durumu protokolün uçlarında tutmak. Bağlantı kuran taşımada iki tarafın da karşısındakinin nerede kaldığını gösteren bir kaydı var. İkinci yol durumu mesajların içinde taşımak.

Çerezin yaptığı iş bu. Durumu sunucunun belleğinde tutmak yerine senin makinene yazıyor ve her istekte onu geri getirtiyor. Fikir yeni değil: 8. bölümdeki SYN cookie, yarı açık bağlantı durumunu ikinci mesajın sıra numarasına kodlayıp kuyruğu tümden ortadan kaldırıyordu. Çerez aynı işi bir kat yukarıda, application layer’da yapıyor.

Çerez dört parçadan kurulur

Mekanizma dört parçayı birden istiyor. İlk ikisi mesajların içinde: yanıt mesajındaki Set-Cookie başlık satırı ve sonraki istek mesajındaki Cookie başlık satırı. Diğer ikisi mesajların dışında: tarayıcının makinende yönettiği çerez dosyası ve sitenin arka ucundaki veritabanı. Dördü bir arada olmadan zincir tamamlanmıyor.

Zincir ilk istekte başlıyor. Siteye ilk vardığında site bir kimlik üretiyor ve veritabanında ona bir kayıt açıyor. Kimliği de yanıtın başlığına yazıyor.

# sunucudan gelen yanıtta
Set-Cookie: oturum=7c1a94e0b3f582d6a4e71b09; Path=/; Max-Age=1800; Secure; HttpOnly

# sonraki her istekte tarayıcıdan giden
Cookie: oturum=7c1a94e0b3f582d6a4e71b09

Sonraki isteklerin hepsi o değeri taşıyor. Sunucunun seni tanıması şu: gelen satırdaki değeri okumak ve veritabanındaki kaydı bulmak. Tanıdığı şey sen değilsin, taşıdığın numara. Temel mekanizmayı tanımlayan belge RFC 6265, Nisan 2011 tarihli ve tam adı HTTP State Management Mechanism. Aşağıda göreceğin SameSite ve ad önekleri o belgede yok; tarayıcıların çoktan uyguladığı ama yıllardır taslak olarak bekleyen yenisinden (6265bis) geliyor.

Değerin ne anlama geldiğine protokol değil uygulama karar veriyor. Protokol yalnızca taşımayı tarif ediyor ve gelen Cookie satırını yok saymak sunucunun hakkı.

Tek bir yanıt birden çok Set-Cookie satırı taşıyabiliyor. Bu satırlar tek satıra katlanmıyor: virgül karakteri Set-Cookie’nin kendi sözdiziminde kullanılıyor ve katlama anlamı bozuyor.

Ad ve değerden sonrası kapsamı çiziyor

ÖznitelikNe yapıyor
Max-Ageçerezin en fazla kaç saniye yaşayacağını söylüyor
Expiresaynı şeyi bir tarih olarak söylüyor; ikisi birden varsa Max-Age üstün geliyor
Domainçerezin hangi makinelere gönderileceğini belirliyor, alt adlar da kapsama giriyor
Pathçerezi belli bir dizin ve altına sınırlıyor, ama güvenlik için ona güvenilmiyor
Secureçerezi yalnızca güvenli kanaldan gönderilir kılıyor
HttpOnlyçerezi HTTP isteklerine ayırıyor, sayfadaki betikler onu okuyamıyor
SameSiteçerezin başka bir siteden tetiklenen isteklere eklenip eklenmeyeceğini belirliyor

Örnekteki çerez 1.800 saniye, yani 30 dakika yaşıyor. Süre hiç yazılmasaydı çerez oturum bitene kadar saklanacaktı, yani tarayıcı kapanınca düşecekti. Oturum çerezi ile kalıcı çerez arasındaki fark bu.

Secure yazan çerez yalnızca şifreli kanaldan, yani HTTPS üstünden gidiyor. Koruduğu şey gizlilik, bütünlük değil: etkin bir saldırgan güvensiz kanaldan aynı adı taşıyan bir çerez göndererek onun üstüne yazabiliyor. HttpOnly ile Secure birbirinden bağımsız, bir çerez ikisini birden taşıyabilir.

Standart, genel amaçlı bir tarayıcıdan çerez başına en az 4.096 bayt saklamasını istiyor. Ad, değer ve öznitelikler bu toplama giriyor. Alan adı başına en az 50, toplamda en az 3000 çerez saklanması bekleniyor.

Sunucuların az ve küçük çerez kullanması bekleniyor, çünkü Cookie satırı her isteğe ekleniyor ve upstream (yukarı yön) bant genişliğinden yiyor. Örnekteki adın uzunluğu 6 bayt, kimlik 24 onaltılık basamak, ad-değer çifti 31 bayt ediyor. Başlık adı ve satır sonuyla birlikte Cookie satırı 41 bayt tutuyor. Bir sayfa aynı kaynaktan 60 nesne çekiyorsa aynı çerez tek sayfa yüklemesinde upstream tarafında 2.460 bayt yük üretiyor.

Tarayıcının çerezi kendiliğinden eklemesi bir açık üretiyor

Tabloya yeni eklenen son satır bir savunma ve neyi savunduğunu bilmeden anlamı yok.

Tarayıcının kuralı sade: bir adrese istek giderken, o adrese ait çerezleri kim istemiş olursa olsun ekliyor. Bankana giriş yaptın, oturum çerezin duruyor. Sonra başka bir sekmede bambaşka bir siteyi açıyorsun ve o sayfanın içinde görünmez bir form ya da bir görsel etiketi, senin bankana bir istek yaptırıyor. Tarayıcı o isteğe oturum çerezini de ekliyor, çünkü kuralı bu. Banka isteği senden gelmiş sayıyor.

Saldırının adı siteler arası istek sahteciliği (CSRF). Saldırganın oturum çerezini okuması gerekmiyor, hatta görmesi bile gerekmiyor; yalnızca kullandırması yetiyor. HttpOnly bu saldırıya karşı hiçbir şey yapmıyor, çünkü çerez okunmuyor.

SameSite özniteliği tam buraya oturuyor ve üç değer alıyor:

değerbaşka siteden gelen isteğe çerez eklenir mi
Stricthiçbir durumda eklenmez
Laxyalnızca üst düzey gezinmede ve güvenli metotlarda eklenir
Noneher zaman eklenir; Secure ile birlikte yazılması zorunlu

Lax bir ödünleşim ve Chrome’da 2020’den beri, öznitelik hiç yazılmamışsa varsayılan: başka bir siteden gelen bir bağlantıya tıkladığında oturumun açık kalıyor, ama başka bir siteden tetiklenen bir form gönderimine çerez eklenmiyor. None ise üçüncü taraf çerezleri için kalan tek yol.

İkinci bir savunma da adın kendisinde. Bir çerezin adı __Host- ile başlıyorsa tarayıcı onu yalnızca Secure işaretliyse, Domain yazılmamışsa ve Path kökse kabul ediyor. Böylece o çerezin hangi makineye ait olduğu adın içinde kilitleniyor ve bir alt alan adı onu üstüne yazamıyor. __Secure- öneki daha gevşek, yalnızca Secure şartını koyuyor.

Güzelliği şurada: kural sunucuda değil, adın kendisinde taşınıyor. Çerezi kim gönderirse göndersin, tarayıcı adı okuyup şartı uyguluyor.

Birinci taraf çerez, ziyaret etmeyi seçtiğin siteden geliyor. Üçüncü taraf çerez hiç seçmediğin bir siteden geliyor, sayfanın içine gömülü bir nesne onu çekiyor. Kalıcı üçüncü taraf çerezleri aynı kimlik değerini birden çok sitede görünür kılıyor; izleme dediğimiz şey de o ortak değerin farklı sitelerde tekrar tekrar geri gönderilmesi. Görünür bir reklam bile gerekmiyor. Görünmez bir bağlantı aynı işi görüyor.

İki farklı sitenin sayfası yan yana; ikisinin de üstünde aynı üçüncü siteden gelen bir reklam şeridi duruyor ve oklar iki sayfadan da o tek kaynağa iniyor. Gömülü nesnenin aynı çerezi iki sitede birden görünür kılması.

Bir not: Türkçe kaynaklarda “HTTP oturumu” çoğu zaman tek bir istek-yanıt turu anlamına geliyor. Bu kitapta oturum, protokolün üstünde çerezle kurulan kullanıcı oturumudur; 11. bölümde el sıkışmanın sonunda üretilen oturum anahtarıyla akrabalığı yok.

DerinleşmeHTTP durum tutma yükünü neden hiç üstlenmedi?

Durum tutan protokoller karmaşıklaşıyor. İki uçtan biri çökerse iki taraftaki durum görüntüleri birbirini tutmuyor ve uzlaştırılması gerekiyor. Durumlu bir protokolde bir işlemin iki adımı ya birlikte oluyor ya hiç olmuyor, yani yarım kalmış işlemden kurtarma yükü doğuyor. HTTP bu yükü hiç üstlenmemeyi seçti.

Bedeli mesajın içinde taşınan değerin görünürlüğü. İzlemede mekanizmanın kendisi hiç değişmiyor: aynı satır, aynı başlık, aynı veritabanı sorgusu. Değişen tek şey çerezi kimin koyduğu.

Bu yüzden savunma protokolde değil, protokolün dışında kuruldu. Üçüncü taraf izleme çerezleri Firefox ve Safari’de varsayılan olarak kapatıldı. Chrome ise yıllarca ertelediği kapatma planından 2024’te vazgeçti ve yerine koymayı düşündüğü teknolojileri 2025’te tümden emekliye ayırdı; üçüncü taraf çerezleri orada hâlâ varsayılan olarak açık. Hukuk da aynı yerden giriyor. AB’nin ePrivacy yönergesi, cihaza zorunlu olmayan bir şey yazmak için kullanıcıdan izin istiyor ve sitelerde karşına çıkan onay kutularının dayanağı bu. GDPR ise kişiyi teşhis edebilen bir çerezi kişisel veri sayıyor ve iznin nasıl alınacağını tarif ediyor; Türkiye’de KVKK da aynı yaklaşımı izliyor.

Aynı nesneyi kaç kez indirmen gerekiyor?

Bir web önbelleği istekleri asıl sunucuyu hiç işin içine katmadan karşılıyor. Nesne depoda varsa istemciye oradan dönüyor ve istek dışarı çıkmıyor. Yoksa önbellek nesneyi asıl sunucudan istiyor, gelen kopyayı saklıyor, aynı kopyayı istemciye veriyor. Kaçırılan isabet sonraki isabeti hazırlıyor.

Bu kutu iki rolü aynı anda oynuyor: isteği yapan istemciye karşı sunucu, asıl sunucuya karşı istemci. Adı proxy.

Kazanç iki tane. Birincisi yanıt süresinin kısalması, çünkü kopya sana daha yakın duruyor. İkincisi kurumun dış erişim hattındaki trafiğin azalması. Asıl dert de o hattın doluluğu: kullanım oranı yükseldikçe kuyruk gecikmesi patlıyor.

Bir kurumun erişim hattı 10 Mbit/s olsun. Kullanıcılar saniyede 40 istek yapıyor ve ortalama nesne 200 kbit. Önbelleksiz durumda hattan 8 Mbit/s geçiyor, yani hat %80 dolu. İsabet oranı %55 olduğunda dışarı yalnızca %45 çıkıyor: 3,6 Mbit/s ve %36 doluluk. Asıl sunucudan gelen istek 1,2 saniye, önbellekten gelen 5 ms sürüyorsa ortalama 0,54 saniyeye iniyor. Hiç kapasite satın alınmadı.

Önbellekler ağın ortasına yerleşmiş ara kutulardan biri. Servis sağlayıcıda, mobil ağda ve içeriğin kopyalarını dünyaya yayan içerik dağıtım ağlarında duruyorlar; tek bir sayfa isteği yol boyunca birden çok önbelleğe uğrayabiliyor. İsteğin doğuşunda andığım tarayıcı önbellekleri bu zincirin hem ilk halkası hem de sana en yakın duranı.

RFC 9111 iki tür ayırıyor. Paylaşılan önbellek birden çok kullanıcı için saklıyor ve genellikle ara kutu olarak konuşlanıyor. Özel önbellek tek kullanıcıya ait, çoğunlukla tarayıcının içinde duruyor. Tanım da sade: HTTP önbelleği, yanıt mesajlarının yerel deposu ve depoyu yöneten alt sistem. Tünel rolündeki bir taraf önbellek kullanamıyor.

Yaşı tazelik ömrünü aşmamış yanıt taze, aşmış olan bayat. Taze yanıt asıl sunucuya hiç sorulmadan kullanılıyor. Yanıtın yaşı, asıl sunucuda üretildiği ya da orada başarıyla doğrulandığı andan beri geçen süre; Age başlığı bu tahmini saniye olarak taşıyor.

Süreye sunucu karar veriyor, kararını da yanıt başlığında bildiriyor.

YönergeNe diyor
max-ageyaş belirtilen saniyeyi geçince yanıt bayat sayılıyor
no-storeyanıtın hiçbir parçası saklanmıyor
no-cachesaklanabiliyor, ama doğrulanmadan kullanılamıyor
privateyanıt tek kullanıcıya ait, paylaşılan önbellek saklayamıyor

Ortadaki iki satır sık karıştırılıyor. Yasak farklı: no-store saklamayı, no-cache doğrulamadan kullanmayı engelliyor. Tarayıcının kendi önbelleği private yazan yanıtı yine de saklayabiliyor.

Çerez başlığının varlığı yanıtın önbelleklenmesini kendiliğinden engellemiyor. Kişiye özel bir yanıtı paylaşılan önbellekten korumak istiyorsan private ya da no-store’u açıkça yazman gerekiyor.

Sunucu hiç süre vermediyse önbellek kendi tahminini yapıyor. Last-Modified tarihine bakıp o tarihten beri geçen sürenin %10’unu ömür sayması yaygın bir seçim. O ömür dolana kadar oradaki kopya taze sayılıyor, gerçekte eskimiş olsa bile. Her önbellek tazelik ile doğruluk arasında bir takas yapıyor. Aynı takas, yaşam süresi adıyla, 5. bölümdeki ad önbelleklerinde de vardı.

Kopyan hâlâ geçerli mi?

Koşullu istek, metodun uygulanmasından önce sınanacak bir önkoşul taşıyan istek. Önkoşul tutmazsa metot hiç uygulanmıyor. Önbellek tazelemenin en verimli yolu koşullu GET. Aynı mekanizma PUT ile DELETE’te kayıp güncelleme sorununu da önlüyor.

Önkoşulda kullanılabilen kaynak üstverisine doğrulayıcı deniyor. HTTP iki tane tanımlıyor.

Last-Modified gösterimin son değişme anını HTTP tarih biçiminde ve saniye çözünürlüğünde taşıyor. ETag ise opak: içinde ne yazdığı istemciyi ilgilendirmiyor, yalnızca eşit mi değil mi diye karşılaştırılıyor. Tırnak içinde bir dizi. Zayıf üretilmiş etiketin başına W/ öneki konmak zorunda, varsayılanı güçlü doğrulayıcı. Saniye çözünürlüğü yetmediğinde ya da değişiklik tarihi düzgün tutulmadığında tarihten daha güvenilir çalışıyor.

İstemci koşulu iki başlıktan biriyle kuruyor. If-None-Match isteği, elindeki etiketlerden hiçbirinin eşleşmemesi koşuluna bağlıyor; eşleşme varsa koşul yanlış oluyor. If-Modified-Since ise GET ya da HEAD’i gösterimin değişme tarihine bağlıyor, veri değişmediyse hiç aktarılmıyor. İkisi birden gelirse tarih yok sayılıyor, çünkü etiket daha kesin sayılıyor. Birlikte gönderilmelerinin tek sebebi, If-None-Match’i gerçeklemeyen eski ara kutularla uyum.

Koşul yanlış çıkarsa sunucu GET ve HEAD için 304, diğer metotlar için 412 dönmek zorunda. Bu iki kodun sınıfı, durum kodlarını ilk rakama göre ayırırken sabitlenmişti. 304 Not Modified, koşul yanlış çıkmasaydı 200 dönecek olan bir isteğin yanıtı. Sunucu istemciyi kendi kopyasına yönlendiriyor. Yanıt başlık bölümü bitince bitiyor.

Boş dönmüyor ama. 304 üreten sunucu, aynı isteğe 200 dönseydi göndereceği Content-Location, Date, ETag ve Vary alanlarını, ayrıca Cache-Control ile Expires’ı yine göndermek zorunda.

HTTP/1.1 304 Not Modified
Date: Fri, 21 Aug 2026 09:14:02 GMT
ETag: "b41f-63c0a7d1e2"
Cache-Control: max-age=1800

Dört satır ve kapanış boş satırı, toplam 120 bayt. Tam gövdeli karşılığı 18.432 baytlık bir stil dosyası olsaydı fark 153 kat olurdu.

Kazanç turda değil, taşınan baytta. Koşullu istek de tam bir gidiş-dönüş ödüyor: soru çıkıyor, cevap dönüyor. Nesne hiç iletilmediği için aktarım gecikmesi ödenmiyor ve ağ kaynağı harcanmıyor.

Bunu kendi makinende iki adımda görebilirsin. Önce yalnızca başlıkları çekip last-modified satırını kopyalıyorsun, sonra o tarihi koşul olarak geri gönderiyorsun.

curl -sI https://example.com/
curl -sI -H "If-Modified-Since: <yukarıdaki tarih>" https://example.com/

İkinci çıktının ilk satırı HTTP/1.1 304 Not Modified oluyor ve gövde hiç gelmiyor. Aynı çıktıda etag ve Age satırları da duruyor, yani doğrulayıcıyı ve paylaşılan bir önbelleğin yaşını tek komutta görüyorsun. example.com belgeleme için ayrılmış bir ad.

Özet

  • HTTP hiçbir şey tutmuyor: her istek ötekilerden bağımsız okunuyor ve adımları birbirine bağlayan şey protokolün dışında kalıyor.
  • Çerez durumu senin makinene koyuyor: Set-Cookie yazıyor, Cookie geri getiriyor, tarayıcı saklıyor, veritabanı karşılığını tutuyor.
  • Öznitelikler ömrü ve kapsamı çiziyor: Max-Age süreyi, Domain ile Path yeri, Secure ile HttpOnly erişimi sınırlıyor.
  • Önbellek kapasite satın almadan doluluğu düşürüyor: kopya sana yaklaşıyor ve dış hattın kullanım oranı geriliyor.
  • Koşullu istek baytı kurtarıyor, turu değil: soru yine gidip geliyor, ama nesne hiç iletilmiyor.

Tek bir nesne için bütün bu yolu yürüdün: bir kimlik, bir saklama kararı, bir de tazelik sorusu. Ama açtığın sayfa tek nesne değil; onlarca parçadan kurulu. Bir sayfa yüzlerce parçadan oluşuyorsa, her parça için bu yolu baştan mı yürüyeceksin?

15. bölüme devam et: HTTP/2'den HTTP/3'e