---
title: 'Sunucu Tarafı İstek Sahteciliği'
source: 'https://academia.sh/tr/kurslar/guvenli-kodlama/sunucu-tarafi-istek-sahteciligi'
course: 'Güvenli Kodlama'
language: tr
updated: '2026-08-17T18:06:42+00:00'
license: 'CC BY-SA 4.0'
---

# Sunucu Tarafı İstek Sahteciliği

Giden istek hedeflerinin kısıt kümesinden geçirilmesi: on iki hedef dört kısıt biçiminden geçirilip kaçının iç ağa ulaşabildiği gerçek adres aritmetiğiyle sayılır, kısıtın yalnız ilk adımda uygulanmasının yeniden yönlendirme zincirinde kaç isteği iç adrese vardırdığı ölçülür ve denetim ile bağlanma arasında ad çözümlemesinin tekrarlanmasının açtığı nokta gösterilir.

Önceki ders yükleme akışında sunucunun aldığı baytları saydı; orada sunucu yalnız saklıyordu.
Bazı akışlarda sunucu daha ileri gider ve dışarıdan gelen bir adrese **kendisi** istek yapar:
rapor üretici abone portalının verdiği bağlantıdan belge çekiyor, saha uygulaması harita
karosunu bir dış uçtan alıyor.

İstek sahteciliğinin daha önce ölçülen biçiminde isteği kullanıcının tarayıcısı gönderiyor ve
kullanıcının kimliğini taşıyordu. Burada isteği sunucunun kendisi gönderir ve taşıdığı
ayrıcalık kimlik değil, **ağdaki yerdir**: sunucu iç ağın içindedir, istemci değildir. Bu
ders o farkı hedef sayısı cinsinden ölçer.

## Adres Aritmetiği

Bir hedefin iç ağa ulaşıp ulaşmadığı ad üzerinden anlaşılmaz, adres üzerinden anlaşılır.
Adres otuz iki bitlik bir sayıdır; bir bloğa düşüp düşmediği maskeyle bir ve işlemidir.
Aşağıdaki blok bu aritmetiği yazar ve kurgu bir ad çözümleyici kurar — ağa hiç çıkılmaz.

**GC13 (varsayım):** ad çözümleme modeldir; gerçek bir sorgu yapılmaz ve tablodaki adlar
belgeleme için ayrılmış aralıklara çözülür. Ölçülen şey çözümlemenin doğruluğu değil,
**kısıtın hangi değere uygulandığıdır**.

