İçeriğe geç
academia.sh

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 node ile 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.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat