document.cookie ve Set-Cookie: Çerez Okuma, Yazma, Silme ve Öznitelikler
document.cookie ile çerez okuma ve yazma, Expires, Max-Age, Domain, Path, Secure, HttpOnly, SameSite öznitelikleri, çerez önekleri ve Cookie Store API.
Tarayıcıda çerez okumak için document.cookie özelliğini okursunuz; size "ad=deger; ad2=deger2" biçiminde, noktalı virgülle ayrılmış bir metin döner. Çerez yazmak için aynı özelliğe "ad=deger; max-age=...; path=/; samesite=lax; secure" gibi bir metin atarsınız; her atama yalnızca bir çerezi oluşturur veya günceller. Sunucu tarafında ise çerezi Set-Cookie yanıt başlığı kurar ve HttpOnly işaretli çerezler JavaScript'e hiç görünmez.
Bu yazı çerezlerin teknik tarafını anlatır: document.cookie okuma ve yazma kuralları, Expires, Max-Age, Domain, Path, Secure, HttpOnly, SameSite ve Partitioned öznitelikleri, __Host- gibi önekler ve eş zamansız Cookie Store API. Çerez bandı, aydınlatma metni ve KVKK gibi hukuki konular çerez politikası ve çerez bandı yazısındadır. Dizinin genel haritası için Web API öğrenme rehberi sayfasına bakabilirsiniz.
Çerez nedir, neden hâlâ kullanılır?
Çerez, sunucunun tarayıcıya gönderdiği küçük bir veri parçasıdır. Tarayıcı onu saklar ve sonraki isteklerde aynı sunucuya Cookie başlığıyla geri yollar. HTTP kendi başına durumsuz olduğu için çerezler, ardışık isteklerin aynı tarayıcıdan geldiğini anlamanın temel yoludur. MDN üç ana kullanım sayar: oturum yönetimi (giriş durumu, sepet), kişiselleştirme (dil, tema) ve izleme.
Eskiden çerezler genel amaçlı istemci deposu olarak da kullanılıyordu. MDN artık bunun yerine localStorage ve sessionStorage ya da IndexedDB önerir. Gerekçesi açıktır: tarayıcılar alan adı başına çerez sayısını (genellikle yüzlerle ifade edilen bir sınır) ve çerez başına boyutu (genellikle 4 KB) kısıtlar; ayrıca her çerez her istekle gönderildiği için çok sayıda çerez özellikle yavaş mobil bağlantılarda performansı düşürür. Kısacası çerezi, sunucunun gerçekten görmesi gereken bilgi için kullanın.
Akış şöyle işler: sunucu yanıtına bir veya daha fazla Set-Cookie başlığı ekler, her başlık ayrı bir çerez kurar. Tarayıcı sonraki isteklerde bu çerezleri tek bir Cookie başlığında birleştirir:
document.cookie bir veri özelliği değil, tarayıcının yerel getter ve setter işlevleri olan bir erişimci (accessor) özelliğidir. Bu yüzden yazdığınız metinle okuduğunuz metin aynı değildir. Okuduğunuzda yalnızca ad=deger çiftlerini alırsınız; path, expires gibi öznitelikler okunan metinde yer almaz ve HttpOnly çerezler listede hiç görünmez. MDN'e göre çiftlerin etrafında boşluk olabilir; şartname her noktalı virgülden sonra tek bir boşluk ister ama bazı tarayıcılar buna uymayabilir.
Tek bir çerezin değerini almak için MDN'in önerdiği kalıp, metni "; " ile bölüp ilgili önekle başlayan parçayı bulmaktır:
Bu kısa kalıp değer içinde = işareti varsa değeri keser ve boşluk farklarına duyarlıdır. Daha dayanıklı bir yardımcı, ilk = işaretinden bölüp boşlukları kırpar ve yüzde kodlamasını çözer. Aşağıdaki işlev yalnızca bir string üzerinde çalıştığı için tarayıcıdan bağımsızdır; örnek metinle Node.js'te çalıştırılıp çıktıları doğrulandı. Tarayıcıda cerezleriAyristir(document.cookie) şeklinde çağırırsınız.
javascript
function cerezleriAyristir(metin) {
const sonuc = {};
for (const parca of metin.split(";")) {
const esit = parca.indexOf("=");
if (esit === -1) continue;
const ad = parca.slice(0, esit).trim();
const deger = parca.slice(esit + 1).trim();
sonuc[ad] = decodeURIComponent(deger);
}
return sonuc;
}
const ornek = "tema=koyu; sepet=3; not=Merhaba%3B%20d%C3%BCnya";
const c = cerezleriAyristir(ornek);
console.log(c.tema); // koyu
console.log(c.not); // Merhaba; dünya
console.log(JSON.stringify(c)); // {"tema":"koyu","sepet":"3","not":"Merhaba; dünya"}
document.cookie ile yazma ve öznitelikler
Yazarken "ad=deger" çiftinin ardından, her biri noktalı virgülle ayrılmış isteğe bağlı öznitelikler eklersiniz. Bir atama tek bir çerezi etkiler; diğer çerezler silinmez. MDN'deki genel akış şudur:
Çerez değerinde virgül, noktalı virgül ve boşluk kullanılamaz. MDN, değeri encodeURIComponent() ile kodlamayı önerir. Aşağıdaki örnek, değeri kodlayıp bir yıllık bir çerez metni hazırlar; metni üreten kısım Node.js'te çalıştırıldı, son satırdaki atama ise yalnızca tarayıcıda anlamlıdır:
İkisi de çerezin ömrünü belirler; ikisi de yoksa çerez oturum çerezidir ve oturum bitince silinir. Ancak "oturumun bitişi" tarayıcıya bağlıdır: MDN, birçok tarayıcının oturum geri yükleme özelliğinin oturum çerezlerini de geri getirdiğini, bu yüzden oturum çerezlerinin beklenenden uzun yaşayabileceğini hatırlatır. Expires sunucunun saatine göre yazılan bir tarihtir ve istemci saatiyle uyuşmayabilir; Max-Age göreli bir süre olduğu için daha az hataya açıktır ve ikisi birlikte verildiğinde Max-Age önceliklidir.
Domain ve Path
Domain verilmezse çerez yalnızca onu kuran sunucuya gönderilir, alt alan adlarına gitmez; Domain vermek bu yüzden kısıtlamayı gevşetir. Değer, yanıtı gönderen sunucunun kendi alan adı veya bir üst alan adı olmalıdır; com veya co.uk gibi bir genel sonek (public suffix) olamaz. Örneğin api.example.com, Domain=example.com kurabilir ama Domain=other.example.com kuramaz; kurallara uymayan çerezler yok sayılır. JavaScript tarafında da alan adı sayfanın kökeniyle eşleşmelidir; yabancı bir alan adına çerez kurma denemesi sessizce yok sayılır.
Path=/docs verildiğinde /docs, /docs/ ve /docs/Web/ eşleşir; /, /docsets ve /fr/docs eşleşmez. MDN burada önemli bir uyarı yapar: Path bir güvenlik önlemi değildir. Aynı kökende gizli bir iframe açıp onun contentDocument.cookie özelliğini okumak başka bir yolun çerezine erişmeyi sağlar. Çerezi gerçekten ayırmanın tek yolu farklı bir alan adı veya alt alan adı kullanmaktır.
Secure ve HttpOnly
Secure işaretli çerez yalnızca https: isteklerinde gönderilir ve http: sayfalar bu işareti taşıyan çerez kuramaz. MDN, localhost istisnasının Safari tarafından desteklenmediğini ayrıca not eder. Secure, diskte veya JavaScript ile okumayı engellemez; yalnızca aktarımı korur. Sitenizin HTTPS kurulumu için HTTPS ve TLS rehberi ve karma içerik uyarıları için mixed content hatası yazılarına bakın.
HttpOnly işaretli çerez document.cookie ile okunamaz ve değiştirilemez; ama fetch() veya XMLHttpRequest ile yapılan isteklerde gönderilmeye devam eder. MDN, oturumu taşıyan çerezlerin mutlaka HttpOnly olmasını önerir; böylece bir XSS açığı oturum kimliğini doğrudan çalamaz. MDN'in güvenlik bölümündeki örnek, korumasız bir çerezin tek satırlık bir betikle saldırganın sunucusuna nasıl gönderilebileceğini gösterir. XSS'in kendisi ve CSP için XSS ve CSP koruma yazısını okuyun.
SameSite
SameSite, çerezin siteler arası isteklerle gönderilip gönderilmeyeceğini belirler. Strict yalnızca çerezi kuran siteden başlayan isteklerde gönderir, başka siteden gelen normal bir bağlantı tıklamasında bile göndermez. Lax buna ek olarak, adres çubuğunu değiştiren üst düzey gezinmelerde ve güvenli metotlarla (GET gibi) gönderir; fetch() çağrıları, <img> ve <script> alt kaynakları ve iframe içi gezinmeler bu kapsama girmez. None her istekte gönderir ve Secure ile birlikte kullanılmak zorundadır. HTTP çerez kılavuzu, SameSite belirtilmeyen çerezin Lax kabul edildiğini söyler; Set-Cookie sayfası ise bunun tarayıcıya göre değiştiğini ve varsayılan olarak uygulanan Lax sürümünün, son iki dakika içinde kurulmuş çerezleri POST isteklerinde de gönderen daha esnek bir sürüm olduğunu belirtir. CSRF ile ilişkisini CSRF saldırısı ve korunma yazısında ele alıyoruz.
Çerez silme ve güncelleme
Çerezi silmek için ayrı bir yöntem yoktur. Aynı ad, aynı path ve varsa aynı domain ile çerezi yeniden yazar, Expires değerini geçmiş bir tarihe veya Max-Age değerini 0 ya da negatife çekersiniz. Yol veya alan adı farklıysa tarayıcı bunu başka bir çerez sayar ve asıl çerez yerinde kalır; "çerezi sildim ama hâlâ duruyor" sorununun en yaygın nedeni budur.
javascript
// MDN örneğindeki gibi geçmiş bir tarihle silme
document.cookie =
"doSomethingOnlyOnce=; expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=None; Secure";
// Max-Age ile silme; path kurulurken kullanılanla aynı olmalı
document.cookie = "tema=; max-age=0; path=/";
Sunucu tarafında aynı işlem Set-Cookie: id=a3fWa; Max-Age=0 ile yapılır. Bir kayıtlı alan adına ait tüm çerezleri temizlemek için Clear-Site-Data: "cookies" yanıt başlığı da kullanılabilir. Güncellemek için ise aynı adla yeni değeri göndermeniz yeterlidir. MDN ayrıca güvenlik açısından bir uyarı ekler: kullanıcı kimlik doğruladığında oturum çerezini, var olsa bile, yeniden üretip göndermek oturum sabitleme (session fixation) saldırılarına karşı korur.
Çerez önekleri: __Secure- ve __Host-
Sunucu, bir çerezin nereden ve hangi özniteliklerle kurulduğunu doğrulayamaz. Bir alt alan adındaki uygulama Domain ile tüm kardeş alt alan adlarına çerez yazabilir. Önekler bu durumu sınırlayan ek bir savunma katmanıdır. Tüm önekler çift alt çizgiyle başlar ve tireyle biter; tire önekin parçasıdır:
__Secure-: Çerez Secure özniteliğiyle ve HTTPS bir sayfa tarafından kurulmalıdır.
__Host-: Secure zorunludur, Domain belirtilemez ve Path=/ olmalıdır. Böylece çerez yalnızca kuran ana makineye gider ve hiçbir yolda üzerine yazılamaz.
__Http-: Secure ve HttpOnly zorunludur; yani yalnızca Set-Cookie ile kurulabilir, document.cookie veya Cookie Store API ile kurulamaz.
__Host-Http-: __Http- kurallarına ek olarak __Host- kısıtlamalarını da taşır.
Tarayıcı kurallara uymayan önekli çerezleri reddeder. Sunucu tarafında çerez adını önekle birlikte kontrol etmeniz gerekir, çünkü tarayıcı Cookie başlığında öneki çıkarmaz. MDN'in uyarısıyla: önekleri desteklemeyen tarayıcılarda bu ek güvenceye güvenemezsiniz, çünkü orada önekli çerezler her zaman kabul edilir.
JavaScript ve Set-Cookie başlığı
Ön uç kodu Set-Cookie başlığını göremez. Fetch şartnamesi bu başlığı yasaklı yanıt başlığı olarak tanımlar ve tarayıcı onu JavaScript'e açılan yanıttan süzer. Aynı şekilde fetch() veya XMLHttpRequest ile istek başlatırken Cookie başlığını elle göndererek çerez değiştiremezsiniz. Bir başka nokta: CORS kullanan bir istekte tarayıcı, istek kimlik bilgilerini (credentials) içermiyorsa yanıttaki Set-Cookie başlıklarını yok sayar. Kimlik bilgili istekleri CORS rehberinde, credentials seçeneğini Request, Response ve Headers yazısında anlatıyoruz.
Cookie Store API: eş zamansız çerez yönetimi
MDN, document.cookie özelliğinin eş zamanlı olduğunu ve okuma sırasında ana iş parçacığını bloke edebildiğini belirtir; mümkünse eş zamansız Cookie Store API'nin kullanılmasını önerir. Bu API promise tabanlıdır, Document nesnesine bağlı olmadığı için service worker içinde de kullanılabilir (ServiceWorkerGlobalScope.cookieStore) ve hata durumunda daha anlaşılır geri bildirim verir; bir çerezi yazıp başarılı olup olmadığını anlamak için hemen geri okumanız gerekmez. Tarayıcı desteği için MDN uyumluluk tablosuna bakın.
cookieStore.set() iki biçimde çağrılır: set(name, value) veya name, value, expires, maxAge, domain, path, sameSite ve partitioned alanlarını içeren bir seçenek nesnesiyle. expires milisaniye cinsinden bir Unix zaman damgasıdır; path varsayılan olarak / olur. expires ile maxAge birlikte verilirse çağrı TypeError ile reddedilir.
get() eşleşen ilk çerezi temsil eden bir nesneye, eşleşme yoksa null değerine çözülür. Bu nesnede güvenebileceğiniz alanlar name ve value'dur; MDN, domain, expires, path, sameSite, secure ve partitioned alanlarının standart dışı olduğunu ve bunlara güvenilmemesi gerektiğini belirtir. getAll() eşleşen tüm çerezleri bir liste olarak verir, delete() ise silme tamamlandığında veya eşleşen çerez yoksa undefined ile çözülür. Yöntemler, köken bir URL'ye serileştirilemezse SecurityError fırlatır.
Değişiklikleri izlemek için cookieStore üzerinde change olayını dinlersiniz. Olay nesnesi bir CookieChangeEvent'tir: changed yeni kurulan çerezleri, deleted süresi dolan veya silinen çerezleri listeler. Aynı ad, alan adı ve yolla üzerine yazılan bir çerez, MDN'e göre olay tetiklemez.
javascript
cookieStore.addEventListener("change", (event) => {
for (const c of event.changed) console.log("kuruldu:", c.name);
for (const c of event.deleted) console.log("silindi:", c.name);
});
Sık yapılan hatalar
Birden fazla çerezi tek atamada yazmaya çalışmak: MDN'e göre bir atama yalnızca tek bir çerezi kurar veya günceller; her çerez için ayrı atama yapın.
Silerken path veya domain'i unutmak: Çerez path=/ ile kurulduysa silerken de path=/ verin.
HttpOnly çerezi JavaScript'le okumayı denemek: Görünmemesi tasarım gereğidir; değeri gerekiyorsa sunucudan ayrı bir uç noktayla alın.
SameSite=None verip Secure'u unutmak:None değeri Secure olmadan kullanılamaz.
Path'i güvenlik sınırı sanmak: Aynı kökendeki her sayfa iframe hilesiyle başka yolun çerezini okuyabilir.
Büyük veriyi çereze koymak: Her istekte gönderilir ve boyut sınırına takılır; istemci verisi için Web Storage veya IndexedDB kullanın.
Sık Sorulan Sorular
document.cookie neden bazı çerezleri göstermiyor?
HttpOnly işaretli çerezler JavaScript'e hiç açılmaz; başka bir yol (Path) veya alan adı için kurulmuş çerezler de o sayfaya ait değildir. Ayrıca okunan metinde yalnızca ad ve değerler bulunur, öznitelikler bulunmaz.
Çerez boyutu ve sayısı için sınır nedir?
MDN'in HTTP çerez kılavuzuna göre tarayıcılar alan adı başına çerez sayısını (genellikle yüzlerle sınırlı) ve çerez başına boyutu (genellikle 4 KB) kısıtlar; kesin değerler tarayıcıya göre değişir.
Cookie Store API document.cookie'nin yerini alır mı?
Aynı çerezleri yönetir ama eş zamansızdır ve service worker'da da çalışır. MDN'in HTTP kılavuzu örneklerinde hâlâ document.cookie kullanılır, çünkü en yaygın desteklenen yol odur. Yeni API'yi kullanmadan önce desteği MDN uyumluluk tablosundan kontrol edin.
Oturum çerezi tarayıcı kapanınca kesin silinir mi?
Hayır. Oturumun ne zaman bittiğine tarayıcı karar verir ve oturum geri yükleme özelliği olan tarayıcılar oturum çerezlerini de geri getirebilir. Kritik oturumlar için sunucu tarafında bir zaman aşımı uygulayın.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
Haber siteleri için yayın yazılımı, barındırma ve sunucu altyapısı kuruyor; sahada öğrendiklerini yazıya döküyor.
Bu yazı genel bilgilendirme amacıyla hazırlanmıştır; hukuki, mali, vergisel ya da teknik danışmanlık değildir ve bir uzmanın görüşünün yerine geçmez. Bilgileri olabildiğince doğru ve güncel aktarmaya çalışıyoruz, ancak yazıda hata veya eksik bulunabilir; mevzuat, ücretler ve yazılım sürümleri yayımdan sonra değişmiş olabilir. Bağlayıcı olan resmî kaynaktır. Yazıdaki bilgilere dayanılarak yapılan işlemlerin sonuçlarından yazar ve KEYDAL sorumlu tutulamaz; önemli bir karar vermeden önce resmî kaynağı kontrol edin ya da bir uzmana danışın. Bir yanlış fark ederseniz bize bildirin, düzeltelim.