---
title: 'Girdi Doğrulama ve Kodlama'
source: 'https://academia.sh/tr/kurslar/backend-uretim/girdi-dogrulama-ve-kodlama'
course: 'Sunucu Güvenliği ve Üretime Alma'
language: tr
updated: '2026-08-17T18:06:49+00:00'
license: 'CC BY-SA 4.0'
---

# Girdi Doğrulama ve Kodlama

Güvenilmeyen veri sınırının gerçekleştirilmesi: yirmi iki isteklik bir kümede izin listesiyle engelleme listesinin yanlış geçme ve yanlış kalma sayıları, doğrulamanın uçta, serviste ve depoda durmasının yan etki maliyeti, tek kodlayıcının üç çıktı bağlamında bozduğu değer sayısı ve tek satırlık bir ayarın sessizce açtığı alan.

Gözlemlenebilirlik kursu ödünç sistemini görünür kıldı, dayanıklılık kursu arızaya
dayanmasını sağladı. İki kurs boyunca sisteme giden her istek geçerliydi: yük üreteci
sözleşmeye uyan gövdeler gönderdi, kaos denemeleri isteği değil altyapıyı bozdu. Sözleşmeye
**uymayan** bir isteğin sistem içinde nereye kadar gidebildiği hiç ölçülmedi.

Bu dersin konusu o sınırdır. Bölünmüş ödünç sisteminin üç dış ucu var; bu uçlara gelen her
gövde, aksi kanıtlanana kadar **güvenilmeyen veridir**. Açıkların kendisi anlatılmaz —
istemci tarafı Frontend Kalitesi, tarama tarafı Kalite ve Test kursunda kuruldu — burada
**savunmanın gerçekleştirimi** ölçülür.

## Güvenilmeyen Veri Sınırı

Sözleşme önce yazılır: hangi uç, hangi alanı, hangi biçimde kabul ediyor. Her isteğin kabul
mü ret mi olacağı ödünç sisteminin kurallarından gelir ve elle etiketlenir.

**BG1 (varsayım):** etiketler eksiksiz ve doğrudur. Ölçülen sayılar bu etiket kümesine
görelidir ve kümede olmayan bir istek biçimi hakkında bir şey söylemez.

```js
// istekler.mjs — odunc sisteminin uc dis ucu, alan sozlesmesi ve elle etiketli istek kumesi
const O = "POST /odunc", K = "GET /katalog", N = "POST /uye/not";

export const SEMA = {
  [O]: { uyeNo: { t: "d", desen: /^U-\d{5}$/, zorunlu: 1 },
         isbn:  { t: "d", desen: /^\d{13}$/, zorunlu: 1 },
         gun:   { t: "s", enAz: 1, enCok: 30 } },
  [K]: { q:     { t: "d", enCok: 64, zorunlu: 1 },
         sira:  { t: "d", kume: ["baslik", "yazar", "yil"] },
         sayfa: { t: "s", enAz: 1, enCok: 500 } },
  [N]: { uyeNo: { t: "d", desen: /^U-\d{5}$/, zorunlu: 1 },
         not:   { t: "d", enCok: 120, zorunlu: 1 } },
};

// [uc, govde, mesru?] — mesru degeri elle verilmis karardir, olcumden gelmez.
export const ISTEKLER = [
  [O, { uyeNo: "U-10432", isbn: "9789750718533", gun: 21 }, 1],
  [O, { uyeNo: "U-10432", isbn: "9789750718533" }, 1],
  [K, { q: "kayip zaman" }, 1],
  [K, { q: "O'Neill", sira: "yazar" }, 1],
  [K, { q: "kalem", sayfa: 3 }, 1],
  [N, { uyeNo: "U-10432", not: "kapak yipranmis" }, 1],
  [N, { uyeNo: "U-77120", not: "iadede 5 < 7 sayfa eksik" }, 1],
  [O, { uyeNo: "U-00001", isbn: "9786050000000", gun: 1 }, 1],
  [K, { q: "tarih -- 20. yuzyil" }, 1],
  [N, { uyeNo: "U-31005", not: "kitap; elden birakildi" }, 1],
  [O, { uyeNo: "U-10432", isbn: "978-975-07-1853-3" }, 1],   // tireli mesru bicim
  [O, { uyeNo: "u-10432", isbn: "9789750718533" }, 0],       // kucuk harf
  [O, { uyeNo: "U-10432", isbn: "978975071853" }, 0],        // on iki hane
  [O, { uyeNo: "U-10432", isbn: "9789750718533", gun: 400 }, 0],
  [O, { uyeNo: "U-10432", isbn: "9789750718533", gun: "21" }, 0],
  [O, { uyeNo: ["U-10432"], isbn: "9789750718533" }, 0],
  [O, { uyeNo: "U-10432", isbn: "9789750718533", ceza: 0 }, 0],
  [K, { q: "k".repeat(200) }, 0],
  [K, { q: "kalem", sira: "kitap.ic_not" }, 0],
  [K, { q: "kalem", sayfa: -2 }, 0],
  [N, { uyeNo: "U-10432" }, 0],
  [N, { uyeNo: "U-10432", not: "ok", yetki: "yonetici" }, 0],
].map(([uc, govde, m], i) => ({ no: i + 1, uc, govde, bekleniyor: m ? "kabul" : "ret" }));

export const sayim = (e) => ISTEKLER.filter((i) => i.bekleniyor === e).length;
```

Sözleşme dışı isteklerde zararlı yük yok; yanlış biçim, yanlış tip ve fazladan alan var.

## İki Karar Biçimi

**İzin listesi** sözleşmede yazılı olan dışında hiçbir şeyi geçirmez. **Engelleme listesi**
adı konmuş kötü biçimleri reddeder, geri kalanı geçirir. `bilinmeyenAlan` ayarı üçüncü bir
satır üretecek.

```js
// dogrulayici.mjs — ayni istek kumesine bakan iki karar bicimi
import { SEMA } from "./istekler.mjs";

// Izin listesi: sozlesmede yazili olan disinda hicbir sey gecmez.
// bilinmeyenAlan = "reddet" | "gecir"  (ikincisi bu dersin sessiz ayari)
export function izinListesi(uc, govde, { bilinmeyenAlan = "reddet" } = {}) {
  const alanlar = SEMA[uc];
  if (!alanlar) return { karar: "ret", neden: "tanimsiz uc" };
  const ret = (n) => ({ karar: "ret", neden: n });
  for (const [ad, v] of Object.entries(govde)) {
    const k = alanlar[ad];
    if (!k) { if (bilinmeyenAlan === "reddet") return ret(`bilinmeyen alan ${ad}`); continue; }
    if (k.t === "d") {
      if (typeof v !== "string") return ret(`${ad} dizge degil`);
      if (k.desen && !k.desen.test(v)) return ret(`${ad} bicime uymuyor`);
      if (k.enCok && v.length > k.enCok) return ret(`${ad} cok uzun`);
      if (k.kume && !k.kume.includes(v)) return ret(`${ad} kume disinda`);
    } else {
      if (!Number.isInteger(v)) return ret(`${ad} tam sayi degil`);
      if (v < k.enAz || v > k.enCok) return ret(`${ad} aralik disinda`);
    }
  }
  for (const [ad, k] of Object.entries(alanlar))
    if (k.zorunlu && govde[ad] === undefined) return ret(`${ad} eksik`);
  return { karar: "kabul", neden: "" };
}

// Engelleme listesi: adi konmus kotu bicimler reddedilir, geri kalan her sey gecer.
const YASAK = ["<", ">", "'", '"', "--", ";", "..", "\\"];
export function engellemeListesi(uc, govde) {
  for (const [ad, v] of Object.entries(govde)) {
    const m = typeof v === "string" ? v : String(v ?? "");
    for (const y of YASAK) if (m.includes(y)) return { karar: "ret", neden: `${ad} yasak imge ${y}` };
    if (m.length > 256) return { karar: "ret", neden: `${ad} cok uzun` };
  }
  return { karar: "kabul", neden: "" };
}

// Yanlis gecme: reddedilmesi gereken istek kabul edildi.
// Yanlis kalma: kabul edilmesi gereken istek reddedildi.
export function olc(istekler, karar) {
  const r = { yanlisGecme: 0, yanlisKalma: 0, kacan: [], takilan: [] };
  for (const i of istekler) {
    const c = karar(i.uc, i.govde).karar;
    if (c === i.bekleniyor) continue;
    if (i.bekleniyor === "ret") { r.yanlisGecme++; r.kacan.push(i.no); }
    else { r.yanlisKalma++; r.takilan.push(i.no); }
  }
  return r;
}
```

```js
// karsilastir.mjs — ayni 22 istek, uc karar bicimi; ucuncusu ilk ikisinin sessiz ayari
import { ISTEKLER, SEMA, sayim } from "./istekler.mjs";
import { izinListesi, engellemeListesi, olc } from "./dogrulayici.mjs";

const artik = (i) => Object.keys(i.govde).filter((a) => !SEMA[i.uc][a]);   // sozlesmede olmayan alan
const alan = Object.values(SEMA).reduce((t, a) => t + Object.keys(a).length, 0);
console.log(`${Object.keys(SEMA).length} uc, ${alan} alan sozlesmesi, ${ISTEKLER.length} istek: ` +
  `${sayim("kabul")} mesru, ${sayim("ret")} sozlesme disi\n`);

const BICIM = [
  ["izin listesi", (uc, g) => izinListesi(uc, g)],
  ["izin listesi (gecir)", (uc, g) => izinListesi(uc, g, { bilinmeyenAlan: "gecir" })],
  ["engelleme listesi", engellemeListesi],
];

console.log(`${"karar bicimi".padEnd(22)}${"yanlis gecme".padStart(13)}${"yanlis kalma".padStart(14)}${"artik alanli kayit".padStart(20)}${"hata".padStart(6)}`);
for (const [ad, f] of BICIM) {
  const r = olc(ISTEKLER, f);
  let a = 0, hata = 0;
  for (const i of ISTEKLER) {
    try { if (f(i.uc, i.govde).karar === "kabul" && artik(i).length) a++; } catch { hata++; }
  }
  console.log(ad.padEnd(22) + String(r.yanlisGecme).padStart(13) + String(r.yanlisKalma).padStart(14) +
    String(a).padStart(20) + String(hata).padStart(6));
  console.log(`  gecen sozlesme disi: ${r.kacan.join(", ") || "yok"}`);
  console.log(`  takilan mesru      : ${r.takilan.map((n) => `${n} (${f(ISTEKLER[n - 1].uc, ISTEKLER[n - 1].govde).neden})`).join(", ") || "yok"}`);
}
```

```
3 uc, 8 alan sozlesmesi, 22 istek: 11 mesru, 11 sozlesme disi

karar bicimi           yanlis gecme  yanlis kalma  artik alanli kayit  hata
izin listesi                      0             1                   0     0
  gecen sozlesme disi: yok
  takilan mesru      : 11 (isbn bicime uymuyor)
izin listesi (gecir)              2             1                   2     0
  gecen sozlesme disi: 17, 22
  takilan mesru      : 11 (isbn bicime uymuyor)
engelleme listesi                11             4                   2     0
  gecen sozlesme disi: 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22
  takilan mesru      : 4 (q yasak imge '), 7 (not yasak imge <), 9 (q yasak imge --), 10 (not yasak imge ;)
```

Engelleme listesi on bir sözleşme dışı isteğin **hepsini** geçirdi: liste yalnızca adını
bildiği imgeleri tanır, on iki haneli tanımlayıcıda ya da fazladan bir alanda o imgelerden
hiçbiri yok. Aynı liste dört meşru isteği reddetti — bir yazar adındaki kesme işareti, bir
nottaki küçüktür imgesi, arama metnindeki iki çizgi, bir noktalı virgül. **Engelleme
listesi iki sütunda birden kaybediyor.**

