---
title: 'Statik Uygulama Güvenlik Testi'
source: 'https://academia.sh/tr/kurslar/guvenlik-otomasyonu/statik-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'
---

# Statik Uygulama Güvenlik Testi

720 kod noktasında statik çözümlemenin üç sayısı: eşik 0,20'den 0,80'e çıkarken bulgu 418'den 56'ya, yanlış pozitif 317'den 6'ya iner ama gerçek bulgu da 101'den 50'ye düşer; 62 açık nokta eşikten bağımsız olarak aracın görüş alanı dışındadır. Aynı kuyruk geliştiriciye verildiğinde 0,20 eşiği 101 gerçek bulgunun 80'ini hiç açılmadan kapattırır, 0,65 eşiği 72 gerçek bulgunun 65'ini inceletir; gerçek bulgu başına inceleme süresi 26,9 dakikadan 10,2 dakikaya iner.

Güvenli Kodlama kursu on yedi ölçüm boyunca aynı soruyu sordu: bir savunma kalıbı kaç noktayı
kendiliğinden kapatıyor, kaç nokta dışarıda kalıyor. Bütün o envanterler elle kurulmuştu ve kod
değiştikçe eskiyen tek bir fotoğraftı. Bu kurs aynı soruyu her değişiklikte soran düzeneği ölçer:
hatta koşan otomatik denetimler.

Bir denetimin değeri "kaç bulgu çıkardığı" değildir. Üç sayı birlikte okunur: kaç kalem tarandı ve
kaç bulgu çıktı, bulguların kaçı gerçek ve kaçı yanlış pozitif, gerçekte var olup **hiç
görülmeyen** kaç kalem kaldı. Üçüncüsü yazılmadıkça ilk ikisi bir güvence değil bir yanılsamadır.
Dördüncü bir sütun da vardır ve o hattadır: denetim kaç dakika ekliyor, kaç yapıyı durduruyor,
kaçını yanlış yere durduruyor. Bu ders kursun ölçü birimini bu dört sütunla kurar ve statik
çözümlemeyi örnek alır.

- **OD1.** Kod tabanı üç depodur: abone portalı, sayaç alım servisi ve ikisinin kullandığı ortak
  kitaplık. Depolar da kod tabanı da **kurgudur**; aşağıdaki sayılar bir modelin çıktısıdır.
- **OD2.** Bir **nokta**, bir aracın kural yazabildiği kod konumudur. Her noktanın gerçekte açık
  olup olmadığı modelin doğrusudur; araç bunu bilmez.
- **OD3. Statik uygulama güvenlik testi** (static application security testing), kaynak kodu
  çalıştırmadan çözümleyip açık adayı üreten denetimdir. Araç her gördüğü noktaya bir **güven
  puanı** verir; **eşik**, bulgu olarak raporlanacak en küçük puandır.
- **OD4.** Her nokta sınıfının bir **kapsam** değeri vardır: aracın o sınıfta hiç aday üretebilme
  olasılığı. Kapsamı sıfır olan sınıf **eşikten bağımsız** olarak görülmez; bu, aracın **görüş
  alanı dışıdır**.
- **OD5.** Üç sayı ayrı yazılır: **gerçek bulgu**, **yanlış pozitif** (bulgu olup açık olmayan) ve
  **görülmeyen** kalem (açık olup bulgu olmayan).
- **OD6.** Hat bedeli model dakikasıyla verilir: yapı başına 4 dakika tarama, yanlış yere bloke
  edilen yapı başına 25 dakika insan zamanı, bulgu başına 6 dakika inceleme. Süreler **veridir**,
  bu sayfada yapılmış bir ölçüm değildir.

## Eşik Üç Sayıyı Birlikte Oynatır

