---
title: 'Web Uygulaması Güvenlik Duvarı'
source: 'https://academia.sh/tr/kurslar/calisma-zamani-guvenligi/web-uygulamasi-guvenlik-duvari'
course: 'Çalışma Zamanı Güvenliği ve Sır Yönetimi'
language: tr
updated: '2026-08-17T18:06:41+00:00'
license: 'CC BY-SA 4.0'
---

# Web Uygulaması Güvenlik Duvarı

Hazır bir kural kümesinin kurgu bir günlük istek kümesinde koşturulması ve üç sayının ayrı ayrı yazılması: durdurulan kötü istek, kaçan kötü istek ve yanlış yere kesilen meşru istek; puan eşiği düşürüldüğünde üçünün nasıl birlikte hareket ettiği, muafiyet yazmanın aynı üç sayıyı hangi bedelle geri getirdiği ve durdurulan hacmin ne kadarının daha ucuz bir aşamada kapatılabileceği.

Önceki kurs kodu taradı, bileşenleri envanterledi ve yapı çıktısını imzaladı; bütün o denetimler
dağıtımdan önce durdu. Uygulama çalışmaya başladığı andan itibaren onu neyin koruduğu ise hiç
sorulmadı. Bu konu o soruyu istek katmanında yanıtlıyor ve ilk ders ölçünün kendisini kuruyor.

Çalışma zamanı, bir kalemi yakalamanın en pahalı olduğu aşamadır: kalem üretimdedir, isteği
gerçek bir abone göndermektedir ve savunma karar vermek için milisaniyeye sahiptir. Bu yüzden
"uygulama katmanı güvenlik duvarı konmalıdır" cümlesi tek başına karar taşımaz. Karar taşıyan
şey üç sayıdır ve üçü **aynı koşumdan** okunmalıdır: kaç kötü istek durduruldu, kaç kötü istek
geçti, kaç meşru istek yanlış yere kesildi. Üçüncüsü yazılmadığında ilk ikisi bir şey ölçmez.

## Kural Kümesi Neye Bakıyor

Bölgesel ölçüm ağının abone portalı ile saha uygulaması aynı üretim ortamında duruyor. Önlerine
bir uygulama katmanı güvenlik duvarı konuyor ve hazır bir kural kümesiyle başlatılıyor: her kural
istekte belirli bir **belirtiyi** arar, eşleştiğinde bir puan yazar, isteğin toplam puanı eşiği
aşarsa istek durdurulur. Aşağıdaki her şey `node` ile kurulan bir modeldir; gerçek trafik
üretilmiyor, gerçek bir yük ya da atlatma dizgesi yazılmıyor.

- **US1.** On bir istek sınıfı, günlük sayıları, beş uç ve on kural kurgusal ölçüm ağına aittir.
- **US2.** Bir isteğin gerçek sınıfı (meşru ya da kötü) modelde bilinir. Üretimde bu sınıf ancak
  inceleme sonrası bilinir; modelde bilindiği varsayılıyor ki yanlış kesilen istek sayılabilsin.
- **US3.** Bir sınıfın taşıdığı belirti kümesi sabittir; aynı sınıftaki her istek aynı puanı alır.
  Gerçekte puan istek başına dağılır, bu dağılım eşik seçimini yumuşatır, yönünü değiştirmez.
- **US4.** Bir kural, aradığı etiketlerin **hepsi** varsa eşleşir. Belirti etiketleri bir söz
  dizimini değil, savunmanın gördüğü yüzeysel bir özelliği adlandırır.
- **US5.** "Daha erken kapatma aşaması" sütunu her kötü sınıf için elle işaretlendi: kalem
  tasarımda mı, kodda mı kapatılabilirdi, yoksa hiçbir erken aşamada kapatılamaz mı.

