---
title: 'Dinamik Uygulama Güvenlik Testi'
source: 'https://academia.sh/tr/kurslar/guvenlik-otomasyonu/dinamik-uygulama-guvenlik-testi'
course: 'Güvenlik Otomasyonu ve Tedarik Zinciri'
language: tr
updated: '2026-08-17T18:06:43+00:00'
license: 'CC BY-SA 4.0'
---

# Dinamik Uygulama Güvenlik Testi

96 uçluk bir yüzeyde çalışan uygulamayı tarayan aracın erişebildiği ve erişemediği alan: anonim gezinme 13 uca varıp 2 açık buluyor, oturum ve kayıtlı akış eklendiğinde 84 uca ve 10 açığa çıkıyor, 12 yönetim ucu her yapılandırmada dışarıda kalıyor. 28 açığın 18'i görülmüyor; 5'i erişilemediği için, 13'ü erişildiği halde. Aynı tarama hatta üç ayrı yere konuyor: her yapıda tam 5 316 dakika ve sıfır gecikme, gecelik tam 443 dakika ve 6 yapı gecikme, yalnız değişen uç 126 dakika ama 3 açığı hiç görmüyor.

Bir önceki ders statik çözümlemenin görüş alanını saydı ve 163 açık noktanın 62'sinin her eşikte
dışarıda kaldığını gösterdi. Bunların büyük bölümü kararı çalışma zamanında verilen noktalardı:
bir isteğin çağıranın yetkisine uyup uymadığı, bir başlığın gerçekten gönderilip gönderilmediği
kaynak metninden okunmuyordu. Bu noktalara ulaşmanın bir yolu var — uygulamayı ayağa kaldırıp
dışarıdan istemek.

**Dinamik uygulama güvenlik testi** (dynamic application security testing), çalışan bir uygulamaya
istek göndererek açık arayan denetimdir. Kaynak koda bakmaz, dolayısıyla dilden ve çerçeveden
bağımsızdır; buna karşılık **yalnız erişebildiğini görür**. Bu ders o sınırı sayar: kaç uca
varılıyor, kaç uca varılamıyor, varılan uçta ne kaçıyor ve bütün bunlar hattan kaç dakika alıyor.

- **OD7.** Yüzey, abone portalı ile sayaç alım servisinin 96 ucudur. Envanter **kurgudur** ve bir
  modeldir; bu sayfada hiçbir hedefe istek gönderilmez.
- **OD8.** Her ucun iki bağımsız özelliği vardır. **Keşif**, adresin nasıl bulunduğudur: sayfa
  bağlantısı, yalnız istemci betiğinin kurduğu adres ya da bir arayüz bildirimi. **Erişim**, uçtan
  geçerli yanıt alma koşuludur: anonim, oturum gerektiren, yalnız belirli bir akış sırasında
  ortaya çıkan, yönetim rolü isteyen.
- **OD9.** Bir yapılandırma, tarayıcıya verilen yetenek kümesidir. Üçü karşılaştırılır ve her biri
  bir öncekinin üstüne tek bir yetenek ekler.
- **OD10.** Her açığın bir **görülür** değeri vardır: araç o uca ulaştığında açığı yakalar mı.
  Değer ucun kendi özelliğidir, yapılandırmadan bağımsızdır; böylece yetenek eklemek bulunan
  açığı yalnız erişim üzerinden değiştirir.
- **OD11.** İstek başına 0,05 model dakikası harcanır. Süreler **veridir**, bu sayfada yapılmış
  bir ölçüm değildir.
- **OD12.** Bir kez incelenip yanlış pozitif olarak işaretlenen bulgu bastırma listesine girer ve
  sonraki koşumlarda yapıyı bir daha durdurmaz.

## Varılan ve Varılamayan Yüzey

