---
title: 'İstek Sahteciliği'
source: 'https://academia.sh/tr/kurslar/frontend-kalitesi/istek-sahteciligi'
course: 'Frontend Kalitesi'
language: tr
updated: '2026-08-17T18:09:22+00:00'
license: 'CC BY-SA 4.0'
---

# İstek Sahteciliği

Çerezlerin kendiliğinden eklenmesinden doğan saldırı sınıfı; SameSite ve Secure niteliklerinin karar tablosu, oturuma bağlanmış istek belirteci, kaynak başlığı denetimi ve yöntem disiplini.

Önceki ders bir soruyla bitti: aynı kaynak politikası yanıtın okunmasını engelliyorsa,
yazma isteği ne oluyor? Yanıt, engellenmediğidir. Kaynaklar arası bir istek sunucuya
ulaşır, sunucu isteği işler, yan etki gerçekleşir; yalnız yanıt gövdesi isteği başlatan
sayfaya teslim edilmez.

Bu boşluk tek başına sorun değildir. Sorun, isteğe kullanıcının kimliğinin kendiliğinden
eklenmesiyle oluşur. Kuzey Yamaç Ölçüm İstasyonu arayüzünde oturum bir çerezle taşınıyorsa,
tarayıcı o çerezi isteğin nereden başlatıldığına bakmadan ekler. Bu ders o davranışın
sonucunu ve iki bağımsız savunma katmanını kurar.

## Ortam Yetkisi

Çerez, İnternet Nasıl Çalışır kursunda tanımlandığı gibi istekle birlikte kendiliğinden
gider. Bu, oturumun sürmesini sağlayan davranıştır: kullanıcı her sayfada kimliğini
yeniden bildirmez. Aynı davranış bir yan sonuç üretir. İsteği kimin başlattığı çerezin
eklenmesini etkilemez; tarayıcı hedef adrese bakar, kaynağa değil.

Buna **ortam yetkisi (ambient authority)** denir: yetki, isteği yapan koda değil, isteğin
gittiği yere iliştirilmiştir. **Siteler arası istek sahteciliği (cross-site request
forgery)** bu yetkinin başka bir sitenin sayfasından tetiklenmesidir. Kullanıcı ölçüm
istasyonuna giriş yapmış durumdayken başka bir sekmede bir sayfa açar; o sayfa, ölçüm
istasyonunun bir uç adresine yazma isteği başlatır. İstek kullanıcının çerezini taşıdığı
için sunucu tarafında meşru görünür.

Saldırıya betik gerekmez. Bir form ögesi gönderilebilir, bir görsel ögesi bir adresi
çağırabilir. Yanıtın okunamaması saldırganın umurunda değildir; amaç okumak değil,
yaptırmaktır.

## Birinci Katman: Çerez Nitelikleri

İlk savunma çerezin kendisindedir. `SameSite` niteliği, çerezin kaynaklar arası isteklere
eklenip eklenmeyeceğini belirler ve üç değer alır. Aşağıdaki kod bu değerlerin karar
tablosunu hesaplar.