```js
// istek.mjs — bir gunluk istek kumesi ve hazir kural kumesi; model, gercek trafik degil
// [ad, gercek sinif, gunluk sayi, belirti etiketleri, uc, daha erken kapatma asamasi]
export const SINIF = [
  ['abone sorgu formu', 'mesru', 84000, [], '/portal/sorgu', '-'],
  ['saha uygulamasi toplu yukleme', 'mesru', 5400, ['uzun-govde', 'kodlanmis-alan'], '/saha/yukleme', '-'],
  ['rapor filtresi, serbest metin', 'mesru', 2600, ['tirnak', 'anahtar-sozcuk'], '/portal/rapor', '-'],
  ['fatura ekinde dosya adi', 'mesru', 900, ['yol-ayraci'], '/portal/fatura', '-'],
  ['ic izleme yoklamasi', 'mesru', 1440, ['arac-imzasi'], '/saglik', '-'],
  ['sorgu alaninda birlestirme', 'kotu', 320, ['tirnak', 'anahtar-sozcuk', 'yorum-imi'], '/portal/sorgu', 'kod'],
  ['form alaninda betik etiketi', 'kotu', 210, ['etiket-acilisi', 'olay-niteligi'], '/portal/sorgu', 'kod'],
  ['ek adinda dizin yukselme', 'kotu', 96, ['yol-ayraci', 'ust-dizin'], '/portal/fatura', 'kod'],
  ['ortu altinda tirnak dizisi', 'kotu', 260, ['tirnak', 'anahtar-sozcuk'], '/portal/rapor', 'kod'],
  ['bilesende yamasi cikmamis acik', 'kotu', 40, ['bicimsiz-govde'], '/saha/yukleme', 'yok'],
  ['is akisi disi toplu indirme', 'kotu', 1200, [], '/portal/rapor', 'tasarim'],
];

// [kural adi, aranan etiketler (hepsi bulunmali), puan]
export const KURAL = [
  ['tirnak ve anahtar sozcuk', ['tirnak', 'anahtar-sozcuk'], 3],
  ['yorum imi', ['yorum-imi'], 2],
  ['etiket acilisi', ['etiket-acilisi'], 3],
  ['olay niteligi', ['olay-niteligi'], 2],
  ['yol ayraci', ['yol-ayraci'], 2],
  ['ust dizin', ['ust-dizin'], 3],
  ['bicimsiz govde', ['bicimsiz-govde'], 4],
  ['bilinen arac imzasi', ['arac-imzasi'], 2],
  ['kodlanmis alan', ['kodlanmis-alan'], 2],
  ['uzun govde', ['uzun-govde'], 1],
];

// muaf = [uc, kural adi] ciftleri; o ucta o kural hic puan yazmaz
export const puan = (s, muaf = []) => KURAL.reduce((t, [ad, ara, p]) =>
  t + (ara.every((e) => s[3].includes(e)) && !muaf.some(([u, k]) => u === s[4] && k === ad) ? p : 0), 0);

export function olc(esik, muaf = []) {
  let yakalanan = 0, kacan = 0, yanlis = 0;
  for (const s of SINIF) {
    const durdu = puan(s, muaf) >= esik;
    if (s[1] === 'kotu') durdu ? (yakalanan += s[2]) : (kacan += s[2]);
    else if (durdu) yanlis += s[2];
  }
  return { yakalanan, kacan, yanlis };
}
```

Kural kümesinin hazır gelmesi, kuralların bu uygulamayı tanımadığı anlamına gelir. Kurallar söz
dizimi düzeyinde bir yüzeye bakar ve o yüzey meşru işin de geçtiği bir yüzeydir: rapor filtresine
serbest metin yazan bir abone ile sorgu alanına birleştirme deneyen bir istek aynı iki belirtiyi
taşıyabilir. Ayrımı kural yapamaz, çünkü ayrım isteğin biçiminde değil **niyetinde ve
bağlamındadır**; kuralın gördüğü tek şey biçimdir.

## Üç Sayı Birlikte Hareket Eder

Eşik, kural kümesinin tek gerçek ayarıdır. Aşağıdaki koşumda kural kümesi, istek kümesi ve
puanlar sabit kalıyor; değişen tek şey eşiktir.

```js
// kosum.mjs — ayni gunluk kume, degisen tek sey esik
import { SINIF, KURAL, puan, olc } from './istek.mjs';

const s = (x, n) => String(x).padStart(n);
const kotu = SINIF.filter((k) => k[1] === 'kotu');
const T = (l) => l.reduce((t, k) => t + k[2], 0);
console.log(`${SINIF.length} istek sinifi, ${KURAL.length} kural; gunde ${T(SINIF)} istek` +
  ` (${T(kotu)} kotu / ${T(SINIF) - T(kotu)} mesru)\n`);
console.log(`${'istek sinifi'.padEnd(31)}${s('sinif', 6)}${s('gunluk', 7)}${s('puan', 5)}` +
  `${s('uc', 15)}${s('erken asama', 13)}`);
for (const k of SINIF)
  console.log(`${k[0].padEnd(31)}${s(k[1], 6)}${s(k[2], 7)}${s(puan(k), 5)}${s(k[4], 15)}${s(k[5], 13)}`);

console.log(`\n${'esik'.padEnd(6)}${s('yakalanan', 11)}${s('kacan', 8)}${s('yanlis kesilen', 16)}` +
  `${s('kesilen/yakalanan', 19)}`);
for (const e of [6, 5, 4, 3, 2]) {
  const r = olc(e);
  console.log(`${String(e).padEnd(6)}${s(r.yakalanan, 11)}${s(r.kacan, 8)}${s(r.yanlis, 16)}` +
    `${s(r.yakalanan ? (r.yanlis / r.yakalanan).toFixed(1) : '-', 19)}`);
}
```