**BG2 (varsayım):** izin listesinin sözleşmesi, kümedeki meşru isteklerin biçimine bakarak
yazılmıştır; sıfır yanlış geçme kısmen bu yakınlığın sonucudur. Kalıntı on birinci istektir:
tireli tanımlayıcı meşrudur, sözleşme onu tanımıyor. **İzin listesinin bedeli budur** —
öngörülmemiş her meşru biçim bir yanlış kalmadır.

Ortadaki satır bu dersin ilk sessiz ayarıdır. `bilinmeyenAlan` ilkesi `gecir` yapıldığında
fırlatılan hata yine sıfırdır, ama iki istek kabul edilir ve depoya sözleşmede olmayan iki
alanla iner: bir ceza değeri ve bir yetki değeri. Bu alanları okuyan bir kod bugün yoktur.

## Sınırın Yeri

Ödünç isteği üç adımdan geçer: uçta kaydı alınır, serviste katalog rezervi yapılır, depoya
yazılır. İlk iki adım geri alınması gereken yan etkilerdir.

**BG3 (varsayım):** yan etki adım sayısıyla ölçülür, saniyeyle değil; her adımın süresi bu
derste sabit sayılır.

```js
// sinir.mjs — ayni dogrulayici, bes ayri sinir; olculen sey yan etkinin nerede durdugu
import { ISTEKLER, SEMA } from "./istekler.mjs";
import { izinListesi } from "./dogrulayici.mjs";

const ADIMLAR = ["uc", "servis", "depo"];   // yan etki: istek kaydi, katalog rezervi, yazma

function kos(istek, yerlesim, kayitli) {
  let yanEtki = 0;
  for (const a of ADIMLAR) {
    if (a === yerlesim && kayitli.includes(istek.uc) &&
        izinListesi(istek.uc, istek.govde).karar === "ret") return { yanEtki, yazildi: false };
    yanEtki++;
  }
  return { yanEtki, yazildi: true };
}

const TUM = Object.keys(SEMA);
const EKSIK = TUM.filter((u) => u !== "POST /uye/not");   // bir uc kayit edilmeyi bekliyor
const bozuk = ISTEKLER.filter((i) => i.bekleniyor === "ret");
const mesru = ISTEKLER.filter((i) => i.bekleniyor === "kabul");

console.log(`${bozuk.length} sozlesme disi istek, ${mesru.length} mesru istek, ${ADIMLAR.length} adimli boru hatti`);
console.log(`\n${"yerlesim".padEnd(12)}${"kapsanan uc".padStart(12)}${"duran".padStart(7)}${"yazilan bozuk".padStart(15)}${"bosa yan etki".padStart(15)}${"mesru yazma".padStart(13)}`);

for (const [ad, yer, kayitli] of [["uc", "uc", TUM], ["uc (eksik)", "uc", EKSIK],
    ["servis", "servis", TUM], ["depo", "depo", TUM], ["yok", "-", []]]) {
  const b = bozuk.map((i) => kos(i, yer, kayitli)), m = mesru.map((i) => kos(i, yer, kayitli));
  console.log(ad.padEnd(12) + String(kayitli.length).padStart(12) +
    String(b.filter((r) => !r.yazildi).length).padStart(7) +
    String(b.filter((r) => r.yazildi).length).padStart(15) +
    String(b.reduce((t, r) => t + (r.yazildi ? 0 : r.yanEtki), 0)).padStart(15) +
    String(m.filter((r) => r.yazildi).length).padStart(13));
}

const gecen = bozuk.filter((i) => kos(i, "uc", EKSIK).yazildi).map((i) => i.no);
console.log(`\nkayit edilmeyen uc POST /uye/not -> depoya inen sozlesme disi kayit: ${gecen.length} (istek ${gecen.join(", ")})`);
console.log(`bu yerlesimde uygulamanin urettigi hata sayisi: 0`);
```

```
11 sozlesme disi istek, 11 mesru istek, 3 adimli boru hatti

yerlesim     kapsanan uc  duran  yazilan bozuk  bosa yan etki  mesru yazma
uc                     3     11              0              0           10
uc (eksik)             2      9              2              0           10
servis                 3     11              0             11           10
depo                   3     11              0             22           10
yok                    0      0             11              0           11

kayit edilmeyen uc POST /uye/not -> depoya inen sozlesme disi kayit: 2 (istek 21, 22)
bu yerlesimde uygulamanin urettigi hata sayisi: 0
```