```js
// adres.mjs — adres aritmetigi ve kurgu ad cozumleyici. Ag erisimi yok, hepsi model.
export const ayristir = (a) => {
  const p = a.split(".");
  if (p.length !== 4) return null;
  const s = p.map((x) => (/^\d{1,3}$/.test(x) ? Number(x) : -1));
  return s.every((n) => n >= 0 && n <= 255)
    ? (((s[0] << 24) >>> 0) + (s[1] << 16) + (s[2] << 8) + s[3]) >>> 0 : null;
};
export const blok = (c) => {
  const [taban, uzunluk] = c.split("/");
  const m = uzunluk === "0" ? 0 : (0xffffffff << (32 - Number(uzunluk))) >>> 0;
  return [(ayristir(taban) & m) >>> 0, m, c];
};
export const icinde = (adres, [taban, m]) => ((adres & m) >>> 0) === taban;

// Yerel ve ozel kullanima ayrilmis adres bloklari.
export const OZEL = ["0.0.0.0/8", "10.0.0.0/8", "100.64.0.0/10", "127.0.0.0/8",
  "169.254.0.0/16", "172.16.0.0/12", "192.168.0.0/16"].map(blok);
export const ozelMi = (adres) => adres !== null && OZEL.some((b) => icinde(adres, b));

// Kurgu ad cozumleyici: ad -> adres. Gercek bir cozumleme yapilmaz.
export const COZUM = {
  "belge.dis-1.ornek": "203.0.113.24", "karo.dis-2.ornek": "198.51.100.9",
  "arsiv.dis-1.ornek": "203.0.113.40", "arsiv-2.dis-1.ornek": "203.0.113.41",
  "gecis.dis-3.ornek": "192.168.30.5",
  "rapor.ic": "10.12.4.7", "olcum-depo.ic": "10.12.4.20", "yerel.ic": "127.0.0.1",
  "kenar.ic": "169.254.10.5", "sayac.ic": "172.20.8.3",
};
export const coz = (ad) => ayristir(COZUM[ad] ?? ad);

// Giden istek hedefleri (kurgu): rapor ureticinin ve saha uygulamasinin cektigi adresler.
export const HEDEF = [
  ["belge.dis-1.ornek", "bildirilen"], ["karo.dis-2.ornek", "bildirilen"],
  ["arsiv.dis-1.ornek", "kullanici"], ["gecis.dis-3.ornek", "kullanici"],
  ["rapor.ic", "kullanici"], ["olcum-depo.ic", "kullanici"], ["yerel.ic", "kullanici"],
  ["kenar.ic", "kullanici"], ["sayac.ic", "kullanici"], ["203.0.113.99", "kullanici"],
  ["10.12.4.9", "kullanici"], ["127.0.0.1", "kullanici"],
];
export const BILDIRILEN = ["belge.dis-1.ornek", "karo.dis-2.ornek", "arsiv.dis-1.ornek"];
```

Hedeflerin üçü bildirilen dış konaklardır; dokuzu kullanıcı verisinden geliyor. Bu ayrım
kapsamanın çıkış noktasıdır: kısıtın kapatması gereken küme dokuz kalemdir, üç kalem zaten
sözleşmenin içindedir.

## Dört Kısıt Biçimi

Aynı hedef kümesi dört kısıttan geçiriliyor. Kısıt yokken, ada bakan bir ret listesiyle,
çözülmüş adrese bakan bir ret listesiyle ve bildirilen konakları sayan bir izin listesiyle.

```js
// kisit.mjs — ayni hedef kumesi dort kisit biciminden geciriliyor
import { HEDEF, BILDIRILEN, OZEL, coz, ozelMi, blok, icinde, ayristir } from "./adres.mjs";

const KISIT = [
  ["kisit yok", () => true],
  ["ad temelli ret listesi", (h) => !h.endsWith(".ic")],
  ["adres temelli ret listesi", (h) => !ozelMi(coz(h))],
  ["izin listesi (bildirilen konak)", (h) => BILDIRILEN.includes(h)],
];

console.log(`${HEDEF.length} giden istek hedefi, ${OZEL.length} ozel adres blogu`);
console.log(`bildirilen dis konak: ${BILDIRILEN.length}, kullanici verisinden gelen hedef: ` +
  `${HEDEF.filter(([, k]) => k === "kullanici").length}\n`);
console.log(`${"kisit bicimi".padEnd(34)}${"gecen".padStart(7)}${"ic aga ulasan".padStart(15)}${"duran bildirilen".padStart(18)}`);
for (const [ad, f] of KISIT) {
  const gecen = HEDEF.filter(([h]) => f(h));
  const ic = gecen.filter(([h]) => ozelMi(coz(h))).length;
  const duran = BILDIRILEN.filter((h) => !f(h)).length;
  console.log(ad.padEnd(34) + String(gecen.length).padStart(7) + String(ic).padStart(15) +
    String(duran).padStart(18));
}

// Adres aritmetigi gercekten kosuyor: hangi hedef hangi bloga dusuyor.
console.log("\nozel bloga dusen hedefler:");
for (const [h] of HEDEF) {
  const a = coz(h);
  const b = OZEL.find((x) => a !== null && icinde(a, x));
  if (b) console.log(`  ${h.padEnd(20)} -> ${String(a >>> 0).padStart(10)} blok ${b[2]}`);
}
console.log(`\n10.12.4.7 -> ${ayristir("10.12.4.7")}, 10.0.0.0/8 tabani ${blok("10.0.0.0/8")[0]}, ` +
  `maske ${blok("10.0.0.0/8")[1] >>> 0}`);
```