```js
// tarama.mjs — statik cozumleme aracinin bulgu kumesi; esik degistikce gercek,
// yanlis pozitif ve gorulmeyen kalem birlikte olculur. MODELDIR, kod tabani kurgudur.
export const TOHUM = 20260311, NOKTA = 720, YAPI = 140, TARAMA_DK = 4, YANLIS_DK = 25;
export const INCELEME_DK = 6;
const uretec = (t) => { let s = t >>> 0;
  return () => (s = (s * 1664525 + 1013904223) >>> 0) / 4294967296; };
const r = uretec(TOHUM);

// kapsam = aracin o sinifta hic aday uretebilme olasiligi; 0 olan sinif esikten
// bagimsiz gorulmez, bu aracin gorus alani disidir. ayirt = puanin ayirt etme gucu.
export const SINIF = [
  { ad: "dizgi birlestirme", pay: 0.26, acik: 0.22, kapsam: 0.95, ayirt: 0.62 },
  { ad: "dis komut cagrisi", pay: 0.08, acik: 0.35, kapsam: 0.90, ayirt: 0.55 },
  { ad: "cozumleme sinirli", pay: 0.14, acik: 0.20, kapsam: 0.40, ayirt: 0.30 },
  { ad: "kriptografi kullanimi", pay: 0.12, acik: 0.28, kapsam: 0.85, ayirt: 0.70 },
  { ad: "yapilandirma sabiti", pay: 0.22, acik: 0.10, kapsam: 0.80, ayirt: 0.25 },
  { ad: "erisim denetimi", pay: 0.18, acik: 0.30, kapsam: 0.00, ayirt: 0.00 },
];
const sinifSec = (u) => { let t = 0;
  for (const s of SINIF) { t += s.pay; if (u < t) return s; } return SINIF.at(-1); };

// Her nokta bir kod konumudur; acik alani modelin dogrusudur, arac onu bilmez.
// Gorulen noktaya bir puan verilir: acik noktalar yukari, temiz noktalar asagi kayar.
export const NOKTALAR = Array.from({ length: NOKTA }, (_, i) => {
  const s = sinifSec(r());
  const acik = r() < s.acik, gordu = r() < s.kapsam, taban = (r() + r()) / 2;
  const puan = !gordu ? null
    : acik ? Math.min(0.99, taban + s.ayirt * 0.45) : Math.max(0.01, taban - s.ayirt * 0.20);
  return { i, sinif: s.ad, acik, puan, yapi: Math.floor(r() * YAPI) };
});

export function esikte(t) {
  const bulgu = NOKTALAR.filter((n) => n.puan !== null && n.puan >= t);
  const gercek = bulgu.filter((n) => n.acik), yanlis = bulgu.filter((n) => !n.acik);
  const kacan = NOKTALAR.filter((n) => n.acik && !bulgu.includes(n));
  const korNokta = kacan.filter((n) => n.puan === null);
  const bulguluYapi = new Set(bulgu.map((n) => n.yapi));
  const gercekliYapi = new Set(gercek.map((n) => n.yapi));
  const yanlisBloke = [...bulguluYapi].filter((y) => !gercekliYapi.has(y)).length;
  return { esik: t, bulgu, gercek: gercek.length, yanlis: yanlis.length, kacan: kacan.length,
    korNokta: korNokta.length, bloke: bulguluYapi.size, yanlisBloke,
    dk: YAPI * TARAMA_DK + yanlisBloke * YANLIS_DK };
}

export const ESIKLER = [0.20, 0.35, 0.50, 0.65, 0.80];
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 ACIK = NOKTALAR.filter((n) => n.acik).length;
  const KOR = NOKTALAR.filter((n) => n.acik && n.puan === null).length;
  console.log(`model (tohum ${TOHUM}): ${NOKTA} nokta, ${ACIK} tanesi gercekte acik, ` +
    `${YAPI} yapi; ${KOR} acik nokta aracin gorus alani disinda`);
  const y1 = gen([7, 8, 9, 9, 12, 11, 8, 14, 9]);
  console.log("\n" + y1(["esik", "bulgu", "gercek", "yanlis+", "gorulmeyen", "gorus disi",
    "bloke", "yanlis bloke", "hat dk"]));
  for (const t of ESIKLER) {
    const o = esikte(t);
    console.log(y1([t.toFixed(2), o.bulgu.length, o.gercek, o.yanlis, o.kacan, o.korNokta,
      o.bloke, o.yanlisBloke, o.dk]));
  }
  const o = esikte(0.50);
  const y2 = gen([22, 8, 7, 8, 9, 9, 12]);
  console.log("\nesik 0.50'de sinif dagilimi");
  console.log(y2(["nokta sinifi", "nokta", "acik", "bulgu", "gercek", "yanlis+", "gorulmeyen"]));
  for (const s of SINIF) {
    const l = NOKTALAR.filter((n) => n.sinif === s.ad);
    const b = o.bulgu.filter((n) => n.sinif === s.ad);
    console.log(y2([s.ad, l.length, l.filter((n) => n.acik).length, b.length,
      b.filter((n) => n.acik).length, b.filter((n) => !n.acik).length,
      l.filter((n) => n.acik).length - b.filter((n) => n.acik).length]));
  }
}
```

```
model (tohum 20260311): 720 nokta, 163 tanesi gercekte acik, 140 yapi; 62 acik nokta aracin gorus alani disinda

esik      bulgu   gercek  yanlis+  gorulmeyen gorus disi   bloke  yanlis bloke   hat dk
0.20        418      101      317          62         62     132            61     2085
0.35        332       99      233          64         62     130            59     2035
0.50        225       92      133          71         62     112            46     1710
0.65        120       72       48          91         62      80            21     1085
0.80         56       50        6         113         62      47             4      660

esik 0.50'de sinif dagilimi
nokta sinifi             nokta   acik   bulgu   gercek  yanlis+  gorulmeyen
dizgi birlestirme          199     47      94       41       53           6
dis komut cagrisi           52     16      24       15        9           1
cozumleme sinirli           99     23      18        8       10          15
kriptografi kullanimi       91     22      39       19       20           3
yapilandirma sabiti        144     18      50        9       41           9
erisim denetimi            135     37       0        0        0          37
```

İlk tablo eşiğin tek bir düğme olmadığını gösteriyor. 0,20'de araç 418 bulgu çıkarıyor ve
bunların 317'si yanlış pozitif — raporun yüzde 75,8'i. Eşik 0,80'e çekildiğinde yanlış pozitif 6'ya
iniyor, ama aynı hareket gerçek bulguyu da 101'den 50'ye düşürüyor. **İki sayı aynı yöne gider;
biri iyileşirken diğeri bozulur.** Eşiği "gürültüyü azaltmak için" yükseltmek, aynı işlemle
gerçek bulguların yarısını rapordan silmektir.

Beşinci sütun eşiğin hiç dokunamadığı yeri yazıyor. 163 açık noktanın 62'si her eşikte
görülmüyor; bu sayı 0,20'de de 0,80'de de aynıdır. Bunlar aracın **yanlış negatif**leridir ve
kaynağı bir ayar hatası değil, çözümlemenin yapısıdır. Sınıf tablosu nedeni gösteriyor: erişim
denetimi sınıfında 135 nokta ve 37 gerçek açık var, bulgu sayısı sıfır. Bir isteğin çağıranın
yetkisine uygun olup olmadığı kaynak metninden okunamaz, çünkü kural kodda değil iş tanımındadır.
Çözümlemesi sınırlı sınıf da benzerdir: 23 açığın 15'i görülmüyor, çünkü çağrı hedefi çalışma
zamanında belirlenen kod aracın izleyemediği bir kenardır. **Bir tarama raporunda "sıfır bulgu"
yazan sınıf, ya temiz olan ya da hiç bakılmayan sınıftır; ikisini ayıran tek şey kapsam
listesidir.**

Son üç sütun hattı ölçüyor. 140 yapının 132'si 0,20 eşiğinde duruyor ve 61'i **yalnız yanlış
pozitif yüzünden** duruyor: hattın neredeyse yarısı boşuna bloke. Bu 61 durdurma model
hesabında 1 525 dakika insan zamanına karşılık geliyor ve toplam hat bedelini 2 085 dakikaya
çıkarıyor. Eşik 0,65'e alındığında yanlış bloke 21'e, toplam 1 085 dakikaya iniyor. Aynı tabloda
gerçek bulgunun 101'den 72'ye indiği yazılıdır — kazanç bedava değildir.

Sınıf tablosu bir ayrım daha yazıyor. Yapılandırma sabiti sınıfı 144 noktayla ikinci büyük
kaynaktır ama yalnız 18'i gerçekten açıktır; 0,50 eşiğinde 50 bulgu üretir ve bunların 41'i
yanlış pozitiftir. Kriptografi kullanımı sınıfı 91 noktayla daha küçüktür ve 39 bulgunun 19'u
gerçektir. İki sınıfın eşiği ayrı ayarlanabilseydi rapor aynı gerçek bulguyu çok daha az
gürültüyle verirdi; tek bir küresel eşik, en gürültülü sınıfın davranışını bütün rapora taşır.

Bu yüzden bir taramanın çıktısı yalnız bulgu listesi değildir. Yanında iki kayıt daha durmalıdır:
hangi nokta sınıflarının tarandığı ve hangi eşikle raporlandığı. Birincisi olmadan sıfır bulgunun
anlamı belirsizdir, ikincisi olmadan iki koşumun sayıları karşılaştırılamaz. Aynı kod tabanında
eşiği 0,80'den 0,50'ye indiren bir koşum bulguyu 56'dan 225'e çıkarır; kodda hiçbir şey
değişmemiştir.