Üç tam yerleşim de aynı sayıda isteği durduruyor; ayrıştıkları yer **ne kadar iş boşa
gittiği**. Uçta doğrulama sıfır yan etkiyle durur, serviste on bir istek kaydını boşa yazar,
depoda yirmi iki adımı boşa çalıştırır — bunların on biri katalog rezervidir, yani bir kopya
ayrılıp geri bırakılır.

İkinci satır ikinci sessiz ayardır. Doğrulayıcı uç başına kaydediliyorsa üç kayıt noktası
vardır ve dördüncü uç eklendiğinde dördüncü kayıt elle yazılmalıdır. Yazılmazsa uygulama
çalışır, hiçbir sınama kırılmaz ve iki sözleşme dışı kayıt sessizce depoya iner. Tek boru
hattı bu riski bir noktaya indirir.

`mesru yazma` sütunu son bir şey söylüyor: doğrulamalı her yerleşimde on bir meşru istekten
**onu** depoya iniyor. Yanlış kalmanın bedeli kaydedilmeyen bir ödünç işlemidir.

## Çıktı Kodlama

Doğrulamayı geçen değer güvenli değildir; **sözleşmeye uygundur**. Üye notu serbest metin
kabul eder, çünkü okuyucu notunda tırnak, virgül ve küçüktür imgesi meşru geçer. Bu değer üç
ayrı yere yazılıyor: bir işaretleme gövdesine, bir öznitelik tırnağının içine ve virgülle
ayrılmış bir dışa aktarım satırına. Ölçü tek sorudur: **değer kaba konup geri okunduğunda
aynı mı çıkıyor?**