```
11 istek sinifi, 10 kural; gunde 96466 istek (2126 kotu / 94340 mesru)

istek sinifi                    sinif gunluk puan             uc  erken asama
abone sorgu formu               mesru  84000    0  /portal/sorgu            -
saha uygulamasi toplu yukleme   mesru   5400    3  /saha/yukleme            -
rapor filtresi, serbest metin   mesru   2600    3  /portal/rapor            -
fatura ekinde dosya adi         mesru    900    2 /portal/fatura            -
ic izleme yoklamasi             mesru   1440    2        /saglik            -
sorgu alaninda birlestirme       kotu    320    5  /portal/sorgu          kod
form alaninda betik etiketi      kotu    210    5  /portal/sorgu          kod
ek adinda dizin yukselme         kotu     96    5 /portal/fatura          kod
ortu altinda tirnak dizisi       kotu    260    3  /portal/rapor          kod
bilesende yamasi cikmamis acik   kotu     40    4  /saha/yukleme          yok
is akisi disi toplu indirme      kotu   1200    0  /portal/rapor      tasarim

esik    yakalanan   kacan  yanlis kesilen  kesilen/yakalanan
6               0    2126               0                  -
5             626    1500               0                0.0
4             666    1460               0                0.0
3             926    1200            8000                8.6
2             926    1200           10340               11.2
```

Beş satır bir ayar eğrisidir ve her satırı ayrı okumak gerekir. Eşik altıda kural kümesi hiçbir
şey durdurmuyor: hiçbir sınıfın toplam puanı altıya ulaşmıyor, yani kurulmuş ama etkisiz bir
katman gündelik ölçümde sıfırdan ayırt edilemez. Eşik beşte üç sınıf durur ve altı yüz yirmi
altı kötü istek kesilir; yanlış kesilen istek sıfırdır. Eşik dörde inince yalnız kırk istek daha
eklenir ve yanlış kesilen yine sıfır kalır — dört, bu kümedeki karşılıksız ayardır.

Asıl karar üçüncü satırdadır. Eşiği üçe indirmek iki yüz altmış kötü isteği daha durdurur ve
karşılığında **sekiz bin meşru isteği** keser. Oran son sütunda yazılı: durdurulan her kötü
istek başına 8,6 kesilen meşru istek. Kesilenler de rastgele değildir; saha uygulamasının toplu
yüklemesi ile rapor filtresine yazılan serbest metindir, yani sistemin iki gerçek işlevi. Eşik
ikide ise durdurulan kötü istek hiç artmaz, kesilen istek iki bin üç yüz kırk artar: sıkılaştırma
belirli bir noktadan sonra yalnızca meşru işi kesmeye başlar.

Kaçan sütunu bütün ayarlarda bin ikiden aşağı inmiyor. Bunun nedeni bir eşik seçimi değil, bir
**görme sınırıdır**: iş akışı dışı toplu indirme hiçbir belirti taşımıyor. İstekler biçim olarak
kusursuzdur, kimliği doğrulanmıştır, yetkisi vardır; yanlış olan tek şey hacim ve bağlamdır.
Söz dizimine bakan bir kural kümesi bunu hiçbir eşikte göremez.

## Muafiyet Yazmanın Bedeli

Eşiği üçte tutup yanlış kesmeyi ayrı ayrı kapatmak, üretimde en sık verilen yanıttır: kesilen
uç ile onu kesen kural bir muafiyet listesine yazılır ve o uçta o kural puan yazmaz. Üç muafiyet
yeterlidir — saha yükleme ucundaki iki kural ile rapor ucundaki tırnak kuralı.

