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