---
title: 'Çıktı Kodlama'
source: 'https://academia.sh/tr/kurslar/guvenli-kodlama/cikti-kodlama'
course: 'Güvenli Kodlama'
language: tr
updated: '2026-08-17T18:06:42+00:00'
license: 'CC BY-SA 4.0'
---

# Çıktı Kodlama

Bağlama göre kaçışlamanın kapsamasının ölçülmesi: altı meşru abone notu dört çıktı bağlamına dört ayrı kodlayıcıyla yerleştirilir, on altı eşlemede geri okunamayan yerleştirme sayılır, on dört çıkış noktalı bir envanterde çağrı yerinde kodlayıcı seçen biçim ile bağlamdan türeten biçim karşılaştırılır ve iç içe iki bağlamda kodlayıcı sırasının kaç değeri bozduğu ölçülür.

Önceki ders giriş noktalarını saydı ve bildirimden türeyen doğrulamanın on beş noktayı
kendiliğinden kapattığını gösterdi. Doğrulamayı geçen değer artık sözleşmeye uygundur:
abone notu iki yüz karakteri aşmıyor, tarife kümede, dönem biçimli. Bu değerin sistemden
**çıkarken** ne olacağı hakkında doğrulama hiçbir şey söylemez.

Bu ders çıkış noktalarını sayar. Aynı abone notu bir sayfa gövdesine, bir öznitelik
tırnağının içine, bir betik değişkenine ve bir adres bileşenine yazılıyor. Dördü de aynı
değeri alıyor; dördü de o değeri farklı bir kuralla okuyor. Ölçülen şey **bağlamın doğru
seçilip seçilmediği ve kaç çıkış noktasının bu seçimi kendi başına yapmak zorunda
kaldığıdır**.

## Dört Çıktı Bağlamı

Bir bağlam üç parçadan oluşur: değeri saran **kap**, kabın kendi **kodlayıcısı** ve kabın
kendi **geri okuyucusu**. Ölçü tek sorudur — değer kaba konup kabın kuralıyla geri
okunduğunda aynısı mı çıkıyor.

**GC5 (varsayım):** geri okuma, kabı çözen tarafın kuralını temsil eder. Bir yerleştirme,
geri okuma değeri birebir vermediğinde bozulmuş sayılır; bozulmanın ne kadar zararlı olduğu
ölçülmez.

```js
// baglam.mjs — dort cikti baglami: kap, kendi kodlayicisi ve kabin kendi geri okuyucusu
// Olcu: deger kaba konup kabin kuraliyla geri okundugunda ayni mi cikiyor?
export const DEGER = ["sayac kapagi kirik", 'abone "acele" notu dusmus', "raf 3 & kat 2",
  "olcum < 5 m3", "ilk satir\nikinci satir", "yuzde 5 artis %"];

const govde = (s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
export const KODLAYICI = {
  govde,
  oznitelik: (s) => govde(s).replace(/"/g, "&quot;").replace(/\n/g, "&#10;"),
  betik: (s) => JSON.stringify(s).slice(1, -1),
  adres: (s) => encodeURIComponent(s),
};

const coz = (s) => s.replace(/&quot;/g, '"').replace(/&#10;/g, "\n")
  .replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&");

export const BAGLAM = {
  govde: [(x) => `<not>${x}</not>`, (k) => {
    const i = k.indexOf("<", 5);
    return k.startsWith("<not>") && k.slice(i) === "</not>" ? coz(k.slice(5, i)) : null;
  }],
  oznitelik: [(x) => `<kayit not="${x}"/>`,
    (k) => { const m = /not="([^"]*)"/.exec(k); return m ? coz(m[1]) : null; }],
  betik: [(x) => `const not = "${x}";`, (k) => {
    try { return JSON.parse(k.slice(k.indexOf('"'), k.lastIndexOf('"') + 1)); } catch { return null; }
  }],
  adres: [(x) => `/rapor?not=${x}&bicim=ozet`, (k) => {
    try {
      const a = k.split("?")[1].split("&").find((p) => p.startsWith("not="));
      return a === undefined ? null : decodeURIComponent(a.slice(4));
    } catch { return null; }
  }],
};

// Tek yerlestirme: deger kodlanir, kaba konur, geri okunur.
export const geriOkunur = (baglam, kodlayiciAdi, deger) => {
  const [kap, oku] = BAGLAM[baglam];
  return oku(kap(KODLAYICI[kodlayiciAdi](deger))) === deger;
};
```

Altı değerin hepsi meşru abone ve saha notudur: bir tırnak, bir ve imgesi, bir küçüktür
imgesi, bir satır sonu, bir yüzde imgesi. Hiçbiri saldırı girdisi değildir; hepsi bir
görevlinin yazabileceği metinlerdir.

## Bağlam Yanlış Seçildiğinde

Dört bağlam ve dört kodlayıcı on altı eşleme verir. Dördü doğru eşlemedir; kalan on ikisi
bağlamın yanlış seçilmesidir.

```js
// secim.mjs — dort baglam x dort kodlayici: baglam yanlis secildiginde kac durum bozuluyor
import { DEGER, KODLAYICI, BAGLAM, geriOkunur } from "./baglam.mjs";

const B = Object.keys(BAGLAM), K = Object.keys(KODLAYICI);
console.log(`${DEGER.length} deger, ${B.length} baglam, ${K.length} kodlayici, ` +
  `${B.length * K.length} esleme, ${DEGER.length * B.length * K.length} yerlestirme\n`);
console.log("bozulan deger sayisi (satir: baglam, sutun: secilen kodlayici)");
console.log("baglam".padEnd(12) + K.map((k) => k.padStart(11)).join(""));
let dogru = 0, yanlis = 0;
for (const b of B) {
  const satir = K.map((k) => DEGER.filter((d) => !geriOkunur(b, k, d)).length);
  K.forEach((k, i) => (k === b ? (dogru += satir[i]) : (yanlis += satir[i])));
  console.log(b.padEnd(12) + satir.map((n) => String(n).padStart(11)).join(""));
}
console.log(`\ndogru baglam secilen ${B.length} eslemede bozulan: ${dogru}`);
console.log(`yanlis baglam secilen ${B.length * K.length - B.length} eslemede bozulan: ${yanlis}`);
```

```
6 deger, 4 baglam, 4 kodlayici, 16 esleme, 96 yerlestirme

bozulan deger sayisi (satir: baglam, sutun: secilen kodlayici)
baglam            govde  oznitelik      betik      adres
govde                 0          0          3          6
oznitelik             1          0          2          6
betik                 4          4          0          6
adres                 3          5          4          0

dogru baglam secilen 4 eslemede bozulan: 0
yanlis baglam secilen 12 eslemede bozulan: 44
```

Köşegen sıfırdır: her bağlam kendi kodlayıcısıyla altı değeri de geri veriyor. Köşegen
dışında doksan altı yerleştirmenin kırk dördü bozuluyor.

Son sütun bu tablonun en öğretici yeridir. Adres kodlayıcısı hangi bağlama konursa konsun
**altı değerin altısını da** bozuyor. Eksik kaçışlama değil, fazla kaçışlama bu: boşluklar
ve noktalama yüzde imgeli dizilere dönüşüyor ve sayfada okunan not artık yazılan not
değil. Yanlış bağlam iki yönde birden hata üretir; sıkı kodlayıcının zararsız olduğu
varsayımı ölçümde tutmuyor.

Betik satırı ikinci noktadır. Gövde kodlayıcısı betik bağlamında dört değeri bozuyor,
çünkü tırnak ve satır sonu gövde kuralında özel değildir — orada özel olan üç imge
başkadır. Kodlayıcının "daha güvenli" olması yetmez; **kabın kuralıyla aynı kural olması
gerekir**.

## Çıkış Noktası Envanteri

Bağlam seçimi bir yerde değil, her çıkış noktasında ayrı ayrı yapılır. Bölgesel ölçüm
ağının çıkış noktaları sayılıyor: abone portalı, faturalama, saha uygulaması ve rapor
üretici.

**GC6 (varsayım):** her çıkış noktasının gerçek bağlamı bilinir ve envantere doğru
yazılmıştır. Ölçülen şey çağrı yerinde seçilen kodlayıcının bu bağlamla uyuşup uyuşmadığıdır.

```js
// cikis-noktalari.mjs — cikis noktasi envanteri (kurgu model) ve iki yazma bicimi
import { DEGER, KODLAYICI, BAGLAM } from "./baglam.mjs";

const KOD = { ...KODLAYICI, ham: (s) => s };
const okunur = (b, k, d) => { const [kap, oku] = BAGLAM[b]; return oku(kap(KOD[k](d))) === d; };

// [servis, cikis noktasi, gercek baglam, cagri yerinde secilen kodlayici]
const CIKIS = [
  ["abone portali", "profil basligi", "govde", "govde"],
  ["abone portali", "not listesi", "govde", "govde"],
  ["abone portali", "form onizleme", "oznitelik", "govde"],
  ["abone portali", "arama baglantisi", "adres", "ham"],
  ["abone portali", "durum betigi", "betik", "govde"],
  ["fatura", "dokum satiri", "govde", "govde"],
  ["fatura", "yazdirma basligi", "oznitelik", "oznitelik"],
  ["fatura", "indirme baglantisi", "adres", "adres"],
  ["saha uygulamasi", "is emri karti", "govde", "govde"],
  ["saha uygulamasi", "harita etiketi", "oznitelik", "ham"],
  ["saha uygulamasi", "sunucu cagrisi", "adres", "adres"],
  ["rapor uretici", "ozet govde", "govde", "govde"],
  ["rapor uretici", "baglanti ureteci", "adres", "govde"],
  ["rapor uretici", "gomulu veri betigi", "betik", "betik"],
];
// Yeni cikis noktalari: cagri yerinde kimse kodlayici secmemis.
const YENI = [["saha uygulamasi", "fotograf basligi", "oznitelik", "ham"],
  ["rapor uretici", "dis baglanti", "adres", "ham"], ["abone portali", "bildirim betigi", "betik", "ham"]];

const olc = (liste, secim) => {
  let bozukNokta = 0, bozukYer = 0;
  for (const [, , baglam, elle] of liste) {
    const n = DEGER.filter((d) => !okunur(baglam, secim === "merkezi" ? baglam : elle, d)).length;
    if (n) bozukNokta++;
    bozukYer += n;
  }
  return [bozukNokta, bozukYer];
};

console.log(`${"asama".padEnd(28)}${"nokta".padStart(6)}${"yerlestirme".padStart(12)}` +
  `${"dagink nokta".padStart(14)}${"dagink yer".padStart(12)}${"merkezi".padStart(9)}`);
for (const [ad, l] of [["mevcut envanter", CIKIS], ["uc yeni nokta eklendi", [...CIKIS, ...YENI]]]) {
  const [dn, dy] = olc(l, "elle"), [, my] = olc(l, "merkezi");
  console.log(ad.padEnd(28) + String(l.length).padStart(6) + String(l.length * DEGER.length).padStart(12) +
    String(dn).padStart(14) + String(dy).padStart(12) + String(my).padStart(9));
}
const say = (b) => CIKIS.filter((c) => c[2] === b).length;
console.log("\nbaglam dagilimi: " + Object.keys(BAGLAM).map((b) => `${b} ${say(b)}`).join("  "));
console.log("cagri yerinde secim: dogru " + CIKIS.filter((c) => c[2] === c[3]).length +
  ", yanlis " + CIKIS.filter((c) => c[3] !== "ham" && c[2] !== c[3]).length +
  ", hic yok " + CIKIS.filter((c) => c[3] === "ham").length);
```

```
asama                        nokta yerlestirme  dagink nokta  dagink yer  merkezi
mevcut envanter                 14          84             5          11        0
uc yeni nokta eklendi           17         102             8          16        0

baglam dagilimi: govde 5  oznitelik 3  betik 2  adres 4
cagri yerinde secim: dogru 9, yanlis 3, hic yok 2
```

On dört çıkış noktasının beşi bozuk yazıyor: üçünde yanlış kodlayıcı seçilmiş, ikisinde
hiçbir kodlayıcı yok. Merkezî biçimde bozulma sıfırdır, çünkü kodlayıcı çağrı yerinde
seçilmiyor — noktanın bağlam bildiriminden türüyor. Aradaki fark bilgi farkı değil, **kararın
yeri** farkıdır: dokuz çağrı yeri doğru seçmiş, beşi seçmemiş; merkezî biçimde seçilecek bir
şey yok.