```
12 giden istek hedefi, 7 ozel adres blogu
bildirilen dis konak: 3, kullanici verisinden gelen hedef: 10

kisit bicimi                        gecen  ic aga ulasan  duran bildirilen
kisit yok                              12              8                 0
ad temelli ret listesi                  7              3                 0
adres temelli ret listesi               4              0                 0
izin listesi (bildirilen konak)         3              0                 0

ozel bloga dusen hedefler:
  gecis.dis-3.ornek    -> 3232243205 blok 192.168.0.0/16
  rapor.ic             ->  168559623 blok 10.0.0.0/8
  olcum-depo.ic        ->  168559636 blok 10.0.0.0/8
  yerel.ic             -> 2130706433 blok 127.0.0.0/8
  kenar.ic             -> 2851998213 blok 169.254.0.0/16
  sayac.ic             -> 2886993923 blok 172.16.0.0/12
  10.12.4.9            ->  168559625 blok 10.0.0.0/8
  127.0.0.1            -> 2130706433 blok 127.0.0.0/8

10.12.4.7 -> 168559623, 10.0.0.0/8 tabani 167772160, maske 4278190080
```

Kısıt yokken on iki hedefin sekizi iç ağa ulaşıyor. Ad temelli ret listesi bu sayıyı üçe
indiriyor ve **üç hedefi hâlâ geçiriyor** — çünkü ada bakıyor, adrese bakmıyor. Geçenlerin
biri dış görünümlü bir ad taşıyor ve bir iç adrese çözülüyor; ikisi zaten sayı olarak
yazılmış iç adreslerdir ve adları `.ic` ile bitmediği için ret listesine takılmıyor.

Adres temelli ret listesi iç ağa ulaşan hedefi sıfırlıyor. Alt liste bunun nasıl olduğunu
gösteriyor: her hedef otuz iki bitlik bir sayıya çevriliyor ve yedi bloktan hangisine
düştüğü hesaplanıyor. Sekiz hedefin sekizi bir bloğa düşüyor ve hiçbiri ada bakılarak
bulunmuyor.

İzin listesi de sıfır veriyor, ama farklı bir yolla: dokuz kullanıcı hedefinin dokuzunu birden
reddediyor. İki kısıtın kapsaması aynı, kapsama biçimi değil. Ret listesi listelenmemiş bir
blok çıktığında açık kalır; izin listesi meşru yeni bir dış konak eklendiğinde onu da durdurur.
Her ikisinin de bedeli bu tabloda sıfır görünüyor, çünkü bildirilen üç konak ikisinden de
geçiyor.

## Kısıtın Uygulandığı Nokta

Kısıtın hangi değere uygulandığı kadar **ne zaman** uygulandığı da kapsamayı belirler. İki
durum bunu ayırır: istek bir yeniden yönlendirme zinciri izliyorsa ve ad çözümlemesi denetimle
bağlanma arasında tekrarlanıyorsa.

**GC14 (varsayım):** zincirler ve ikinci çözümleme modeldir. Ölçülen şey bir olayın olma
olasılığı değil, **kısıtın o adımı görüp görmediğidir**.

```js
// zincir.mjs — kisitin uygulandigi nokta: ilk adim, her adim, ve cozumlemenin tekrari
import { HEDEF, COZUM, coz, ozelMi, ayristir } from "./adres.mjs";

// Yeniden yonlendirme zincirleri (kurgu): istegin izledigi adim dizisi.
const ZINCIR = [
  ["belge.dis-1.ornek", ["belge.dis-1.ornek"]],
  ["karo.dis-2.ornek", ["karo.dis-2.ornek", "203.0.113.60"]],
  ["arsiv.dis-1.ornek", ["arsiv.dis-1.ornek", "arsiv-2.dis-1.ornek", "10.12.4.20"]],
  ["gecis.dis-3.ornek", ["gecis.dis-3.ornek"]],
  ["belge.dis-1.ornek", ["belge.dis-1.ornek", "127.0.0.1"]],
];
const adim = ZINCIR.reduce((t, [, z]) => t + z.length, 0);
console.log(`${ZINCIR.length} yeniden yonlendirme zinciri, ${adim} adim\n`);
console.log(`${"kisitin uygulandigi nokta".padEnd(28)}${"tamamlanan".padStart(12)}${"ic adrese varan".padStart(17)}`);
for (const [ad, secim] of [["yalniz ilk adim", (z) => [z[0]]], ["her adim", (z) => z]]) {
  const tamam = ZINCIR.filter(([, z]) => secim(z).every((h) => !ozelMi(coz(h))));
  const ic = tamam.filter(([, z]) => ozelMi(coz(z[z.length - 1]))).length;
  console.log(ad.padEnd(28) + String(tamam.length).padStart(12) + String(ic).padStart(17));
}

// Cozumlemenin tekrari: denetim anindaki adres ile baglanma anindaki adres ayri olabilir.
const IKINCI = { ...COZUM, "belge.dis-1.ornek": "10.12.4.31" };
const cozIkinci = (ad) => ayristir(IKINCI[ad] ?? ad);
const gecen = HEDEF.filter(([h]) => !ozelMi(coz(h)));
console.log(`\nadres temelli kisiti gecen hedef: ${gecen.length}`);
console.log(`${"baglanma bicimi".padEnd(34)}${"ic adrese varan".padStart(17)}`);
console.log("denetim ve baglanti ayri cozumleme".padEnd(34) +
  String(gecen.filter(([h]) => ozelMi(cozIkinci(h))).length).padStart(17));
console.log("tek cozumleme, denetlenen adrese".padEnd(34) +
  String(gecen.filter(([h]) => ozelMi(coz(h))).length).padStart(17));
```

```
5 yeniden yonlendirme zinciri, 9 adim

kisitin uygulandigi nokta     tamamlanan  ic adrese varan
yalniz ilk adim                        4                2
her adim                               2                0

adres temelli kisiti gecen hedef: 4
baglanma bicimi                     ic adrese varan
denetim ve baglanti ayri cozumleme                1
tek cozumleme, denetlenen adrese                  0
```

Üst tablo kısıtın yerini ölçüyor. Aynı kısıt yalnız ilk adıma uygulandığında dört zincir
tamamlanıyor ve ikisi bir iç adreste bitiyor; her adıma uygulandığında iki zincir tamamlanıyor
ve hiçbiri iç adrese varmıyor. Kısıt aynı kısıttır — değişen tek şey dokuz adımın kaçının
görüldüğüdür. **Bir isteğin hedefi tek bir değer değil, bir dizidir.**

Alt tablo ikinci noktayı veriyor. Kısıtı geçen dört hedeften biri, bağlanma anında yeniden
çözüldüğünde bir iç adrese düşüyor. Denetim doğru çalışmıştı; denetlenen değer artık
bağlanılan değer değil. İkinci satır çözümü gösteriyor: çözümleme bir kez yapılır, kısıt o
adrese uygulanır ve bağlantı **ada değil, denetlenen adrese** kurulur. O zaman iç adrese
varan hedef sıfırdır.

İki satırın ortak dersi kapsamanın tanımıyla ilgilidir. Bir kısıt, uygulandığı değer ile
kullanılan değer aynı olduğu sürece kapsar; ikisi ayrıldığı anda kısıt geçerli kalır ama
kapsaması yoktur. Yeni bir giden istek noktası eklendiğinde sorulacak soru budur: bu nokta
kısıtı hangi değere ve hangi adıma uyguluyor.

## Giden İstek Noktası Envanteri