```js
// kodlama.mjs — dogrulamayi gecmis mesru degerler, uc ayri cikti baglami
// Olcu: deger kaba yerlestirilip kabin kendi kuraliyla geri okundugunda aynisi mi cikiyor?
const DEGERLER = ["kapak yipranmis", "iadede 5 < 7 sayfa eksik", 'uye "acele" notu dusmus',
  "raf 3, kat 2", "ilk satir\nikinci satir", 'bagis, "ikinci el" 5 kitap'];

const govde = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
const oznitelik = (s) => govde(s).replace(/"/g, "&quot;").replace(/\n/g, "&#10;");
const ayrilmis = (s) => `"${s.replace(/"/g, '""')}"`;
const coz = (s) => s.replace(/&quot;/g, '"').replace(/&#10;/g, "\n")
  .replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&");

const ayir = (k) => {                       // tirnaga saygili alan ayirici
  const alan = []; let s = "", t = false;
  for (let i = 0; i < k.length; i++) {
    const c = k[i];
    if (t && c === '"' && k[i + 1] === '"') { s += '"'; i++; }
    else if (c === '"') t = !t;
    else if (!t && (c === "," || c === "\n")) { alan.push(s); s = ""; }
    else s += c;
  }
  return [...alan, s];
};

const BAGLAM = [
  ["govde", (x) => `<not>${x}</not>`, govde, (k) => {
    const son = k.indexOf("<", 5);          // alan, bir sonraki kap imgesine kadar okunur
    return k.startsWith("<not>") && k.slice(son) === "</not>" ? coz(k.slice(5, son)) : null;
  }],
  ["oznitelik", (x) => `<kayit baslik="${x}"/>`, oznitelik,
    (k) => { const m = /baslik="([^"]*)"/.exec(k); return m ? coz(m[1]) : null; }],
  ["ayrilmis", (x) => `U-10432,${x},2026-03-04`, ayrilmis,
    (k) => { const a = ayir(k); return a.length === 3 ? a[1] : null; }],
];

const dene = (kodlayici) => {
  const liste = [];
  for (const [ad, kap, dogru, oku] of BAGLAM)
    DEGERLER.forEach((d, i) => {
      if (oku(kap(kodlayici(d, dogru))) !== d) liste.push(`${ad}/${i + 1}`);
    });
  return liste;
};

console.log(`${DEGERLER.length} deger x ${BAGLAM.length} baglam = ${DEGERLER.length * BAGLAM.length} yerlestirme\n`);
console.log(`${"kodlayici".padEnd(24)}${"geri okunamayan".padStart(16)}  yer`);
for (const [ad, f] of [["kodlama yok", (d) => d], ["tek kodlayici (govde)", govde],
    ["baglama gore", (d, dogru) => dogru(d)]]) {
  const l = dene(f);
  console.log(`${ad.padEnd(24)}${String(l.length).padStart(16)}  ${l.join(" ") || "-"}`);
}
```

```
6 deger x 3 baglam = 18 yerlestirme

kodlayici                geri okunamayan  yer
kodlama yok                            7  govde/2 oznitelik/3 oznitelik/6 ayrilmis/3 ayrilmis/4 ayrilmis/5 ayrilmis/6
tek kodlayici (govde)                  7  oznitelik/3 oznitelik/6 ayrilmis/2 ayrilmis/3 ayrilmis/4 ayrilmis/5 ayrilmis/6
baglama gore                           0  -
```

Tek kodlayıcı hiçbir şey kazandırmadı: on sekiz yerleştirmenin yedisi hâlâ geri okunamıyor
ve **liste değişti**. Gövde bağlamı düzeldi, ayrılmış değer bağlamında ikinci değer bozuldu
— nottaki küçüktür imgesi kaçış dizisine çevrildiği için dışa aktarım satırında ham metin
olarak duruyor. Üçüncü sessiz sonuç budur: dosya açılır, satırlar okunur ve içindeki not
artık yazılan not değildir.

Doğru gerçekleştirim kodlamayı **veri girerken değil, yazarken** yapar; girişte kodlanan bir
değer ikinci bağlama gittiğinde iki kez kodlanır.

## Özet

- Aynı yirmi iki istekte izin listesi 0 yanlış geçme ve 1 yanlış kalma, engelleme listesi
  11 yanlış geçme ve 4 yanlış kalma verdi. Engelleme listesinin geçirdiklerinde zararlı imge
  yoktu; yanlış biçim, yanlış tip ve fazladan alan vardı.
- İzin listesinin bedeli tek yanlış kalmadadır: tireli yazılmış meşru bir tanımlayıcı
  reddedildi, bir ödünç işlemi kaydedilmedi.
- Doğrulama uçta durduğunda 0, serviste 11, depoda 22 adım boşa çalıştı; durdurulan istek
  sayısı üçünde de aynıydı. Fark yalnız maliyettedir.
- Tek kodlayıcı üç bağlama yetmedi: 18 yerleştirmenin 7'si geri okunamadı ve bir bağlam
  düzelirken başkası bozuldu. Kodlama her çıktı bağlamında ayrı yapılır.
- Üç yanlış ayar da sessizdir, toplam fırlatılan hata sıfırdır: `bilinmeyenAlan` ilkesi
  2 artık alanı depoya indirdi, kaydı unutulan bir uç 2 sözleşme dışı kaydı yazdırdı, yanlış
  bağlamdaki kodlayıcı bir satırı bozdu. Doğrulayıcının kaydı uç başına yapılırsa 3 noktada
  tekrarlanır, tek boru hattında 1 noktada durur.

## Sonraki Adım

Doğrulama sınırı gövdenin biçimini garanti eder. Garanti etmediği şey o değerin sistemin
içinde **nasıl kullanıldığıdır**. Sözleşmeye tamamen uyan bir arama metni, bir sıralama
alanı ya da bir bildirim şablonu; bir sorgu metnine, bir komut satırına veya bir şablon
gövdesine dizge birleştirmesiyle konduğunda artık veri değil, o dilin bir parçası olur.
Sonraki ders bu üç yeri aynı kökten gösterir ve tek kararı ölçer: değer metne
birleştirildiğinde ile ayrı bir işlenen olarak geçirildiğinde aynı istek kümesi kaç farklı
sonuç üretiyor.