İkinci satır kapsamanın yeni noktada nasıl davrandığını veriyor. Üç yeni çıkış noktası
eklendiğinde dağınık biçimde bozuk nokta beşten sekize çıkıyor — **her yeni çıkış noktası
doğrudan bir bozulma adayıdır**, çünkü kodlayıcıyı yazan biri olmadıkça yoktur. Merkezî
biçim aynı üç noktada sıfırda kalıyor.

## İç İçe Bağlam

Envanterdeki her nokta tek bir bağlama yazmıyor. Bir öznitelik tırnağının içine bir betik
parçası konduğunda değer iki kabın içindedir ve iki kuralla okunur.

```js
// ic-ice.mjs — bir baglamin icine gomulu ikinci baglam: oznitelik icinde betik baglami
import { DEGER, KODLAYICI } from "./baglam.mjs";

const kap = (x) => `<kayit islem="const not = &quot;${x}&quot;;"/>`;
const coz = (s) => s.replace(/&quot;/g, '"').replace(/&#10;/g, "\n")
  .replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&");
const oku = (k) => {                    // once dis kap, sonra ic kap kendi kuraliyla okunur
  const m = /islem="([^"]*)"/.exec(k);
  if (!m) return null;
  const kod = coz(m[1]);
  try { return JSON.parse(kod.slice(kod.indexOf('"'), kod.lastIndexOf('"') + 1)); } catch { return null; }
};

console.log(`${DEGER.length} deger, ic ice iki baglam: oznitelik icinde betik\n`);
console.log(`${"kodlayici secimi".padEnd(32)}${"geri okunamayan".padStart(16)}`);
for (const [ad, f] of [["yalniz dis baglam (oznitelik)", KODLAYICI.oznitelik],
    ["yalniz ic baglam (betik)", KODLAYICI.betik],
    ["once dis sonra ic", (d) => KODLAYICI.betik(KODLAYICI.oznitelik(d))],
    ["once ic sonra dis", (d) => KODLAYICI.oznitelik(KODLAYICI.betik(d))]])
  console.log(ad.padEnd(32) + String(DEGER.filter((d) => oku(kap(f(d))) !== d).length).padStart(16));
```

```
6 deger, ic ice iki baglam: oznitelik icinde betik

kodlayici secimi                 geri okunamayan
yalniz dis baglam (oznitelik)                  2
yalniz ic baglam (betik)                       1
once dis sonra ic                              2
once ic sonra dis                              0
```

Tek kodlayıcı iki yönde de yetmiyor: dış bağlamınki iki değeri, iç bağlamınki bir değeri
bozuyor. İki kodlayıcı birlikte kullanıldığında sonucu **sıra** belirliyor. Dıştan içe
gidilirse iki değer bozuk kalır; içten dışa gidilirse altısı da geri okunur.

Bunun kapsama karşılığı doğrudandır. Çıkış noktası başına **tek bir bağlam** tutan bir
bildirim, iç içe noktayı ifade edemez; o noktalar merkezî kalıbın dışında kalır ve karar
yine çağrı yerine döner. Kapsamayı sabit tutmak isteyen bildirim, bağlamı değil **bağlam
dizisini** taşımak zorundadır.

Bağlam dağılımı satırı ayrı bir şey söylüyor: on dört noktanın beşi gövde, dördü adres, üçü
öznitelik, ikisi betik bağlamındadır. Dört bağlamın hepsi kullanılıyor ve hiçbiri baskın
değil. Tek kodlayıcıyla çalışan bir kod tabanının bu dağılımda doğru sonuç vermesi olanaksızdır;
köşegen dışı hücrelerin sayısı doğrudan bu dağılımdan gelir.

## Kalıbın Yetmediği İkinci Yer

Merkezî kalıp her noktada doğru kodlayıcıyı seçse bile bir varsayıma dayanır: depodan gelen
değer hamdır. Bu varsayım kaldırıldığında kalıp elinde olmayan bir nedenden bozar.