Kısıtın hangi değere ve hangi adıma uygulandığı ölçüldü. Kalan soru kaç noktada uygulandığı.
Bölgesel ölçüm ağında sekiz giden istek noktası var ve yarısı merkezî bir giden istek
istemcisinden geçiyor.

```js
// nokta.mjs — giden istek noktasi envanteri ve merkezi giden istek istemcisinin kapsamasi
import { coz, ozelMi } from "./adres.mjs";

// [servis, nokta, hedefler, hedef kaynagi, istemci]
const NOKTA = [
  ["rapor", "belgeCek", ["belge.dis-1.ornek", "arsiv.dis-1.ornek"], "kullanici", "merkezi"],
  ["rapor", "arsivCek", ["arsiv.dis-1.ornek", "10.12.4.9"], "kullanici", "dogrudan"],
  ["saha", "karoCek", ["karo.dis-2.ornek"], "bildirilen", "merkezi"],
  ["saha", "onizleme", ["gecis.dis-3.ornek", "yerel.ic"], "kullanici", "dogrudan"],
  ["abone portali", "logoCek", ["belge.dis-1.ornek", "kenar.ic"], "kullanici", "dogrudan"],
  ["fatura", "kurCek", ["karo.dis-2.ornek"], "bildirilen", "merkezi"],
  ["bildirim", "webKanci", ["203.0.113.99", "rapor.ic"], "kullanici", "dogrudan"],
  ["olcum", "toplayiciCek", ["sayac.ic"], "bildirilen", "merkezi"],
];
const hedefSayisi = NOKTA.reduce((t, n) => t + n[2].length, 0);

// Bir kurulumda bir hedefin gecip gecmedigi: kisit ya hic uygulanmiyor ya adrese uygulaniyor.
const gecer = (n, h, kurulum) => {
  const kisitli = kurulum === "hepsi" || (kurulum === "istisna" ? n[3] === "kullanici" : n[4] === "merkezi");
  return kisitli ? !ozelMi(coz(h)) : true;
};

console.log(`${NOKTA.length} giden istek noktasi, ${hedefSayisi} hedef, ` +
  `${NOKTA.filter((n) => n[4] === "merkezi").length} nokta merkezi istemciden geciyor\n`);
console.log(`${"kurulum".padEnd(32)}${"gecen hedef".padStart(12)}${"ic aga ulasan".padStart(15)}${"duran mesru ic cagri".padStart(22)}`);
for (const [adi, kurulum] of [["mevcut: dogrudan cagrilar var", "mevcut"],
    ["tumu merkezi istemciden", "hepsi"], ["merkezi + bildirilen ic cagri", "istisna"]]) {
  let gecen = 0, ic = 0, duran = 0;
  for (const n of NOKTA) for (const h of n[2]) {
    const g = gecer(n, h, kurulum);
    if (g) { gecen++; if (ozelMi(coz(h))) ic++; }
    else if (n[3] === "bildirilen" && ozelMi(coz(h))) duran++;
  }
  console.log(adi.padEnd(32) + String(gecen).padStart(12) + String(ic).padStart(15) + String(duran).padStart(22));
}
console.log(`\nyeni giden istek noktasi eklendiginde: merkezi istemcide yazilacak kisit 0, ` +
  `dogrudan cagrida ${1} kisit`);
```

```
8 giden istek noktasi, 13 hedef, 4 nokta merkezi istemciden geciyor

kurulum                          gecen hedef  ic aga ulasan  duran mesru ic cagri
mevcut: dogrudan cagrilar var             12              5                     1
tumu merkezi istemciden                    7              0                     1
merkezi + bildirilen ic cagri              8              1                     0

yeni giden istek noktasi eklendiginde: merkezi istemcide yazilacak kisit 0, dogrudan cagrida 1 kisit
```

