Ders 01 / 15
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.
İçindekiler
Ö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ı.
// 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.
// 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ı.
// 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.
// 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.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.