Ders 02 / 15
Oturumlar
Durumu sunucuda tutan oturum düzeneği: oturum çerezindeki kimlik, $_SESSION, session_regenerate_id(true) ve kimliği taşıyan tarafın sınırı.
Yayın Güncelleme
Bu derste
- Oturum çerezinin yalnız bir kimlik taşıdığını, durumun sunucuda kaldığını açıklar
- session_start() ve $_SESSION ile sepeti sunucuda tutup istemcinin çerezinin sonucu değiştirmediğini ölçer
- Girişte session_regenerate_id(true) ile kimliği yenileyip oturum verisinin korunduğunu gösterir
- İstemcinin kimliği seçebildiği sınırı ölçüp oturumu sunucu olarak sınıflayan cümleyi bu sınırla birlikte okur
İçindekiler
Çerezler dersi sepeti istemcide bıraktı ve istemci onu 2’den 5’e çevirebildi. İmza bu çevirmeyi fark etti ama sonucun sahibini değiştirmedi. Bu ders aynı değeri sunucuya taşır: istemcinin elinde yalnız bir kimlik kalır, sepetin kendisi sunucuda durur.
Düzeneğin adı oturumdur (session). session_start() çağrısı iki iş yapar. İstekte bir oturum kimliği (session id) taşıyan çerez varsa sunucudaki o kimliğe ait kaydı açar ve içeriğini $_SESSION dizisine yükler. Yoksa yeni bir kimlik üretir, boş bir kayıt açar ve kimliği yanıtta bir çerezle, yani oturum çerezi (session cookie) olarak yollar. İstemci sonraki isteklerde bu çerezi geri gönderir. Çerezin taşıdığı şey sepet değil, kaydın adıdır.
Kimlik bir tutamaçtır. C’de Bellek ve İşaretçiler kursunda bir işaretçi başka bir yerde duran veriyi gösterir ve gösterdiği şeyin yaşamını kodu yazan yönetir. Oturum kimliği de sunucudaki bir durumu gösteren tutamaçtır; fark, tutamacı elinde taşıyanın kodu yazan değil, istemci olmasıdır. Bu farkın ölçüm için ne anlama geldiği dersin sonunda görülür.
Sepet Sunucuda
Ölçüm Çerezler dersindeki aynı çekirdekle yapılır. taraf.php bir önceki dersten birebir gelir ve değişmez; burada yalnız yeniden verilir.
<?php // taraf.php — bu sonucu kim değiştirebiliyor? declare(strict_types=1); // Kodun dışındaki taraflar, karar sırasıyla: her istek, her dış çağrı, her dağıtım. const DIS_TARAFLAR = ['istemci', 'üçüncü taraf', 'ortam']; /** Sonucu bir kez sapmasız, sonra her dış tarafın sapmasıyla ayrı ayrı hesaplar. */ function sina(callable $sonuc, array $sapmalar): array { $taban = $sonuc([]); $degisti = []; foreach (DIS_TARAFLAR as $taraf) { if (array_key_exists($taraf, $sapmalar)) { $degisti[$taraf] = $sonuc([$taraf => $sapmalar[$taraf]]) !== $taban; } } return $degisti; } /** Sonucu değiştirebilen ilk dış taraf; hiçbiri değiştiremiyorsa sunucu. */ function taraf(array $degisti): string { foreach (DIS_TARAFLAR as $t) { if ($degisti[$t] ?? false) return $t; } return 'sunucu'; } function tarafRaporu(string $ad, callable $sonuc, array $sapmalar): string { $degisti = sina($sonuc, $sapmalar); $satirlar = []; foreach ($degisti as $t => $d) $satirlar[] = $t . ($d ? ' değiştirdi' : ' değiştiremedi'); $sonTaraf = taraf($degisti); echo "$ad → $sonTaraf\n ", implode(' · ', $satirlar), "\n"; return $sonTaraf; }
Yeni dosya oturum.php’dir. İlk bölüm oturumu kurar. Dört ayar açıkça verilir, çünkü ders çalışma zamanının varsayılanına güvenmez. session.use_strict_mode sunucunun tanımadığı bir kimliği kabul etmemesini ister; varsayılanı kapalıdır. session.cookie_samesite oturum çerezinin başka bir sitenin isteğiyle gönderilmesini sınırlar; varsayılanı boştur. session.cookie_httponly çerezi sayfadaki betikten saklar. session.save_path kayıtların yazıldığı yeri geçici dizine bağlar. ob_start() çıktıyı tamponlar, çünkü oturum başlıkları ilk çıktıdan önce gönderilmek zorundadır ve tampon bu sırayı koşum boyunca korur.
<?php // oturum.php — sepet oturumda durur; istemcinin çerezi sonucu değiştiremez declare(strict_types=1); require 'taraf.php'; ob_start(); ini_set('session.use_strict_mode', '1'); ini_set('session.cookie_samesite', 'Lax'); ini_set('session.cookie_httponly', '1'); ini_set('session.save_path', sys_get_temp_dir()); session_start(); $_SESSION['sepet'] = 2; $onceki = session_id(); session_regenerate_id(true); echo 'kimlik yenilendi: ', session_id() !== $onceki ? 'farklı' : 'aynı', "\n"; echo 'sepet korundu: ', $_SESSION['sepet'], "\n"; tarafRaporu( 'sepet (oturumda)', function (array $s): int { if (isset($s['istemci'])) { $_COOKIE['sepet'] = $s['istemci']; } return $_SESSION['sepet']; }, ['istemci' => '5'], ); ob_end_flush();
kimlik yenilendi: farklı
sepet korundu: 2
sepet (oturumda) → sunucu
istemci değiştiremedi
Sonuç bölümü iki işi bir arada gösterir. İlk iki satır girişte yapılan kimlik yenilemesidir; sonraki iki satır ölçümdür. Ölçümde istemci sepet=5 gönderir ve sapma bunu $_COOKIE’ye yazar. Sepeti okuyan kod ise $_SESSION['sepet']’e bakar. Çerez değişir, sonuç değişmez.
DO5. Karar sırası istemci, üçüncü taraf, ortam, sunucudur. Bu ölçümün karşıtı Çerezler dersindeki ilk satırdır: orada aynı sapma aynı sepeti 2’den 5’e çevirdi ve sonuç istemci çıktı. Burada aynı sapma sonucu değiştiremedi ve sonuç sunucudur. Fark değerin taşındığı yerdir: sepet çerezdeyken isteği gönderen sepetin sahibiydi, sepet sunucudaki kayıtta durunca onun elinde yalnız kaydın adı kalır.
Kaydın Ömrü ve Bedeli
Sunucuda durmanın iki bedeli vardır. Birincisi ömürdür. Kayıt, kullanıcı çıkış yapınca ya da süresi dolunca silinmelidir; silinmezse sunucuda kimsenin kullanmadığı kayıtlar birikir. Kayıt silindiğinde istemcinin elindeki kimlik geçersiz kalır ve session.use_strict_mode açıkken sunucu onu kabul etmez, yeni bir kimlik üretir. Kimliğin istemcide kalması, kaydın sunucuda yaşamasını garanti etmez; kaydın yaşadığına sunucu karar verir.
İkincisi ölçeklemedir. Kayıtlar tek bir makinenin geçici dizininde duruyorsa, aynı kullanıcının iki isteği iki farklı makineye düştüğünde ikinci makine kaydı bulamaz. Bu yüzden birden çok makine çalışan bir uygulamada kayıtlar paylaşılan bir depoya yazılır. Bu bir yapılandırma kararıdır ve bir sonraki dersin konusuna yaklaşır: depoyu kodun içine yazmak yerine ortamın seçmesi gerekir.
Sunucuda durmak bir şeyi daha değiştirir: sepetin doğruluğu artık istemcinin dürüstlüğüne bağlı değildir. Çerezde 5 gelen bir sepeti sunucunun gerçekten 5 olduğunu doğrulaması gerekirdi; oturumda doğrulanacak bir şey yoktur, çünkü değeri sunucu yazdı. Doğrulama yükü kalkmaz, yer değiştirir: kimliğin geçerliliği, kaydın var olup olmadığına indirgenir ve bunu session_start() kendi başına yapar.
Kimliği Yenilemek
Kimlik girişten önce ve sonra aynı kalırsa kimliği bilen biri giriş yapmış oturumu da bilir. Buna oturum sabitleme (session fixation) denir. Düzenek basittir: kullanıcı doğrulandığı anda session_regenerate_id(true) çağrılır. Fonksiyon yeni bir kimlik üretir, true argümanı eski kimliğe ait kaydı siler ve $_SESSION içeriği yeni kayda taşınır.
Ölçüm bunu iki satırda gösterir: kimlik yenilendikten sonra öncekinden farklıdır ve sepet 2 olarak korunur. Kimliğin kendisi basılmaz, çünkü her koşumda değişir; ölçülen şey farktır. Sabitleme saldırısı bu derste kurulmaz. Düzeneğin işi o saldırının dayandığı varsayımı, giriş öncesi ve sonrası kimliğin aynı kalmasını ortadan kaldırmaktır.
DO6. session_regenerate_id(true) sunucunun kendi kaydını güvenceye alan bir önlemdir ve taraf cümlesini değiştirmez. Kimliği üreten de, yenileyen de, eski kaydı silen de sunucudur. Ama kimliği yanıtta çerezle istemciye geri yollamak yine istemcide durmak zorundadır; bu iki durumun birleşimi bir sonraki bölümün konusudur.
Sınırlayıcı Ölçüm
Oturumun sahibi sunucu olarak sınıflandı. Bu cümlenin bir sınırı var: oturum kimliğinin kendisi istemcidedir. İstemci çerezde başka bir kimlik sunarsa ne olur? Aşağıdaki dosya önce bir oturum açıp sepeti 2 yapar, sonra aynı sepeti iki kimlikle okur: sunucunun verdiği kimlik ve istemcinin sunduğu başka bir kimlik. Başka kimlik, sunucunun hiç üretmediği nötr bir dizgedir.
<?php // baska.php — istemci başka bir oturum kimliği sunarsa hangi oturuma düşer declare(strict_types=1); require 'taraf.php'; ob_start(); ini_set('session.use_strict_mode', '1'); ini_set('session.cookie_samesite', 'Lax'); ini_set('session.cookie_httponly', '1'); ini_set('session.save_path', sys_get_temp_dir()); function sepetOku(string $kimlik): int { session_id($kimlik); session_start(); $sepet = $_SESSION['sepet'] ?? 0; session_write_close(); return $sepet; } session_start(); $_SESSION['sepet'] = 2; $kimlik = session_id(); session_write_close(); tarafRaporu( 'sepet (oturumda, istemci başka kimlik sunar)', fn(array $s) => sepetOku($s['istemci'] ?? $kimlik), ['istemci' => 'baskakimlik0123456789'], ); ob_end_flush();
sepet (oturumda, istemci başka kimlik sunar) → istemci
istemci değiştirdi
DO7. Sonuç değişti ve değiştiren istemcidir. Sunucu tanımadığı kimliği kabul etmedi (session.use_strict_mode) ve yeni, boş bir kayıt açtı; sepet 2 yerine 0 okundu. İstemci kendi sepetine başka bir kimlikle değil, hiçbir sepeti olmayan bir oturuma düştü.
Ölçümün ikinci bir okuması da vardır: sapma sunucunun kaydını değiştirmedi. Sunucudaki oturum 2 olarak kaldı, değişen hangi oturumun açıldığıdır. Karar sırası bu yüzden tek bir ölçümde iki cümleye bölünür: sepetin içeriğini istemci belirleyemez, hangi sepetin açılacağını istemci belirler.
Özet
- Oturum, durumu sunucuda tutar. İstemcide kalan yalnız bir kimliktir ve oturum çerezi bunu her istekle geri taşır.
session_start()kimlik varsa kaydı açıp$_SESSION’a yükler, yoksa yeni bir kimlik ve boş kayıt üretir.- Aynı
sepet=5sapması Çerezler dersinde sonucu değiştirdi; oturumda değiştiremedi. Bu dersin ölçü sınıfı sunucudur: sepetin içeriğini istemci belirleyemez. session_regenerate_id(true)girişte kimliği yeniler, eski kaydı siler ve$_SESSIONiçeriğini korur; sabitlemeye karşı düzenek budur.- Sınır: kimliği taşıyan istemcidir. İstemci başka bir kimlik sunarsa kendi sepetine değil başka bir oturuma düşer, yani hangi oturumun açılacağı istemcide kalır.
Sonraki Adım
Çerez de, oturum da istekle gelen veriyi ölçtü. Bir uygulamanın okuduğu her değer istekten gelmez: veritabanı adı, anahtar ve bağlantı ayarları dağıtım ortamından gelir. Sonraki ders, Yapılandırma ve Ortam Değişkenleri, bu değerleri koddan ayırıp ortama bırakır ve kimin değiştirebildiğini ölçer.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.