```js
// muafiyet.mjs — esik 3'te yanlis kesmeyi muafiyetle kapatmanin bedeli
import { SINIF, puan, olc } from './istek.mjs';

const s = (x, n) => String(x).padStart(n);
const MUAF = [['/saha/yukleme', 'uzun govde'], ['/saha/yukleme', 'kodlanmis alan'],
  ['/portal/rapor', 'tirnak ve anahtar sozcuk']];

const AYAR = [['esik 4, muafiyet yok', 4, []], ['esik 3, muafiyet yok', 3, []],
  ['esik 3, 3 muafiyet', 3, MUAF]];
console.log(`${'ayar'.padEnd(22)}${s('yakalanan', 11)}${s('kacan', 8)}${s('yanlis kesilen', 16)}${s('bakilan kalem', 15)}`);
for (const [ad, e, m] of AYAR) {
  const r = olc(e, m);
  console.log(`${ad.padEnd(22)}${s(r.yakalanan, 11)}${s(r.kacan, 8)}${s(r.yanlis, 16)}${s(10 + m.length, 15)}`);
}

console.log(`\nmuafiyetin ucta actigi alan:`);
for (const [u, k] of MUAF) {
  const gecen = SINIF.filter((x) => x[4] === u && x[1] === 'kotu' && puan(x) >= 3 && puan(x, MUAF) < 3);
  console.log(`  ${u.padEnd(15)}${k.padEnd(26)}${gecen.length ? `gecen kotu: ${gecen[0][0]} (${gecen[0][2]})` : 'gecen kotu yok'}`);
}
```

```
ayar                    yakalanan   kacan  yanlis kesilen  bakilan kalem
esik 4, muafiyet yok          666    1460               0             10
esik 3, muafiyet yok          926    1200            8000             10
esik 3, 3 muafiyet            666    1460               0             13

muafiyetin ucta actigi alan:
  /saha/yukleme  uzun govde                gecen kotu yok
  /saha/yukleme  kodlanmis alan            gecen kotu yok
  /portal/rapor  tirnak ve anahtar sozcuk  gecen kotu: ortu altinda tirnak dizisi (260)
```

Birinci ve üçüncü satır üç sayının üçünde de aynıdır: 666, 1.460, 0. Yani üç muafiyetle
sıkılaştırılmış eşik, hiç muafiyet yazılmamış gevşek eşikle tam olarak aynı sonucu veriyor.
Fark yalnız son sütundadır — bakılan kalem sayısı ondan on üçe çıkmıştır. Üç kalem daha, üç ayrı
gerekçe, her uç değişikliğinde yeniden gözden geçirilecek üç satır.

Alt liste bunun nedenini veriyor. Muafiyet bir kuralı bir uçta kapatır ve o uçtan geçen **her
isteği** kapsar. Rapor ucundaki tırnak muafiyeti meşru filtre metnini kurtarırken aynı uçtan
geçen iki yüz altmış kötü isteği de birlikte kurtardı: üç puanlık kural o uçta artık hiç
yazmıyor. Saha yükleme ucundaki iki muafiyet bu yan etkiyi üretmedi, çünkü o uçtaki tek kötü
sınıf başka bir kuralla yakalanıyor. İkisi arasındaki fark önceden bilinmez; ancak muafiyetin
kapsadığı istek kümesi sayıldığında görülür. Muafiyet listesi bu yüzden bir ayar değil, bir
envanterdir: her satırın hangi uçta hangi kuralı susturduğu ve o uçtan başka nelerin geçtiği
ayrıca izlenmediği sürece liste zamanla kural kümesinin kendisinden daha belirleyici olur.

## Durdurulanın Nereye Ait Olduğu

İlk iki sütun bu katmanın ne yaptığını söylüyor. Üçüncü sütun kursun asıl sorusudur: durdurulan
hacim, daha ucuz bir aşamada zaten kapatılabilir miydi.

```js
// asama.mjs — durdurulan kalemin kaci daha ucuz bir asamada kapatilabilirdi
import { SINIF, puan } from './istek.mjs';

const s = (x, n) => String(x).padStart(n);
const kotu = SINIF.filter((k) => k[1] === 'kotu');
const ASAMA = ['kod', 'tasarim', 'yok'];

console.log(`${'esik'.padEnd(6)}${ASAMA.map((a) => s(a, 10)).join('')}${s('yalniz burada %', 17)}`);
for (const e of [5, 4, 3]) {
  const d = kotu.filter((k) => puan(k) >= e);
  const t = d.reduce((x, k) => x + k[2], 0);
  const pay = ASAMA.map((a) => d.filter((k) => k[5] === a).reduce((x, k) => x + k[2], 0));
  console.log(`${String(e).padEnd(6)}${pay.map((p) => s(p, 10)).join('')}` +
    `${s(t ? (100 * pay[2] / t).toFixed(1) : '-', 17)}`);
}

console.log(`\nhicbir esikte durdurulmayan kotu sinif:`);
for (const k of kotu.filter((x) => puan(x) < 2))
  console.log(`  ${k[0].padEnd(31)}${s(k[2], 7)}  belirti yok, erken asama: ${k[5]}`);
console.log(`\nyalniz calisma zamaninda kapatilabilen sinif:`);
for (const k of kotu.filter((x) => x[5] === 'yok'))
  console.log(`  ${k[0].padEnd(31)}${s(k[2], 7)}  puan ${puan(k)}, esik 4'te durur`);