```js
// samesite.mjs — cerez nitelikleri istek turlerine gore karar tablosu uretir
const GUVENLI_YONTEMLER = new Set(['GET', 'HEAD']);

function gonderilirMi(cerez, istek) {
  if (cerez.secure && istek.sema !== 'https') return ['hayir', 'Secure nitelikli cerez sifresiz semada gonderilmez'];
  if (istek.ayniSite) return ['evet', 'ayni site istegi'];
  switch (cerez.sameSite) {
    case 'Strict':
      return ['hayir', 'Strict kaynaklar arasi her istegi diser'];
    case 'Lax':
      return istek.ustDuzeyGezinme && GUVENLI_YONTEMLER.has(istek.yontem)
        ? ['evet', 'Lax ust duzey gezinmede guvenli yontemi gecirir']
        : ['hayir', 'Lax yalniz ust duzey guvenli gezinmeyi gecirir'];
    case 'None':
      return cerez.secure ? ['evet', 'None kaynaklar arasi gonderir'] : ['hayir', 'None icin Secure zorunlu'];
    default:
      return ['hayir', 'taninmayan deger'];
  }
}

const istekler = [
  { ad: 'ayni site cagri', ayniSite: true, ustDuzeyGezinme: false, yontem: 'GET', sema: 'https' },
  { ad: 'disaridan bag (GET)', ayniSite: false, ustDuzeyGezinme: true, yontem: 'GET', sema: 'https' },
  { ad: 'disaridan form (POST)', ayniSite: false, ustDuzeyGezinme: true, yontem: 'POST', sema: 'https' },
  { ad: 'disaridan cerceve', ayniSite: false, ustDuzeyGezinme: false, yontem: 'GET', sema: 'https' },
  { ad: 'disaridan betik cagrisi', ayniSite: false, ustDuzeyGezinme: false, yontem: 'POST', sema: 'https' },
];

const cerezler = [
  { ad: 'Strict+Secure', sameSite: 'Strict', secure: true },
  { ad: 'Lax+Secure', sameSite: 'Lax', secure: true },
  { ad: 'None+Secure', sameSite: 'None', secure: true },
  { ad: 'None, Secure yok', sameSite: 'None', secure: false },
];

const basliklar = ['istek turu'.padEnd(24), ...cerezler.map((c) => c.ad.padEnd(16))].join('').trimEnd();
console.log(basliklar);
for (const istek of istekler) {
  const hucreler = cerezler.map((cerez) => gonderilirMi(cerez, istek)[0].padEnd(16));
  console.log(istek.ad.padEnd(24) + hucreler.join('').trimEnd());
}

console.log('\ngerekce ornegi (Lax+Secure):');
for (const istek of istekler) {
  const [karar, neden] = gonderilirMi(cerezler[1], istek);
  console.log(' ', istek.ad.padEnd(24), karar.padEnd(6), neden);
}
```

```
$ node samesite.mjs
istek turu              Strict+Secure   Lax+Secure      None+Secure     None, Secure yok
ayni site cagri         evet            evet            evet            evet
disaridan bag (GET)     hayir           evet            evet            hayir
disaridan form (POST)   hayir           hayir           evet            hayir
disaridan cerceve       hayir           hayir           evet            hayir
disaridan betik cagrisi hayir           hayir           evet            hayir

gerekce ornegi (Lax+Secure):
  ayni site cagri          evet   ayni site istegi
  disaridan bag (GET)      evet   Lax ust duzey gezinmede guvenli yontemi gecirir
  disaridan form (POST)    hayir  Lax yalniz ust duzey guvenli gezinmeyi gecirir
  disaridan cerceve        hayir  Lax yalniz ust duzey guvenli gezinmeyi gecirir
  disaridan betik cagrisi  hayir  Lax yalniz ust duzey guvenli gezinmeyi gecirir
```

Tablo üç kuralı görünür kılar. `Strict`, kaynaklar arası her isteği diser; koruması en
geniştir ama başka bir siteden gelen bir bağla giren kullanıcı oturumsuz karşılanır.
`Lax`, yalnız üst düzey gezinmede ve yalnız güvenli yöntemle çerezi geçirir; dışarıdan
gelen bir formun `POST` isteği ile bir çerçeve yüklemesi eler. `None` her durumda gönderir
ve bu yüzden `Secure` niteliğini zorunlu kılar; nitelik yoksa çerez hiç gönderilmez.

Bu tabloyla birlikte iki nitelik daha oturum çerezinin ayrılmaz parçasıdır. `HttpOnly`,
çerezin betikten okunmasını engeller; ilk derste kurulan betik çalıştırma savunması
aşıldığında oturumun doğrudan çalınmasını zorlaştırır. `Secure`, çerezin şifresiz bir
bağlantıda gönderilmesini önler.

## SameSite'ın Yetmediği Yerler

Nitelik güçlü bir azaltmadır, ama tek savunma olarak yeterli sayılmaz.

Birincisi, "aynı site" ile "aynı kaynak" farklı ölçütlerdir. Aynı site ölçütü kayıt
edilebilir alan adı üzerinden hesaplanır; `rapor.ornek.test` ile `olcum.ornek.test` ayrı
kaynaklardır ama aynı sitedir. Alt alanlardan birinin denetimini kaybetmek, o alan
üzerinden gönderilen isteklerin aynı site sayılması demektir. Bu riski daraltmak için
çerez adına `__Host-` öneki konur: bu önek, çerezin yalnız tam olarak belirlenen konağa
ait olmasını ve alan adı kapsamının genişletilememesini zorunlu kılar.

İkincisi, niteliğin bildirilmediği durumda uygulanacak davranış gerçekleştirime bağlıdır.
Bazı gerçekleştirimler bildirilmemiş çerezi kısıtlayıcı bir değer gibi ele alır, bazıları
almaz. Bu yüzden nitelik varsayılana bırakılmaz, açıkça yazılır.