İlk satır mevcut durumu veriyor: on üç hedefin beşi iç ağa ulaşıyor ve beşinin de geldiği yer
merkezî istemciden geçmeyen dört doğrudan çağrıdır. Kısıt kod tabanında vardır ve doğru
yazılmıştır; **yalnız dört noktada çağrılıyor.**

İkinci satır bütün noktaların merkezî istemciye alınmasını gösteriyor. İç ağa ulaşan sıfıra
iniyor, ama son sütun bir kalıyor: ölçüm toplayıcıya yapılan çağrı meşru bir iç çağrıdır ve
kısıt onu da durduruyor. Hedefi kullanıcı verisinden gelmeyen bir nokta için kısıt yanlış
yerdedir.

Üçüncü satır düzeltmeyi ölçüyor: kısıt yalnız hedefi kullanıcı verisinden gelen noktalara
uygulanınca duran meşru çağrı sıfırlanıyor ve iç ağa ulaşan bire çıkıyor — o bir, bildirilmiş
iç servis çağrısıdır. **Kapsamanın ölçüsü iç ağa ulaşan hedef sayısı değil, kullanıcı
verisinden gelip iç ağa ulaşan hedef sayısıdır**; bu ayrım yazılmazsa kısıt ya meşru işi
durdurur ya da kaldırılır.

## Özet

- Giden istek hedeflerinin iç ağa ulaşıp ulaşmadığı ad üzerinden değil, otuz iki bitlik
  adres ve maske aritmetiğiyle belirlenir. Yedi özel blok, sekiz hedefi yakaladı.
- On iki hedefin 8'i kısıt yokken iç ağa ulaşıyor. Ad temelli ret listesi bunu 3'e indiriyor
  ve geçirdiği üçün biri dış görünümlü bir addır, ikisi sayıyla yazılmış iç adrestir. Adres
  temelli ret listesi ve izin listesi 0 veriyor.
- İki sıfır aynı değildir: ret listesi listelenmemiş bir blok çıktığında açık kalır, izin
  listesi 9 kullanıcı hedefinin 9'unu birden reddeder ve yeni meşru dış konağı da durdurur.
- Kısıt yalnız ilk adıma uygulandığında 5 zincirin 4'ü tamamlandı ve 2'si iç adreste bitti;
  her adıma uygulandığında 2 zincir tamamlandı ve iç adrese varan 0 oldu. Bir isteğin hedefi
  tek değer değil, dizidir.
- Sekiz giden istek noktasının 4'ü merkezî istemciden geçiyor; kalan dördü yüzünden 13 hedefin
  5'i iç ağa ulaşıyor. Hepsi merkezî istemciye alındığında bu 0 oluyor ama 1 meşru iç çağrı
  duruyor; kısıt yalnız kullanıcı kaynaklı hedeflere uygulandığında duran meşru çağrı 0.
- Denetimle bağlanma arasında ad yeniden çözüldüğünde kısıtı geçen 4 hedeften 1'i iç adrese
  düştü. Tek çözümleme yapılıp denetlenen adrese bağlanıldığında bu sayı 0. Kısıt, uygulandığı
  değer ile kullanılan değer ayrıldığı anda kapsamasını yitirir.

## Sonraki Adım

Buraya kadarki altı ders dışarıdan gelen verinin sınırını çizdi ve her sınırda kapsamayı
saydı: giriş noktası, çıkış bağlamı, sorgu yeri, şablon gövdesi, yükleme katmanı ve giden
istek hedefi. Hepsinin ortak varsayımı, gelen şeyin bir **değer** olmasıydı — bir metin, bir
sayı, bir bayt dizisi. Kimi akışlarda gelen şey değer değil, bir nesne tanımıdır: alanları,
türü ve kurulma biçimi verinin içinde yazar. Sonraki ders seri durumdan çıkarmayı güvenilir
tür kümesi cinsinden ölçer ve konuyu kapatır: kaç tür kabul ediliyor, izin listesi kaçını
kapatıyor ve veri biçimi seçmek kaç noktayı ortadan kaldırıyor.