## Bulgu Yorgunluğu

Buraya kadar sayılan her şey aracın çıktısıdır. Bulgu bir işe yarayacaksa bir kişinin onu açması
gerekir, ve o kişinin dikkati sınırsız değildir.

```js
// yorgunluk.mjs — ayni bulgu kumesi gelistiriciye gidiyor: her yanlis pozitif
// inceleme olasiligini dusurur, gercek bulgu geri yukseltir. MODELDIR.
import { esikte, ESIKLER, INCELEME_DK, TOHUM } from "./tarama.mjs";

const uretec = (t) => { let s = t >>> 0;
  return () => (s = (s * 1664525 + 1013904223) >>> 0) / 4294967296; };

// Guven, gelistiricinin siradaki bulguya bakma olasiligidir. Bakilmayan bulgu
// hicbir bilgi vermez, bu yuzden dusen guven kendini onarmaz.
function kuyruk(t) {
  const r = uretec(TOHUM + 7);
  const liste = esikte(t).bulgu.slice().sort((a, b) => a.yapi - b.yapi || a.i - b.i);
  let guven = 1, incelenen = 0, incelenenGercek = 0, atlananGercek = 0;
  for (const n of liste) {
    if (r() >= guven) { if (n.acik) atlananGercek++; continue; }
    incelenen++;
    if (n.acik) { incelenenGercek++; guven = Math.min(1, guven + 0.10); }
    else { guven = Math.max(0.10, guven - 0.055); }
  }
  return { bulgu: liste.length, gercek: liste.filter((n) => n.acik).length,
    incelenen, incelenenGercek, atlananGercek, guven, dk: incelenen * INCELEME_DK };
}

const gen = (B) => (h) => h.map((v, j) => (j ? String(v).padStart(B[j])
  : String(v).padEnd(B[0]))).join("");
const y = gen([7, 8, 9, 11, 12, 12, 11, 9, 11]);
console.log(`bulgu basina inceleme ${INCELEME_DK} model dakikasi; guven 1.00'den baslar`);
console.log(y(["esik", "bulgu", "gercek", "incelenen", "inc. gercek", "atlanan g.",
  "son guven", "inc. dk", "dk/gercek"]));
for (const t of ESIKLER) {
  const o = kuyruk(t);
  console.log(y([t.toFixed(2), o.bulgu, o.gercek, o.incelenen, o.incelenenGercek,
    o.atlananGercek, o.guven.toFixed(2), o.dk,
    o.incelenenGercek ? (o.dk / o.incelenenGercek).toFixed(1) : "-"]));
}
const dusuk = kuyruk(0.20), orta = kuyruk(0.65);
console.log(`\nesik 0.20 esik 0.65'ten ${dusuk.gercek - orta.gercek} fazla gercek bulgu ` +
  `cikariyor ama ${orta.incelenenGercek - dusuk.incelenenGercek} tanesi daha az inceleniyor`);
console.log(`0.20'de ${dusuk.atlananGercek} gercek bulgu hic acilmadan kapaniyor, ` +
  `0.65'te ${orta.atlananGercek}; gercek bulgu basina inceleme suresi ` +
  `${(dusuk.dk / dusuk.incelenenGercek).toFixed(1)} dakikadan ` +
  `${(orta.dk / orta.incelenenGercek).toFixed(1)} dakikaya iniyor`);
```

```
bulgu basina inceleme 6 model dakikasi; guven 1.00'den baslar
esik      bulgu   gercek  incelenen inc. gercek  atlanan g.  son guven  inc. dk  dk/gercek
0.20        418      101         94          21          80       0.10      564       26.9
0.35        332       99        119          36          63       0.18      714       19.8
0.50        225       92        198          82          10       0.93     1188       14.5
0.65        120       72        110          65           7       0.94      660       10.2
0.80         56       50         55          49           1       1.00      330        6.7