```js
// saklama.mjs — deger depoya kodlanmis girerse merkezi kalip ne yapiyor
import { DEGER, KODLAYICI, BAGLAM } from "./baglam.mjs";

const B = Object.keys(BAGLAM);
const yerlestir = (b, d) => { const [kap, oku] = BAGLAM[b]; return oku(kap(KODLAYICI[b](d))); };
console.log(`${DEGER.length} deger x ${B.length} baglam; merkezi kalip her noktada dogru kodlayiciyi seciyor\n`);
console.log(`${"saklama karari".padEnd(28)}${"bozulan".padStart(9)}  baglam basina`);
for (const [ad, sakla] of [["ham saklanan deger", (d) => d],
    ["giriste bir kez kodlanmis", KODLAYICI.govde]]) {
  const satir = B.map((b) => DEGER.filter((d) => yerlestir(b, sakla(d)) !== d).length);
  console.log(ad.padEnd(28) + String(satir.reduce((a, c) => a + c, 0)).padStart(9) +
    "  " + B.map((b, i) => `${b} ${satir[i]}`).join("  "));
}
```

```
6 deger x 4 baglam; merkezi kalip her noktada dogru kodlayiciyi seciyor

saklama karari                bozulan  baglam basina
ham saklanan deger                  0  govde 0  oznitelik 0  betik 0  adres 0
giriste bir kez kodlanmis           8  govde 2  oznitelik 2  betik 2  adres 2
```

Değer girişte bir kez kodlanıp öyle saklandığında dört bağlamın dördü de ikişer değeri
bozuyor. Kodlayıcı seçimi doğrudur, kap doğrudur, geri okuyucu doğrudur; bozan şey değerin
depoya girerken uğradığı işlemdir. Ve imgesi ile küçüktür imgesi taşıyan iki not, çıkışta
ikinci kez kodlandığı için okuyucuya kaçış dizisiyle varıyor.

Bu bozulmanın kapsama karşılığı ilkinden ağırdır. Çağrı yerindeki yanlış seçim **tek**
noktayı bozar; depodaki yanlış saklama kararı o değeri okuyan **her** noktayı bozar — bu
envanterde on dördünü birden. Kodlamanın yeri çıkıştır ve bunun nedeni ilke değil, sayıdır:
çıkışta karar bağlam başına verilir, girişte tek karar bütün bağlamlara dayatılır.

## Özet

- Dört bağlam ve dört kodlayıcı on altı eşleme verdi. Doğru eşlemelerde 96 yerleştirmenin
  hiçbiri bozulmadı; yanlış bağlam seçilen on iki eşlemede 44 yerleştirme geri okunamadı.
- Yanlış bağlam iki yönde birden bozar: adres kodlayıcısı diğer üç bağlamda altı değerin
  altısını da bozdu — eksik kaçışlama değil, fazla kaçışlama. Gövde kodlayıcısı betik
  bağlamında dört değeri bozdu.
- On dört çıkış noktasının 9'unda kodlayıcı doğru seçilmiş, 3'ünde yanlış, 2'sinde hiç
  seçilmemiş; dağınık biçimde 5 nokta ve 11 yerleştirme bozuk. Kodlayıcı bağlam
  bildiriminden türetildiğinde bozulma 0.
- Üç yeni çıkış noktası eklendiğinde dağınık biçimde bozuk nokta 5'ten 8'e çıktı, merkezî
  biçimde 0'da kaldı. Yeni çıkış noktası, kodlayıcısını yazan biri olmadıkça baştan
  bozuktur.
- Değer girişte bir kez kodlanıp öyle saklandığında merkezî kalıp doğru çalıştığı hâlde 8
  yerleştirme bozuldu. Çağrı yerindeki yanlış seçim tek noktayı, depodaki yanlış saklama
  kararı o değeri okuyan 14 noktayı birden bozar.
- İç içe bağlamda tek kodlayıcı yetmedi: dış bağlamınki 2, iç bağlamınki 1 değeri bozdu.
  Sıra belirleyicidir — içten dışa 0, dıştan içe 2. Nokta başına tek bağlam tutan bir
  bildirim bu noktaları kapsayamaz.

## Sonraki Adım

Çıktı kodlaması değerin **okunacağı** kabı hedef alır. Değerin sistem içinde bir sorgu
metnine konması ayrı bir sorundur: orada kap bir belge değil, bir sorgu dilidir ve o dili
okuyan taraf veriyle komutu aynı metinden ayırmak zorundadır. Sonraki ders sorgu
noktalarını sayar ve tek soruyu ölçer: kaç sorgu değeri ayrı bir işlenen olarak taşıyan bir
arayüzden geçiyor, kaç sorgu değeri metnin kendisine katıyor ve bu iki biçimden hangisi
yeni bir sorgu eklendiğinde noktayı kendiliğinden kapsıyor.