```

```
esik         kod   tasarim       yok  yalniz burada %
5            626         0         0              0.0
4            626         0        40              6.0
3            886         0        40              4.3

hicbir esikte durdurulmayan kotu sinif:
  is akisi disi toplu indirme       1200  belirti yok, erken asama: tasarim

yalniz calisma zamaninda kapatilabilen sinif:
  bilesende yamasi cikmamis acik      40  puan 4, esik 4'te durur
```

Tablo katmanın gerçek payını gösteriyor. Eşik dörtte durdurulan altı yüz altmış altı isteğin
altı yüz yirmi altısı — yüzde doksan dördü — kod aşamasında kapatılabilir sınıflardan geliyor:
sorgu birleştirme parametreli sorguyla, betik etiketi çıktı kodlamasıyla, dizin yükselme yol
doğrulamasıyla kapanır ve bunların üçü de bir defa yazılıp bütün istekler için geçerli olur.
Bu katman aynı kalemleri her gün, her istekte yeniden yakalıyor.

Yüzde altı ise başka bir şey. Bileşende yaması çıkmamış bir açık için erken aşama yoktur:
kalem ne tasarımda vardı ne kodda yazıldı, bağımlılık envanterinde göründüğü an da bir düzeltme
sürümü mevcut değildi. O kırk isteği durduran tek şey bu katmandır ve kural kümesinin varlık
nedeni tam olarak budur. Katmanın ölçüsü toplam durdurma sayısı değil, **yalnız burada
durdurulabilen** sayıdır.

Alt liste ise ters yönü söylüyor. İş akışı dışı toplu indirme hiçbir eşikte durmuyor; bu kalem
ne kurallarla ne eşikle yakalanır, çünkü yetkilendirme ve iş akışı kararıdır, yani tasarım
aşamasına aittir. Kural kümesi bu kalemi hiç görmediği hâlde günlük gösterge tablosunda altı yüz
altmış altı durdurma yazacaktır. Katmanın kurulu olması, kapsadığı kalem sınıfını genişletmez.

## Özet

- Bir çalışma zamanı savunması üç sayıyla ölçülür ve üçü aynı koşumdan okunur: durdurulan kötü
  istek, kaçan kötü istek, yanlış yere kesilen meşru istek. Üçüncüsü yazılmadığında ilk ikisi
  bir şey ölçmez.
- Eşik 5'ten 4'e inince durdurulan istek 626'dan 666'ya çıktı ve yanlış kesilen sıfır kaldı;
  3'e inmek 260 istek daha durdurup 8.000 meşru isteği kesti (yakalanan başına 8,6 kesilen),
  2'ye inmek hiçbir kazanç eklemeden 2.340 kesme daha ekledi.
- Eşik 3 ile üç muafiyet, eşik 4 ile hiç muafiyetin verdiği üç sayının aynısını verdi (666,
  1.460, 0); tek fark bakılan kalemin 10'dan 13'e çıkmasıdır. Muafiyetlerden biri aynı uçtan
  geçen 260 kötü isteği de kapsadı.
- Kaçan istek hiçbir eşikte 1.200'ün altına inmedi: iş akışı dışı toplu indirme hiçbir belirti
  taşımıyor. Söz dizimine bakan kural biçimi görür, bağlamı görmez.
- Eşik 4'te durdurulan 666 isteğin 626'sı kod aşamasında bir kez kapatılabilecek sınıflardan
  geliyor. Yalnız çalışma zamanında kapatılabilen pay günde 40 istek, yani yüzde 6'dır — yaması
  çıkmamış bileşen açığı.

## Sonraki Adım

Bu dersin kural kümesi tek bir isteğe bakıp karar verdi: belirti var mı, puan eşiği aşıyor mu.
Kaçan bin iki yüz istek ise tam olarak bu yüzden kaçtı — hiçbiri tek başına yanlış değildi.
İş akışı dışı toplu indirmenin yanlışlığı isteğin içinde değil, **aynı istemciden gelen istek
sayısında ve zamanlamasındadır**. Bunu görmek için savunmanın bir isteği değil bir sayacı
okuması gerekir: pencere başına kaç istek, hangi anahtara bağlı, hangi eşikle. Sonraki ders o
sayacı üç ayrı pencere biçiminde koşturuyor ve aynı üç sayıyı orada soruyor — özellikle
ikincisini, çünkü hız sınırının en pahalı yanı durdurduğu kötü istek değil, meşru tepe yükünden
kestiği istektir.