Üçüncüsü, `Lax` değeri üst düzey `GET` gezinmesini geçirir. Durum değiştiren bir işlem
`GET` ile yapılıyorsa bu savunma o işlemi kapsamaz. Yöntem disiplini bu yüzden savunmanın
parçasıdır.

## İkinci Katman: Oturuma Bağlı Belirteç

İkinci savunma, isteğin gerçekten uygulamanın kendi sayfasından başlatıldığını kanıtlar.
Sunucu her oturum için tahmin edilemez bir **istek belirteci** üretir, sayfaya gömer ve
gönderimde geri bekler. Belirtecin oturuma bağlanması kritiktir: bağlanmazsa saldırgan
kendi oturumu için aldığı geçerli bir belirteci başka bir kullanıcının isteğine
yerleştirebilir.

```js
// belirtec.mjs — oturuma baglanmis istek belirteci uretimi ve dogrulanmasi
import { createHmac, timingSafeEqual } from 'node:crypto';

const SUNUCU_GIZLISI = Buffer.from('7b2a0f5c9d1e4a8b6c3f0d2e5a7b9c1d', 'utf8');

function belirtecUret(oturumKimligi, tuz) {
  const imza = createHmac('sha256', SUNUCU_GIZLISI).update(`${oturumKimligi}.${tuz}`).digest('base64url');
  return `${tuz}.${imza}`;
}

function belirtecDogrula(oturumKimligi, belirtec) {
  if (typeof belirtec !== 'string' || !belirtec.includes('.')) return false;
  const [tuz] = belirtec.split('.');
  const beklenen = Buffer.from(belirtecUret(oturumKimligi, tuz));
  const gelen = Buffer.from(belirtec);
  return beklenen.length === gelen.length && timingSafeEqual(beklenen, gelen);
}

function kaynakDenetimi(basliklar, beklenen) {
  if (basliklar['sec-fetch-site'] === 'same-origin') return true;
  if (basliklar.origin) return basliklar.origin === beklenen;
  return false;
}

const OTURUM = 'oturum-4417';
const gecerli = belirtecUret(OTURUM, 'a1b2c3');
console.log('uretilen belirtec:', gecerli);

const denemeler = [
  ['dogru oturum, dogru belirtec', OTURUM, gecerli],
  ['baska oturumun belirteci', 'oturum-9002', gecerli],
  ['imzasi degistirilmis', OTURUM, `${gecerli.slice(0, -1)}X`],
  ['belirtec yok', OTURUM, undefined],
];

console.log('\nbelirtec dogrulama:');
for (const [ad, oturum, deger] of denemeler) {
  console.log(' ', ad.padEnd(30), belirtecDogrula(oturum, deger) ? 'gecerli' : 'reddedildi');
}

const BEKLENEN_KAYNAK = 'https://olcum.ornek.test';
const baslikKumeleri = [
  ['kendi sayfasindan', { origin: BEKLENEN_KAYNAK, 'sec-fetch-site': 'same-origin' }],
  ['baslik yok, isaret var', { 'sec-fetch-site': 'same-origin' }],
  ['disaridan gonderim', { origin: 'https://baska.ornek.test', 'sec-fetch-site': 'cross-site' }],
  ['ikisi de yok', {}],
];

console.log('\nkaynak denetimi:');
for (const [ad, basliklar] of baslikKumeleri) {
  console.log(' ', ad.padEnd(30), kaynakDenetimi(basliklar, BEKLENEN_KAYNAK) ? 'kabul' : 'reddedildi');
}
```

```
$ node belirtec.mjs
uretilen belirtec: a1b2c3.F5jj3rvIaTbTm94oBnF_AttfP9Oumrx8um4rO-DYY64

belirtec dogrulama:
  dogru oturum, dogru belirtec   gecerli
  baska oturumun belirteci       reddedildi
  imzasi degistirilmis           reddedildi
  belirtec yok                   reddedildi

kaynak denetimi:
  kendi sayfasindan              kabul
  baslik yok, isaret var         kabul
  disaridan gonderim             reddedildi
  ikisi de yok                   reddedildi
```