```js
// yuzey.mjs — calisan uygulamayi tarayan aracin erisebildigi ve erisemedigi yuzey.
// MODELDIR; uc envanteri kurgudur, hicbir hedefe istek gonderilmez.
export const TOHUM = 20260317, UC = 96, ISTEK_DK = 0.05;
const uretec = (t) => { let s = t >>> 0;
  return () => (s = (s * 1664525 + 1013904223) >>> 0) / 4294967296; };
const r = uretec(TOHUM);

// kesif: uc adresinin nasil bulundugu. erisim: uca gecerli yanit aldirmanin kosulu.
const KESIF = [["baglanti", 0.52], ["istemci", 0.27], ["bildirim", 0.21]];
const ERISIM = [["anonim", 0.30], ["oturum", 0.42], ["sira", 0.16], ["yonetim", 0.12]];
// Acik sinifi: gorme = arac o sinifi erisebildigi bir ucta yakalama olasiligi.
export const SINIF = [
  { ad: "yapilandirma basligi", pay: 0.22, gorme: 0.95, istek: 4 },
  { ad: "yansiyan girdi", pay: 0.26, gorme: 0.85, istek: 26 },
  { ad: "hata mesaji sizintisi", pay: 0.18, gorme: 0.75, istek: 12 },
  { ad: "erisim denetimi", pay: 0.20, gorme: 0.15, istek: 18 },
  { ad: "is akisi kurali", pay: 0.14, gorme: 0.05, istek: 22 },
];
const sec = (tablo, u) => { let t = 0;
  for (const [ad, p] of tablo) { t += p; if (u < t) return ad; } return tablo.at(-1)[0]; };
const sinifSec = (u) => { let t = 0;
  for (const s of SINIF) { t += s.pay; if (u < t) return s; } return SINIF.at(-1); };

export const UCLAR = Array.from({ length: UC }, (_, i) => {
  const kesif = sec(KESIF, r()), erisim = sec(ERISIM, r());
  const acik = r() < 0.34 ? sinifSec(r()) : null;
  // gorulur, ucun kendi ozelligidir: arac uca ulassa bile bu acigi yakalar mi.
  const gorulur = acik ? r() < acik.gorme : false;
  return { i, kesif, erisim, acik, gorulur,
    istek: 6 + (acik ? acik.istek : 14), yanlis: r() < 0.13 };
});

// Uc yapilandirma: her biri bir onceki yetenegin ustune bir tane ekler.
export const YAPILANDIRMA = [
  { ad: "anonim gezinme", kesif: ["baglanti"], erisim: ["anonim"] },
  { ad: "oturumlu gezinme", kesif: ["baglanti", "istemci"], erisim: ["anonim", "oturum"] },
  { ad: "oturum + kayitli akis", kesif: ["baglanti", "istemci", "bildirim"],
    erisim: ["anonim", "oturum", "sira"] },
];
export const erisilen = (y) =>
  UCLAR.filter((u) => y.kesif.includes(u.kesif) && y.erisim.includes(u.erisim));

export function kosum(y) {
  const varilan = erisilen(y);
  const istek = varilan.reduce((a, u) => a + u.istek, 0);
  const gercek = varilan.filter((u) => u.acik && u.gorulur);
  const yanlisPoz = varilan.filter((u) => u.yanlis);
  const acikUc = UCLAR.filter((u) => u.acik);
  return { ad: y.ad, varilan, istek, gercek, yanlisPoz,
    erisilemeyen: acikUc.filter((u) => !varilan.includes(u)).length,
    gorulmeyen: acikUc.length - gercek.length, dk: Math.round(istek * ISTEK_DK) };
}

const gen = (B) => (h) => h.map((v, j) => (j ? String(v).padStart(B[j])
  : String(v).padEnd(B[0]))).join("");

if (import.meta.url === `file://${process.argv[1]}`) {
  const acikUc = UCLAR.filter((u) => u.acik);
  console.log(`model (tohum ${TOHUM}): ${UC} uc, ${acikUc.length} tanesinde gercek acik; ` +
    `${UCLAR.filter((u) => u.erisim === "yonetim").length} uc yonetim rolu istiyor`);
  const y1 = gen([23, 9, 8, 8, 9, 9, 12, 14, 11]);
  console.log("\n" + y1(["yapilandirma", "erisilen", "istek", "bulgu", "gercek", "yanlis+",
    "gorulmeyen", "erisilemeyen", "tarama dk"]));
  const sonuc = YAPILANDIRMA.map(kosum);
  for (const o of sonuc) {
    console.log(y1([o.ad, o.varilan.length, o.istek, o.gercek.length + o.yanlisPoz.length,
      o.gercek.length, o.yanlisPoz.length, o.gorulmeyen, o.erisilemeyen, o.dk]));
  }
  const tam = sonuc.at(-1);
  const y2 = gen([23, 7, 11, 10, 14, 16]);
  console.log("\nen genis yapilandirmada acik sinifina gore");
  console.log(y2(["acik sinifi", "acik", "erisilen", "bulunan", "erisilemeyen", "erisilip kacan"]));
  for (const s of SINIF) {
    const l = acikUc.filter((u) => u.acik.ad === s.ad);
    const e = l.filter((u) => tam.varilan.includes(u));
    const b = tam.gercek.filter((u) => u.acik.ad === s.ad).length;
    console.log(y2([s.ad, l.length, e.length, b, l.length - e.length, e.length - b]));
  }
  console.log(`\nyetenek eklemenin karsiligi: erisilen uc ${sonuc[0].varilan.length} -> ` +
    `${sonuc[1].varilan.length} -> ${tam.varilan.length}, bulunan gercek acik ` +
    `${sonuc[0].gercek.length} -> ${sonuc[1].gercek.length} -> ${tam.gercek.length}, ` +
    `tarama ${sonuc[0].dk} -> ${sonuc[1].dk} -> ${tam.dk} dakika`);
}
```

```
model (tohum 20260317): 96 uc, 28 tanesinde gercek acik; 12 uc yonetim rolu istiyor

