Ders 03 / 11
Güvenlik Gereksinimleri
Sınanabilirlik üç parçadan türetilir ve 20 güvenlik gereksinimi üzerinde koşturulur: 13'ü otomatik sınanabilir, 3'ü tek bir eksik parça yüzünden gözle denetlenir, 4'ü nitel yüklemi yüzünden yeniden yazılmadan hiçbir sınıfa geçemez. Beş kötüye kullanım senaryosu listeyi yüzde 40 büyütür ve gelen 8 gereksinimin 7'si engelleyici kiptedir; gözle sınamanın 40 saatlik yükü eksik parçalar yazıldığında tamamen düşer.
İçindekiler
Önceki ders önlenen 250 saatin dörtte birinin gereksinim aşamasında doğan kalemlerden geldiğini saydı, ama o kalemleri yakalayan denetimi tek satırda bıraktı: on sekiz gereksinim incelemesi, beş uyarı, üç gerçek kalem. Bir incelemenin bir kalemi nasıl yakaladığı açılmadı. Yakalayabilmesinin tek koşulu vardır: gereksinimin, karşılanıp karşılanmadığı sınanabilir biçimde yazılmış olması. “Sistem güvenli olmalıdır” satırı hiçbir incelemede hiçbir kalem üretmez, çünkü ihlal edildiğini gösterecek bir gözlem yoktur.
Bu ders sınanabilirliği bir sıfat olmaktan çıkarıp üç parçaya ayırır ve yirmi gereksinimlik bir liste üzerinde koşturur. İkinci yarıda listenin nereden geldiği sorulur: özellik listesini okuyarak yazılan gereksinimlerle, sistemin engellemesi gereken bir hedefi izleyen bir aktör düşünülerek yazılan gereksinimler aynı kümeyi vermez.
- DY12. Gereksinim listesi kurgusaldır ve
nodeile modellenir. Her gereksinim dört alanla yazılır: özne, yüklem türü, eşik, kapsam. - DY13. Sınanabilirlik verilmez, türetilir: yüklem gözlenebilirse ve hem eşik hem kapsam yazılmışsa gereksinim otomatik sınanabilir. Parçalardan biri eksikse gözle denetlenir; yüklem nitelse hiç sınanamaz.
- DY14. Yüklem türü ve kip alanları gereksinimin yazılış biçiminin kaydıdır, içeriğinin değeri değil. Sınanamaz yazılmış bir gereksinim önemsiz değildir; yalnız denetlenemez.
- DY15. Kötüye kullanım senaryosu bir aktör ve bir hedefle modellenir; hiçbir adım çalıştırılabilir biçimde verilmez. Senaryonun bir kurumun kendi sistemi dışında denenmesi yazılı yetki ve tanımlı kapsam gerektirir, aksi hem yasadışı hem de meslek dışıdır.
- DY16. Koşum sayıları ve gözle denetim dakikası model değerleridir; önceki derslerin değişiklik ve dağıtım sayılarıyla uyumludur.
Sınanabilirliğin Üç Parçası
Bir gereksinimin otomatik sınanabilmesi için üç şey gerekir: ihlalin görüleceği gözlenebilir bir yüklem, karşılandığını söyleyecek bir eşik ve nerede geçerli olduğunu söyleyen bir kapsam. Üçünden biri eksikse sınama bir insana devredilir.
// gereksinim.mjs — olcum agi yaziliminin guvenlik gereksinimleri (model) // satir: ad | ozne | yuklem turu | esik | kapsam | kip // yuklem: olay = gozlenebilir olay, durum = denetlenebilir durum, nitelik = nitel sifat // kip: saglar = sistemin yaptigi is, engeller = sistemin reddettigi is const oku = (s) => s.trim().split('\n').map((r) => { const [ad, ozne, yuklem, esik, kapsam, kip] = r.trim().split(/\s+/); return { ad, ozne, yuklem, esik, kapsam, kip }; }); export const GEREKSINIM = oku(` oturum-suresi-siniri oturum durum 30-dk abone-portali engeller hatali-giris-siniri giris-ucu olay 5-deneme abone-portali engeller aktarim-sifrelemesi dis-baglanti durum zorunlu tum-uclar saglar olcum-verisi-saklama olcum-kaydi durum 24-ay olcum-deposu saglar yetki-denetimi-kapsami okuma-ucu olay her-istek faturalama saglar gizli-deger-kaynakta kaynak-dosya durum 0-adet tum-depolar engeller kisisel-veri-gunlukte gunluk-satiri durum 0-alan tum-servisler engeller bagimlilik-yasi bagimlilik durum 180-gun tum-yapilar saglar yonetim-ucu-erisimi yonetim-ucu olay ic-ag sayac-toplama engeller yedek-sifrelemesi yedek-dosyasi durum zorunlu fatura-vt saglar istek-hiz-siniri genel-uc olay 60-istek-dk abone-portali engeller oturum-sonlandirma cikis-eylemi olay 1-istek abone-portali saglar dosya-yukleme-boyu yukleme-ucu durum 10-mb saha-uygulamasi engeller hata-mesaji-icerigi hata-yaniti durum - tum-uclar engeller denetim-kaydi-tutma yetki-degisikligi olay her-degisiklik - saglar parola-saklama-bicimi abone-kaydi durum - abone-portali saglar kimlik-dogrulama-gucu abone-girisi nitelik - abone-portali saglar arayuz-guvenligi saha-uygulamasi nitelik - - saglar veri-butunlugu olcum-kaydi nitelik - - saglar gorev-ayrimi fatura-onayi nitelik - faturalama engeller`); // Sinanabilirlik turetilir: gozlenebilir yuklem + esik + kapsam varsa otomatik sinanir. export function sinif(g) { if (g.yuklem === 'nitelik') return 'sinanamaz'; const eksik = ['esik', 'kapsam'].filter((a) => g[a] === '-'); return eksik.length === 0 ? 'otomatik' : 'gozle'; } export const eksikParca = (g) => ['esik', 'kapsam'].filter((a) => g[a] === '-'); // Kotuye kullanim senaryosu: bir aktor, sistemin engellemesi gereken bir hedefi izler. // Model olarak yazilir; hicbir adim calistirilabilir bicimde verilmez. export const SENARYO = [ ['abone-hesabini-ele-gecirme', 'dis-aktor', ['hatali-giris-siniri', 'oturum-suresi-siniri', 'oturum-sonlandirma', 'giris-bildirimi']], ['baskasinin-faturasini-okuma', 'yetkili-abone', ['yetki-denetimi-kapsami', 'kayit-kimligi-tahmini']], ['olcum-kaydini-degistirme', 'saha-personeli', ['denetim-kaydi-tutma', 'olcum-yazma-yetkisi', 'olcum-degisikligi-onayi']], ['toplu-abone-verisi-cekme', 'yetkili-abone', ['istek-hiz-siniri', 'toplu-indirme-siniri', 'disari-akan-hacim-esigi']], ['cihazi-baskasi-adina-kaydetme', 'dis-aktor', ['cihaz-kayit-dogrulamasi', 'kayit-hiz-siniri']], ]; // Senaryolardan cikan ve listede olmayan gereksinimler, ayni bicimde yazildiginda: export const YENI = oku(` giris-bildirimi basarili-giris olay her-giris abone-portali saglar kayit-kimligi-tahmini fatura-kaydi durum tahmin-edilemez faturalama engeller olcum-yazma-yetkisi olcum-kaydi olay rol-esli olcum-deposu engeller olcum-degisikligi-onayi olcum-duzeltmesi olay iki-imza olcum-deposu engeller toplu-indirme-siniri dis-aktarim durum - abone-portali engeller disari-akan-hacim-esigi dis-aktarim durum 50-mb-gun tum-uclar engeller cihaz-kayit-dogrulamasi cihaz-kaydi olay saha-onayi saha-uygulamasi engeller kayit-hiz-siniri cihaz-kaydi olay 10-kayit-saat - engeller`);
// kosum1.mjs — gereksinimler sinanabilirlige gore ayrilir; eksik parca sayilir import { GEREKSINIM, sinif, eksikParca } from './gereksinim.mjs'; const say = (l, s) => l.filter((g) => sinif(g) === s).length; console.log(`${GEREKSINIM.length} gereksinim; otomatik ${say(GEREKSINIM, 'otomatik')}, ` + `gozle ${say(GEREKSINIM, 'gozle')}, sinanamaz ${say(GEREKSINIM, 'sinanamaz')}`); console.log('\nsinif gereksinim esigi olan kapsami olan gozlenebilir yuklem'); for (const s of ['otomatik', 'gozle', 'sinanamaz']) { const l = GEREKSINIM.filter((g) => sinif(g) === s); console.log(s.padEnd(12) + String(l.length).padEnd(12) + String(l.filter((g) => g.esik !== '-').length).padEnd(13) + String(l.filter((g) => g.kapsam !== '-').length).padEnd(14) + l.filter((g) => g.yuklem !== 'nitelik').length); } console.log('\notomatige gecmeyen gereksinimler ve eksik parcalari'); for (const g of GEREKSINIM.filter((x) => sinif(x) !== 'otomatik')) console.log(' ' + g.ad.padEnd(25) + sinif(g).padEnd(12) + (g.yuklem === 'nitelik' ? 'yuklem nitel: yeniden yazilmadan sinif degistiremez' : `eksik: ${eksikParca(g).join(', ')}`)); const tekEksik = GEREKSINIM.filter((g) => sinif(g) === 'gozle' && eksikParca(g).length === 1); console.log(`\ntek parca eklenerek otomatige gecen ${tekEksik.length} gereksinim; ` + `yeniden yazim gerektiren ${say(GEREKSINIM, 'sinanamaz')} gereksinim`); console.log(`onarimdan sonra otomatik ${say(GEREKSINIM, 'otomatik') + tekEksik.length}/` + `${GEREKSINIM.length}, kalan ${GEREKSINIM.length - say(GEREKSINIM, 'otomatik') - tekEksik.length}`);
20 gereksinim; otomatik 13, gozle 3, sinanamaz 4 sinif gereksinim esigi olan kapsami olan gozlenebilir yuklem otomatik 13 13 13 13 gozle 3 1 2 3 sinanamaz 4 0 2 0 otomatige gecmeyen gereksinimler ve eksik parcalari hata-mesaji-icerigi gozle eksik: esik denetim-kaydi-tutma gozle eksik: kapsam parola-saklama-bicimi gozle eksik: esik kimlik-dogrulama-gucu sinanamaz yuklem nitel: yeniden yazilmadan sinif degistiremez arayuz-guvenligi sinanamaz yuklem nitel: yeniden yazilmadan sinif degistiremez veri-butunlugu sinanamaz yuklem nitel: yeniden yazilmadan sinif degistiremez gorev-ayrimi sinanamaz yuklem nitel: yeniden yazilmadan sinif degistiremez tek parca eklenerek otomatige gecen 3 gereksinim; yeniden yazim gerektiren 4 gereksinim onarimdan sonra otomatik 16/20, kalan 4
Yirmi gereksinimin on üçü otomatik sınanabilir, üçü gözle denetlenir, dördü hiç sınanamaz. Asıl
bilgi ikinci ve üçüncü satırların ayrımındadır. Gözle denetlenen üç gereksinimin yüklemi
gözlenebilirdir; eksik olan tek bir alandır. hata-mesaji-icerigi hata yanıtının ne
içermeyeceğini söyler ama eşik yazmaz; denetim-kaydi-tutma her yetki değişikliğinin kaydını
ister ama hangi servislerde geçerli olduğunu söylemez. İkisi de bir satır eklenerek otomatiğe
geçer.
Sınanamaz dördün durumu farklıdır. veri-butunlugu ya da arayuz-guvenligi eksik alanı olan
gereksinimler değildir; yüklemleri bir gözleme karşılık gelmez. Bunlara eşik yazmak da işe
yaramaz, çünkü neyin ölçüleceği belli değildir. Sınıf değiştirmeleri için gereken şey tamamlama
değil yeniden yazımdır: her biri, ihlalinin görüleceği bir olaya ya da duruma çevrilmelidir ve
bu çeviri genellikle tek bir gereksinimi birkaç gereksinime böler.
Ayrımın karar karşılığı nettir. Üç gereksinim için yapılacak iş bir alan doldurmaktır; dört gereksinim için yapılacak iş bir tasarım tartışmasıdır. Onarımdan sonra liste 16 otomatik ve 4 sınanamaz gereksinime ayrılır — ve bu dört gereksinim, ne kadar denetim kurulursa kurulsun kod aşamasında hiçbir uyarı üretmez.
Bir uyarı burada gereklidir: sınanabilirlik doğruluk değildir. Oturum süresi sınırının otuz dakika yazılmış olması onu otomatik sınanabilir yapar, ama otuz dakikanın doğru sayı olduğunu göstermez; yanlış bir eşik de kusursuz biçimde sınanır. Bu sınıflandırma gereksinimin denetime uygun olup olmadığını ölçer, isabetli olup olmadığını değil. İkisinin karıştırılması yaygın bir kusur üretir: eşik, sınanabilir olsun diye yazılır ve sayının nereden geldiği hiç tartışılmaz.
Kötüye Kullanım Senaryosunun Kattığı
Yukarıdaki yirmi gereksinim özellik listesi okunarak yazılmıştır: sistemin yapması gereken işlerden türetilmiştir. Kötüye kullanım senaryosu (misuse case) ters yönden başlar — bir aktör, sistemin engellemesi gereken bir hedefi izler ve bu hedefin engellenmesi için hangi gereksinimlerin gerektiği yazılır.
// kosum2.mjs — kotuye kullanim senaryolari listeyi ne kadar buyutuyor, ne bicimde import { GEREKSINIM, YENI, SENARYO, sinif } from './gereksinim.mjs'; const mevcut = new Set(GEREKSINIM.map((g) => g.ad)); console.log('senaryo aktor gereksinim listede yeni'); let ref = 0, varOlan = 0; for (const [ad, aktor, uretilen] of SENARYO) { const v = uretilen.filter((x) => mevcut.has(x)).length; ref += uretilen.length; varOlan += v; console.log(ad.padEnd(31) + aktor.padEnd(16) + String(uretilen.length).padEnd(12) + String(v).padEnd(9) + (uretilen.length - v)); } console.log(`${SENARYO.length} senaryo, ${ref} gereksinim referansi, ${varOlan} listede, ` + `${ref - varOlan} yeni; liste %${(((ref - varOlan) / GEREKSINIM.length) * 100).toFixed(0)} buyuyor`); const say = (l, s) => l.filter((g) => sinif(g) === s).length; const kip = (l, k) => l.filter((g) => g.kip === k).length; console.log('\nkume gereksinim otomatik gozle sinanamaz engeller engeller %'); for (const [ad, l] of [['ozellik listesinden', GEREKSINIM], ['senaryolardan', YENI]]) console.log(ad.padEnd(21) + String(l.length).padEnd(12) + String(say(l, 'otomatik')).padEnd(10) + String(say(l, 'gozle')).padEnd(7) + String(say(l, 'sinanamaz')).padEnd(11) + String(kip(l, 'engeller')).padEnd(10) + ((kip(l, 'engeller') / l.length) * 100).toFixed(0)); // Sinanabilirlik sinifi, gereksinimin hangi asamada sinandigini ve bedelini belirler. const DAGITIM = 60, DEGISIKLIK = 420, GOZLE_DK = 8; console.log('\nsinif sinandigi asama kosum sayisi insan dakikasi'); const tum = [...GEREKSINIM, ...YENI]; for (const [s, asama, kosum, dk] of [['otomatik', 'kod', DEGISIKLIK, 0], ['gozle', 'dagitim', DAGITIM, GOZLE_DK], ['sinanamaz', 'calisma-zamani', 0, 0]]) console.log(s.padEnd(12) + asama.padEnd(17) + String(say(tum, s) * kosum).padEnd(14) + say(tum, s) * kosum * dk); const gozleDk = say(tum, 'gozle') * DAGITIM * GOZLE_DK; console.log(`\n${tum.length} gereksinimin ${say(tum, 'otomatik')}'i kod asamasinda, ` + `${say(tum, 'gozle')}'i dagitim asamasinda sinaniyor, ${say(tum, 'sinanamaz')}'u hic sinanmiyor`); console.log(`gozle sinamanin yillik yaklasigi ${gozleDk} dakika (${(gozleDk / 60).toFixed(1)} saat); ` + `eksik parcalar yazilirsa ${(gozleDk / 60).toFixed(1)} saatin tamami dusuyor`);
senaryo aktor gereksinim listede yeni abone-hesabini-ele-gecirme dis-aktor 4 3 1 baskasinin-faturasini-okuma yetkili-abone 2 1 1 olcum-kaydini-degistirme saha-personeli 3 1 2 toplu-abone-verisi-cekme yetkili-abone 3 1 2 cihazi-baskasi-adina-kaydetme dis-aktor 2 0 2 5 senaryo, 14 gereksinim referansi, 6 listede, 8 yeni; liste %40 buyuyor kume gereksinim otomatik gozle sinanamaz engeller engeller % ozellik listesinden 20 13 3 4 9 45 senaryolardan 8 6 2 0 7 88 sinif sinandigi asama kosum sayisi insan dakikasi otomatik kod 7980 0 gozle dagitim 300 2400 sinanamaz calisma-zamani 0 0 28 gereksinimin 19'i kod asamasinda, 5'i dagitim asamasinda sinaniyor, 4'u hic sinanmiyor gozle sinamanin yillik yaklasigi 2400 dakika (40.0 saat); eksik parcalar yazilirsa 40.0 saatin tamami dusuyor
Beş senaryo on dört gereksinime dokunuyor; altısı listede zaten var, sekizi yeni. Liste yüzde kırk büyüyor ve büyümenin nerede yoğunlaştığı önemlidir: son senaryonun ürettiği iki gereksinimin ikisi de yeni. Cihaz kaydı özellik listesinde bir işlevdir ve o işlevin gereksinimleri yazılmıştır; kaydın başkası adına yapılabilmesi bir işlev değildir, bu yüzden hiçbir özellik satırından türemez.
Burada bir terim ayrımı gerekir. Bir senaryo, sistemin desteklediği bir kullanımı adım adım yazar ve o kullanımın doğru sonuç vermesini ister. Kötüye kullanım senaryosu aynı biçimi kullanır ama sahibi sistemin karşı tarafındadır ve istediği sonuç sistemin vermemesi gereken sonuçtur. İkinci tablo farkı sayıya çeviriyor: özellik listesinden gelen yirmi gereksinimin yüzde 45’i engelleyici kiptedir, senaryolardan gelen sekiz gereksinimin yüzde 88’i. Bir gereksinim listesinde engelleyici kipin payı düşükse eksik olan güvenlik dikkati değil, kaynaktır.
Senaryolardan gelen sekiz gereksinimin altısı doğrudan otomatik sınanabilir yazılmıştır. Bunun nedeni yazanın daha dikkatli olması değil, sorunun biçimidir: engellenecek bir hedef zaten bir gözlem, bir eşik ve bir kapsam ister. “Cihaz kaydı saha onayına bağlıdır” cümlesi hem ihlalin görüleceği olayı hem eşiği taşır; “arayüz güvenli olmalıdır” taşımaz.
Tablonun ölçmediği bir şey var ve bu dersin sınırı orasıdır: beş senaryonun nereden geldiği. Senaryolar birinin aklına geldiği için listededir. Altıncı bir senaryo yazılsaydı listeye kaç gereksinim daha eklenirdi sorusunun bu tabloda yanıtı yoktur, çünkü senaryo kümesinin kendisi sistematik bir yöntemle üretilmemiştir. Ölçülen şey senaryo başına kazançtır, kapsanan hedef oranı değildir; ikisi karıştırıldığında beş senaryo yazmış bir ekip işini bitirmiş sayar.
Sınanabilirliğin Aşama Karşılığı
Son tablo bu kursun ölçü eksenine bağlanıyor. Yirmi sekiz gereksinimin on dokuzu otomatik sınanabilir olduğu için kod aşamasında sınanır ve yılda 7.980 koşum üretir; bu koşumların insan maliyeti sıfırdır. Beş gereksinim yalnız gözle denetlenebildiği için sınanma noktası dağıtım aşamasına kayar: yılda 300 denetim, 2.400 dakika, yani 40 saat.
İki sayı yan yana okunmalıdır. Otomatik sınanan gereksinim, doğduğu aşamadan sonraki ilk fırsatta ve her değişiklikte sınanır; ihlali kod aşamasında yakalanır. Gözle sınanan gereksinim ancak bir dağıtım hazırlanırken bakılır ve ihlali önceki dersin tablosunda üç aşama geç yakalanan kalem olarak görünür. Sınanabilirlik bir yazım niteliği gibi durur ama sonucu doğrudan yakalama aşamasıdır.
Dört sınanamaz gereksinim üçüncü satırdadır ve hiçbir koşum üretmez. Bunlar sistemde yok sayılmaz; yalnız ihlalleri bir denetim tarafından değil, bir olay tarafından bildirilir. Önceki dersin diliyle: bu dört gereksinim, hiçbir denetimin görmediği kalem sınıfının gereksinim aşamasındaki kaynağıdır. Bir gereksinim listesinin güvenlik değeri, kaç satır içerdiğiyle değil, kaç satırının bir koşum sayısına karşılık geldiğiyle ölçülür; bu listede oran yirmi sekizde on dokuzdur.
Özet
- Otomatik sınanabilirlik üç parçadan türer: gözlenebilir yüklem, eşik, kapsam. Üçünden biri eksikse gereksinim gözle denetlenir, yüklem nitelse hiç sınanamaz.
- 20 gereksinimin 13’ü otomatik, 3’ü gözle, 4’ü sınanamazdır. Gözle denetlenen 3’ü tek bir alan eklenerek otomatiğe geçer; sınanamaz 4’ü yeniden yazılmadan sınıf değiştiremez.
- 5 kötüye kullanım senaryosu 14 gereksinime dokunur, 6’sı listede vardır, 8’i yenidir; liste yüzde 40 büyür ve tamamen yeni olan senaryo, özellik listesinde bir işlev karşılığı olmayan senaryodur.
- Özellik listesinden gelen gereksinimlerin yüzde 45’i engelleyici kiptedir, senaryolardan gelenin yüzde 88’i; engelleyici kipin düşük payı yazarın dikkatini değil listenin kaynağını gösterir.
- 28 gereksinimin 19’u kod aşamasında yılda 7.980 kez sıfır insan maliyetiyle sınanır; 5’i dağıtım aşamasında 300 denetimde 40 saat tüketir, 4’ü hiç sınanmaz.
- Eksik parçalar yazıldığında gözle sınamanın 40 saatlik yükünün tamamı düşer; sınanamaz dört gereksinim ise hiçbir denetimde uyarı üretmemeye devam eder.
Sonraki Adım
Bu ders gereksinimin nasıl yazılacağını ölçtü ve iki iş çıkardı: üç gereksinime eksik alan yazmak, dört gereksinimi yeniden düşünmek. İkisi de birinin yapması gereken işlerdir ve o birinin kim olduğu hiç sorulmadı. Eksik eşiği yazacak kişi, kötüye kullanım senaryosunu yürütecek kişi ve tasarım oturumunda gözlenemez bir yüklemi fark edecek kişi aynı kişi değildir; beş ekibin hepsinde de bulunmaz. Önceki iki ders denetimleri aşamalara dağıttı, bu ders gereksinimleri sınanabilir biçime çevirdi — ama her ikisi de yapacak yetkinliğin her ekipte hazır bulunduğunu varsaydı. Sonraki ders o varsayımı ölçer: kaç ekip var, kaçında güvenlik gözü olan biri var, bir kişinin kapasitesi kaç ekibe yetiyor ve kapasite yetmediğinde kaç inceleme güvenlik gözü olmadan geçiyor.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.