Belirteç, sunucu gizlisiyle üretilen bir imza taşır ve imza oturum kimliğini kapsar; başka
bir oturumun belirteci sunulduğunda imza uyuşmaz. Karşılaştırma `timingSafeEqual` ile
yapılır: karakter karakter kısa devre yapan bir karşılaştırma, doğru önek uzunluğunu
ölçülebilir bir zaman farkına dönüştürür.

Belirtecin taşınma yolu da kuralın parçasıdır. Yalnız bir çerezde taşınırsa saldırı
karşısında değeri kalmaz, çünkü çerez de kendiliğinden gider. Belirteç, çerez dışında bir
yerde bulunmalıdır: gizli bir form alanı veya uygulamanın açıkça eklediği bir istek
başlığı. Uygulama Mimarisi kursundaki Tarayıcıda Kimlik Doğrulama dersi bu ayrımın öteki
yüzünü kurmuştu; oturumu bir çerez yerine bellekteki bir belirteçle taşıyan ve isteğe
açıkça ekleyen bir tasarımda ortam yetkisi zaten oluşmaz, dolayısıyla bu saldırı sınıfı
kendiliğinden ortadan kalkar. Bedeli, oturumun sayfa yenilemesinde yeniden kurulmasıdır.

## Üçüncü Katman: Kaynak Denetimi

Çıktının son bölümü üçüncü katmanı gösterir. Sunucu, durum değiştiren her istekte isteğin
kaynağını denetler. `Origin` başlığı bulunuyorsa beklenen kaynakla karşılaştırılır. Bu
başlığın bulunmadığı durumlar için tarayıcının eklediği getirme meta bilgisi kullanılır:
`Sec-Fetch-Site` başlığı isteğin aynı kaynaktan mı, aynı siteden mi, yoksa dışarıdan mı
başlatıldığını bildirir.

Denetimin son satırı önemlidir: iki başlığın da bulunmadığı istek kabul edilmez.
Eksikliği "sorun yok" saymak, denetimi bir başlığın silinmesiyle atlatılabilir hâle
getirir. Bu başlıklar uygulama kodunun değil tarayıcının yazdığı başlıklardır ve tarayıcı
tarafından değiştirilemez; yokluklarını güvenli yorumlamak için bir neden yoktur.

## Yöntem Disiplini

Bütün bu katmanların altında bir varsayım vardır: durum değiştiren işlemler güvenli
yöntemlerle yapılmaz. İnternet Nasıl Çalışır kursunda tanımlanan **güvenli yöntem**
kavramı burada bir güvenlik gereğine dönüşür. Ölçüm kaydını silen bir uç `GET` ile
çağrılabiliyorsa, bir görsel ögesi bile o ucu tetikler; `Lax` çerez davranışı ve pek çok
kaynak denetimi bu durumu kapsamaz.

Kural olarak yazma işlemleri `POST`, `PUT`, `PATCH` veya `DELETE` yöntemleriyle yapılır ve
sunucu, yazma uçlarında yöntem denetimini açıkça uygular.

## Özet

- İstek sahteciliği, çerezin isteği kimin başlattığına bakılmadan eklenmesinden doğar;
  yanıtın okunamaması yan etkinin gerçekleşmesini engellemez.
- `SameSite` niteliği ilk katmandır: `Strict` kaynaklar arası her isteği, `Lax` üst düzey
  güvenli gezinme dışındaki her isteği eler; `None` için `Secure` zorunludur.
- Aynı site ölçütü aynı kaynak ölçütünden geniştir; alt alan riski `__Host-` öneki ve ikinci
  bir katmanla daraltılır.
- İstek belirteci oturuma bağlanır, çerez dışında bir yerde taşınır ve sabit zamanlı
  karşılaştırmayla doğrulanır.
- `Origin` ve `Sec-Fetch-Site` başlıkları üçüncü katmandır; ikisinin de bulunmadığı istek
  reddedilir ve durum değiştiren işlemler güvenli yöntemlere açılmaz.

## Sonraki Adım

Bu dersin savunmaları tek tek başlıklar ve nitelikler üzerinden kuruldu. Aynı yanıt
başlığı yüzeyinde, saldırı sınıfına özgü olmayan ama tümünün etkisini azaltan bir küme
daha vardır: bağlantının şifresiz kalmasını engelleyen, belgenin başka bir sayfa
tarafından çerçevelenmesini sınırlayan ve dışarı sızan adres bilgisini daraltan başlıklar.
Sonraki ders bu kümeyi ve eksikliklerini bulan bir yapılandırma denetimini ele alır.