yapilandirma            erisilen   istek   bulgu   gercek  yanlis+  gorulmeyen  erisilemeyen  tarama dk
anonim gezinme                13     278       2        2        0          26            25         14
oturumlu gezinme              50    1066       9        5        4          23            19         53
oturum + kayitli akis         84    1772      17       10        7          18             5         89

en genis yapilandirmada acik sinifina gore
acik sinifi               acik   erisilen   bulunan  erisilemeyen  erisilip kacan
yapilandirma basligi         6          3         3             3               0
yansiyan girdi               5          5         5             0               0
hata mesaji sizintisi        3          3         2             0               1
erisim denetimi              7          7         0             0               7
is akisi kurali              7          5         0             2               5

yetenek eklemenin karsiligi: erisilen uc 13 -> 50 -> 84, bulunan gercek acik 2 -> 5 -> 10, tarama 14 -> 53 -> 89 dakika
```

İlk satır bir taramanın en yaygın kurulumudur: uygulamanın adresini ver ve gezmesini bekle.
96 ucun **13'üne** varıyor. 28 açığın 25'i o anda erişilemeyen bir uçtadır ve rapor iki gerçek
bulguyla kapanır. Bu rapor yanlış değildir; eksik olduğu **hiçbir yerinde yazmaz**. "İki bulgu"
sonucunu okuyan biri yüzeyin yüzde 86'sının hiç denenmediğini bilmez.

İkinci satır tarayıcıya geçerli bir oturum ve istemci tarafında kurulan adresleri veriyor:
erişilen uç 50'ye, gerçek bulgu 5'e çıkıyor. Üçüncü satır arayüz bildirimini ve kaydedilmiş akış
sırasını ekliyor — böylece yalnız belirli bir sırayla ulaşılabilen 16 uca da varılıyor. Erişilen
uç 84, gerçek bulgu 10. **Bulunan açık sayısını üçe katlayan şey aracın yeteneği değil, ona
verilen erişimdir.** 12 yönetim ucu hiçbir satırda taranmıyor, çünkü modelde tarayıcıya yönetim
kimliği verilmemiştir; bu, kapsam kararının doğrudan yanlış negatife dönüştüğü yerdir.

İkinci tablo görülmeyen 18 açığı iki gerekçeye ayırıyor ve ayrım karar taşıyor. **Beşi
erişilemediği için görülmüyor** — üç yapılandırma başlığı ve iki akış kuralı, yönetim ucundadır.
Bunlar kapsamı genişleterek kapanabilir. **On üçü erişildiği halde görülmüyor**; kapsam
genişletmek bunlara hiçbir şey yapmaz. Erişim denetimi sınıfının yedi açığının yedisine de
ulaşılıyor ve hiçbiri bulunmuyor: bir isteğin yetkisiz olduğunu anlamak, aynı isteği **iki farklı
kimlikle** gönderip yanıtları karşılaştırmayı gerektirir; tek kimlikli bir gezinme bunu yapamaz.
İş akışı kuralı sınıfı da benzerdir — bir adımın atlanabildiğini görmek için beklenen sıranın ne
olduğunu bilmek gerekir, ve tarayıcı bunu bilmez.

Bir önceki dersle birlikte okununca tablo tamamlanıyor. Statik çözümleme yapılandırma başlığını
hiç görmüyordu; buradaki araç altısının üçünü buluyor. Buna karşılık erişim denetimi sınıfı her
iki denetimde de sıfır bulguyla kapanıyor. **İki denetimin birleşimi bile bir sınıfı boş
bırakıyor**, ve o sınıfın hangisi olduğu ancak kapsam listesi yazıldığında görünür.

## Hattaki Yerleşim

Tarama 89 model dakikası sürüyor. Bu süre hattaki yeri belirler ve yer, bulgunun geliştiriciye
kaç yapı sonra döndüğünü belirler.

```js
// yerlesim.mjs — ayni tarama hatta uc ayri yere konuyor: her yapida tam, her yapida
// yalniz degisen uc, gecelik tam. Sureler MODEL dakikasidir, olcum degildir.
import { YAPILANDIRMA, erisilen, kosum, ISTEK_DK, TOHUM } from "./yuzey.mjs";

const uretec = (t) => { let s = t >>> 0;
  return () => (s = (s * 1664525 + 1013904223) >>> 0) / 4294967296; };
const r = uretec(TOHUM + 11);
const YAPI = 60, GECE = 12;                  // gecelik kosum her 12 yapida bir
const ULASILAN = erisilen(YAPILANDIRMA.at(-1));
const TAM_DK = kosum(YAPILANDIRMA.at(-1)).dk;

// Her yapi bir kac uca dokunur. Bir acik bir yapida dogar; dogduran yapinin o uca
// dokunmus olmasi sart degildir, cunku ortak kitaplik degisikligi baska uca yansir.
const dokunan = Array.from({ length: YAPI }, () => new Set(
  Array.from({ length: 1 + Math.floor(r() * 3) }, () => ULASILAN[Math.floor(r() * ULASILAN.length)])));
const DOGAN = ULASILAN.filter((u) => u.acik && u.gorulur).map((u) => {
  const y = Math.floor(r() * YAPI);
  if (r() < 0.65) dokunan[y].add(u);          // degisiklik dogrudan o uca dokunuyor
  return { uc: u, dogus: y };
});

// Bir yerlesim, hangi yapida hangi uc kumesinin tarandigini soyler.
const YERLESIM = [
  { ad: "her yapida tam", kapi: true, tara: (y) => ULASILAN, kosar: () => true },
  { ad: "yalniz degisen uc", kapi: true, tara: (y) => [...dokunan[y]], kosar: () => true },
  { ad: "gecelik tam", kapi: false, tara: (y) => ULASILAN, kosar: (y) => y % GECE === GECE - 1 },
];