esik 0.20 esik 0.65'ten 29 fazla gercek bulgu cikariyor ama 44 tanesi daha az inceleniyor
0.20'de 80 gercek bulgu hic acilmadan kapaniyor, 0.65'te 7; gercek bulgu basina inceleme suresi 26.9 dakikadan 10.2 dakikaya iniyor
```

Tablo, ilk tablodaki sıralamayı tersine çeviriyor. Araç ölçüsüyle 0,20 en iyi eşiktir: 101 gerçek
bulgu, hepsinden fazlası. Kuyruk ölçüsüyle en kötü eşiktir: o 101 bulgunun yalnız **21'i
inceleniyor**, 80'i hiç açılmadan kapanıyor. 0,65 eşiği 29 gerçek bulgu daha az çıkarıyor ama
44 gerçek bulgu daha fazla inceletiyor. Bulgu sayısı ile kapatılan açık sayısı aynı yönde
gitmiyor.

Mekanizma güven sütununda yazılı. Güven, bir sonraki bulguya bakma olasılığıdır; her yanlış
pozitif onu 0,055 düşürür, her gerçek bulgu 0,10 yükseltir. 0,20 eşiğinde kuyruğun başındaki
yoğun yanlış pozitif dizisi güveni ilk yüz bulguda tabana indiriyor ve orada bırakıyor: son güven
0,10. Bir kez oraya inildiğinde onarım da durur, çünkü **bakılmayan bulgu hiçbir bilgi vermez** —
gerçek bulgu güveni ancak açıldığında yükseltebilir. **Bulgu yorgunluğu** (alert fatigue) bu
kilitlenmenin adıdır ve tek bir bulgu üzerinde görülmez; kuyruğun tamamı üzerinde ortaya çıkar.

Son sütun aynı olguyu maliyet tarafından yazıyor. 0,20'de gerçek bulgu başına 26,9 dakika
inceleniyor, 0,80'de 6,7 dakika. Aradaki fark yanlış pozitiflerin açılıp kapatılmasına giden
zamandır. Bu ders eşiğin doğru değerini vermez, çünkü doğru değer kod tabanına ve ekibin
kapasitesine bağlıdır. Verdiği şey karar kuralıdır: bir eşik **üç sayıyla birlikte** raporlanır ve
dördüncü olarak kuyruğun ne kadarının gerçekten açıldığı ölçülür. Bu dört sayı olmadan eşik
değiştirmek, hangi sütunun ödediği bilinmeden yapılan bir takastır.

## Özet

- Bir denetim üç sayıyla ölçülür: kaç bulgu çıktı, kaçı gerçek ve kaçı yanlış pozitif, gerçekte
  var olup hiç görülmeyen kaç kalem kaldı. Dördüncü sütun hattadır: eklenen dakika ve bloke yapı.
- Eşik iki sayıyı aynı yöne oynatır: 0,20'den 0,80'e çıkarken yanlış pozitif 317'den 6'ya inerken
  gerçek bulgu da 101'den 50'ye düşer.
- 163 açık noktanın 62'si her eşikte görülmez; erişim denetimi sınıfının 37 açığının hiçbiri
  raporda yoktur, çünkü kural kaynak metninde değil iş tanımındadır.
- Hat bedeli eşiğe bağlıdır: 0,20'de 140 yapının 61'i yalnız yanlış pozitif yüzünden bloke olur ve
  toplam 2 085 dakika, 0,65'te 21 yapı ve 1 085 dakika.
- Bulgu sayısı ile kapatılan açık sayısı aynı yönde gitmez: 0,20 eşiği 101 gerçek bulgunun 21'ini
  inceletirken 0,65 eşiği 72'nin 65'ini inceletir, çünkü yoğun yanlış pozitif güveni tabana
  indirir ve bakılmayan bulgu onu geri yükseltemez.

## Sonraki Adım

Bu dersin bütün ölçümü kaynak metni üzerindeydi: aracın gördüğü şey dosyalardaki kod
konumlarıydı ve görüş alanı dışında kalan 62 açık noktanın büyük bölümü, kararı çalışma zamanında
verilen noktalardı. O noktalara ulaşmanın bir yolu var: uygulamayı ayağa kaldırıp dışarıdan
istemek. Ama bu kez tarayıcının önünde başka bir sınır durur — çalışan bir uygulamanın her ucu
istekle erişilebilir değildir. Bir bölümü oturum açmadan yanıt vermez, bir bölümü yalnız belirli
bir sıra izlendiğinde ortaya çıkar. Sonraki ders çalışan uygulamayı tarayan aracın **erişebildiği
ve erişemediği yüzeyi** ayırır ve aynı üç sayıyı bu kez uç kümesi üzerinde verir.