function olc(z) {
  const gorulen = new Set(), gecikme = [], blokeYapi = new Set(), yanlisYapi = new Set();
  let dk = 0;
  for (let y = 0; y < YAPI; y++) {
    if (!z.kosar(y)) continue;
    const kume = z.tara(y);
    dk += kume.reduce((a, u) => a + u.istek, 0) * ISTEK_DK;
    for (const u of kume) {
      if (u.yanlis && !gorulen.has(u)) { gorulen.add(u); yanlisYapi.add(y); }
      const d = DOGAN.find((x) => x.uc === u && x.dogus <= y && !gorulen.has(x));
      if (d) { gorulen.add(d); gecikme.push(y - d.dogus); blokeYapi.add(y); }
    }
  }
  const bulunan = gecikme.length;
  return { ad: z.ad, dk: Math.round(dk), bulunan, kacan: DOGAN.length - bulunan,
    ort: bulunan ? (gecikme.reduce((a, b) => a + b, 0) / bulunan).toFixed(1) : "-",
    enKotu: bulunan ? Math.max(...gecikme) : "-",
    bloke: z.kapi ? blokeYapi.size : 0,
    yanlisBloke: z.kapi ? [...yanlisYapi].filter((y) => !blokeYapi.has(y)).length : 0 };
}

const gen = (B) => (h) => h.map((v, j) => (j ? String(v).padStart(B[j])
  : String(v).padEnd(B[0]))).join("");
const y = gen([20, 11, 10, 9, 13, 13, 8, 14]);
console.log(`${YAPI} yapi, tam tarama ${TAM_DK} model dakikasi, ` +
  `hattaki gorunur acik ${DOGAN.length}; gecikme yapi sayisidir`);
console.log(y(["yerlesim", "toplam dk", "bulunan", "kacan", "ort. gecikme", "en kotu gec.",
  "bloke", "yanlis bloke"]));
for (const z of YERLESIM) {
  const o = olc(z);
  console.log(y([o.ad, o.dk, o.bulunan, o.kacan, o.ort, o.enKotu, o.bloke, o.yanlisBloke]));
}
const [a, b, c] = YERLESIM.map(olc);
console.log(`\ntam tarama her yapida ${a.dk} dakika alip ${a.bulunan} acigi ayni yapida ` +
  `veriyor; gecelik kosum ${c.dk} dakikaya, yani ${(100 * (1 - c.dk / a.dk)).toFixed(1)}% ` +
  `daha aza iniyor ve ayni ${c.bulunan} acigi ortalama ${c.ort} yapi sonra veriyor`);
console.log(`degisen uc taramasi ${b.dk} dakikada ${b.bulunan} acik buluyor; ` +
  `${b.kacan} acik hic taranmayan bir ucta durdugu icin bulunmuyor`);
```

```
60 yapi, tam tarama 89 model dakikasi, hattaki gorunur acik 10; gecikme yapi sayisidir
yerlesim              toplam dk   bulunan    kacan ort. gecikme en kotu gec.   bloke  yanlis bloke
her yapida tam             5316        10        0          0.0            0      10             0
yalniz degisen uc           126         7        3          2.7           19       7             6
gecelik tam                 443        10        0          6.0           11       0             0

tam tarama her yapida 5316 dakika alip 10 acigi ayni yapida veriyor; gecelik kosum 443 dakikaya, yani 91.7% daha aza iniyor ve ayni 10 acigi ortalama 6.0 yapi sonra veriyor
degisen uc taramasi 126 dakikada 7 acik buluyor; 3 acik hic taranmayan bir ucta durdugu icin bulunmuyor
```

Üç satır aynı taramayı, aynı yüzeyi ve aynı on açığı ele alıyor; ayrıldıkları yer bedeldir. Her
yapıda tam tarama on açığın onunu da doğduğu yapıda veriyor — gecikme sıfır — ve karşılığında
5 316 model dakikası alıyor. Gecelik koşum aynı on açığı aynı eksiksizlikle buluyor, hattan
yüzde 91,7 daha az dakika alıyor ve hiçbir yapıyı durdurmuyor. Ödediği şey tek bir sütunda:
ortalama 6 yapı, en kötü durumda 11 yapı gecikme. Bir açık doğduktan sonra on bir yapı boyunca
üretime gidebilir.

Üçüncü satır ucuzdur ve eksiktir. Yalnız değişen uçları taramak 126 dakikada kalıyor ama **on
açığın üçünü hiç bulmuyor**. Nedeni ikinci kod bloğunun yorumunda yazılı: bir açık her zaman
kendi ucuna dokunan değişiklikte doğmaz. Ortak kitaplıkta yapılan bir değişiklik başka bir ucun
davranışını bozar, o uç altmış yapı boyunca bir daha değişmez ve değişen uç taraması oraya hiç
uğramaz. **Değişen dosyaya bakan bir denetim, değişmeyen yerde doğan açığı göremez.**

Son sütun beklenmedik yerdedir. En ucuz yerleşim, yanlış pozitif yüzünden **en çok yapıyı
durduran** yerleşimdir: 6 yapı. Tam tarama yedi yanlış pozitifin hepsini ilk koşumda çıkarır,
hepsi bir kerede elenir ve bastırma listesine girer; değişen uç taraması aynı yedi bulguyu
haftalara yayarak birer birer çıkarır ve her biri ayrı bir yapıyı durdurur. Toplam yanlış pozitif
sayısı aynıdır, hatta bıraktığı iz farklıdır.

## Özet

- Çalışan uygulamayı tarayan araç yalnız erişebildiğini görür: anonim gezinme 96 ucun 13'üne
  varıp 2 açık bulur, oturum ve kayıtlı akış eklendiğinde 84 uca ve 10 açığa çıkar.
- Görülmeyen 18 açık iki gerekçeye ayrılır ve ayrım karar taşır: 5'i erişilemediği için (kapsam
  genişletilerek kapanır), 13'ü erişildiği halde (kapsam genişletmek etkilemez).
- Erişim denetimi sınıfının yedi açığının yedisine de ulaşılır ve hiçbiri bulunmaz; aynı sınıf
  statik çözümlemede de sıfır bulguyla kapanmıştı — iki denetimin birleşimi bile onu boş bırakır.
- Hattaki yerleşim bulunan açığı değil gecikmeyi ve bedeli değiştirir: her yapıda tam tarama
  5 316 dakika ve sıfır gecikme, gecelik koşum 443 dakika ve ortalama 6 yapı gecikme.
- Yalnız değişen uçları taramak 126 dakikaya iner ama on açığın üçünü hiç görmez, çünkü ortak
  bileşen değişikliğiyle doğan açık hiç dokunulmayan bir uçta durur.
- Yanlış pozitifin bedeli yerleşime bağlıdır: aynı yedi bulgu tam taramada bir kerede, değişen uç
  taramasında altı ayrı yapıyı durdurarak elenir.

## Sonraki Adım

İki denetim de aynı varsayımla çalıştı: taranan şey ekibin yazdığı koddur. Oysa çalışan sürecin
büyük bölümü başka yerde yazılmış bileşenlerden gelir ve bu bileşenlerin açıkları zaten bilinir —
biri onları bulmuş, kaydetmiş ve yayımlamıştır. O halde iş bulmak değil **eşleştirmektir**: elde
bir bağımlılık çizgesi ve bir kayıt listesi vardır, sorulan soru hangi kaydın hangi bileşeni
gerçekten etkilediğidir. Bu eşleştirmenin kendi yanlış pozitifi ve kendi yanlış negatifi vardır.
Sonraki ders bağımlılık çizgesini bilinen açık kataloğuyla eşleştirir, doğrudan ve geçişli
etkilenen bileşeni ayırır ve çağrılmayan bileşendeki açığın neden başka bir sıraya girdiğini
sayar.
