Ders 12 / 22
Kimlik Doğrulama Günlükleri
Oturum açma, yetki isteği ve oturum kapanışı olaylarının izi: kimlik doğrulama ile yetkilendirmenin ayrımı, metin eşleyen süzgeçlerin kaç satırda yanıldığı ve saldırının en önemli satırının neden başarısız değil başarılı satır olduğu.
İçindekiler
Önceki ders bir kaydın nereden geldiğini ve hangi adrese yazıldığını kurdu; ölçtüğü şey, tek bir birim dosyasına bakan tanının altı denemenin beşinde yanılmasıydı. Orada sorulan soru “hangi birim bozuldu” sorusuydu. Bir makinede aynı sistem günlüğüne düşen ama bambaşka bir soruya hizmet eden ikinci bir olay kümesi vardır: kim girdi, ne istedi, verildi mi.
Bu ders o kümeyi ele alır. Kayıtların kendisi sıradandır; zor olan, onlardan çıkarılan tanıdır. Bir arıza incelemesinde günlük satırının doğruluğu tartışılmaz, ama bir güvenlik incelemesinde satırın hangi olayı temsil ettiği tartışılır ve iki farklı olay çoğunlukla birbirine çok benzeyen iki satır üretir.
Farkın bir nedeni de kaydı yazan tarafın konumudur. Servis günlüklerini yazan program kendi iç durumunu bilir; ne yaptığını doğru anlatabilir. Kimlik olaylarını yazan taraf ise karşısındakini bilmez: gelen isteğin arkasında kimin durduğu, tam olarak ölçmeye çalıştığı şeydir. Bu yüzden kimlik günlüğü bir gözlem kaydı değil, bir karar kaydıdır: sistemin verdiği kararı yazar, kararın doğru olup olmadığını yazmaz.
İki Ayrı Soru, Tek Dosya
Kimlik doğrulama (authentication) bir tek soruya yanıt verir: bu istek gerçekten iddia ettiği hesaba mı ait. Yanıt bir parolayla, bir anahtarla ya da başka bir kanıtla verilir ve sonucu ikilidir. Yetkilendirme (authorization) ise ondan sonra gelir: kimliği kanıtlanmış hesabın istediği işlemi yapmaya hakkı var mı.
Ayrım önemlidir, çünkü iki başarısızlık türü bambaşka şeyler anlatır. Kimlik doğrulama başarısızlığı “bu kişi olduğunu kanıtlayamadı” demektir; parolayı yanlış yazan bir kullanıcı da, parola deneyen bir saldırgan da bu satırı üretir. Yetkilendirme başarısızlığı ise “bu kişi olduğunu kanıtladı, ama bu işlemi yapamaz” demektir; burada hesabın kime ait olduğu şüpheli değildir, istenen iş fazladır. Birinci satır kimliğin dışarıdan zorlandığını, ikinci satır içerideki bir yapılandırma eksiğini ya da bir yetki aşımı denemesini gösterir.
Üçüncü bir olay türü daha vardır: oturum açılışı ve kapanışı. Oturum, kimlik doğrulamanın kabul edilmesinden sonra başlayan ve kapanana kadar süren bağlamdır. Kapanış kaydının eksik olması olağan bir durumdur: bağlantı koparsa, süreç zorla sonlandırılırsa ya da makine yeniden başlarsa açılış kaydı vardır, kapanış kaydı yoktur. Açık oturum sayısını günlükten çıkaran bir tanı, bu yüzden gerçekten açık olan oturum sayısından fazla sayar.
Bu kayıtların değiştirilmeye karşı korunması, imzalanması ve bağımsız bir denetim izine dönüştürülmesi ayrı bir konudur ve Yönetişim, Risk ve Uyumluluk kursunda ele alınmıştır; burada tekrarlanmaz. Buradaki soru daha dar: makinenin kendi kimlik günlüğünde duran satırlardan hangi tanı çıkar.
Yetki Yükseltmenin Bıraktığı İz
Bir hesabın kendi yetkisinin ötesinde bir iş yapması için araya bir yükseltme adımı girer: istek yapılır, kural kümesine bakılır, kabul ya da ret kaydı yazılır. Kaydın taşıdığı alanlar isteği yapan hesap, hedeflenen kimlik ve çalıştırılmak istenen komuttur.
Bu satırın söylemediği şey nedendir. Kabul kaydı, kuralın hangi maddesinin isteği kabul ettiğini yazmaz; ret kaydı da hangi maddenin engellediğini yazmaz. İki farklı yapılandırma hatası — kuralın hiç bulunmaması ile kuralın bulunup daha dar bir kuralla gölgelenmesi — aynı ret satırını üretir. Tanı bu iki durumu ayırmak isterse günlüğe değil yapılandırmaya bakmak zorundadır. Günlük olayın olduğunu söyler; niçin olduğunu söylemez.
İkinci eksik komutun kendisidir. Kayıt çalıştırılmak istenen komutu yazar, ama komutun ne yaptığını yazmaz. Bir kabuk çağıran tek satırlık bir komut kaydedilir; o kabukta yapılan işler kaydedilmez, çünkü onlar ayrı bir sürecin içindedir. Kabuk Programlama kursunda kurulan alt süreç modeli burada bir günlük sınırına dönüşür: yükseltme kaydı bir kapıyı gösterir, kapının ardında yapılanları değil.
Üçüncü eksik zamandır. Yükseltilmiş yetki çoğunlukla bir süre boyunca yeniden sorulmadan geçerli kalır. O süre içinde yapılan ikinci ve üçüncü istekler yeni bir kimlik doğrulama kaydı üretmez. Günlükten “hesap kaç kez kimliğini kanıtladı” sorusunun yanıtı okunabilir; “hesap kaç kez yükseltilmiş yetkiyle iş yaptı” sorusunun yanıtı okunamaz. İki soruyu aynı sayıyla yanıtlamak, bu dersin ölçtüğü türden bir yanlış tanıdır.
Satırlar Nasıl Görünür
Kimlik olayları çoğunlukla ayrı bir dosyada toplanır; dosyanın adı dağıtıma göre değişir ve aynı satırlar sistem günlüğünde de bulunabilir. Aşağıdaki döküm örnektir ve çalıştırılmamıştır.
# ornek dokum , calistirilmis degildir [ 301.020] sshd[1207]: giris basarisiz: hesap yedek, kaynak uzak [ 301.900] sshd[1207]: giris basarisiz: hesap yedek, kaynak uzak [ 318.400] sudo[1214]: yetki dogrulama basarisiz: hesap uygulama, komut yedek-gorevi [ 342.000] sshd[1207]: giris basarili: hesap yedek, kaynak uzak
Dört satırın üçü “basarisiz” sözcüğünü taşır, ama üçü aynı olayı anlatmaz. İlk ikisi uzak bir kaynaktan gelen kimlik doğrulama başarısızlığıdır; üçüncüsü yerel bir hesabın yetkisi olmayan bir komutu istemesidir. Metin eşleyen bir süzgeç üçünü de aynı kovaya atar.
# ornek dokum , calistirilmis degildir $ grep basarisiz /var/log/auth.log [ 301.020] sshd[1207]: giris basarisiz: hesap yedek, kaynak uzak [ 318.400] sudo[1214]: yetki dogrulama basarisiz: hesap uygulama, komut yedek-gorevi
Alan bilen bir sorgu ise olayın türünü, hesabı ve kaynağı ayrı ayrı kısıtlayabilir; önceki derste kurulan yapılandırılmış kayıt ile düz metin ayrımının pratik karşılığı budur.
Metin süzgecinin bir kırılganlığı daha vardır. Süzgeç, kaydı yazan programın seçtiği sözcüğe bağımlıdır; aynı olayı başka bir sözcükle yazan bir program süzgeçten sessizce düşer. İki program aynı makinede aynı olayı iki farklı ifadeyle yazıyorsa, tek bir örüntüyle arayan operatör birinin kayıtlarını hiç görmez ve o eksikliği fark ettiren bir uyarı da oluşmaz. Alan üzerinden yapılan sorgu bu bağımlılığı ortadan kaldırmaz, ama bağımlılığı metnin gövdesinden alan adına taşır ve alan adı, ileti metnine göre çok daha yavaş değişir.
Ölçülen Şey: Üç Süzgeç ve Bir Alan
Ölçü, ortak tanımın üretecinin üzerine kurulmuş bir kimlik günlüğüyle yapılır. Kurgunun varsayımları: makinede beş hesap bulunur (GN5); arka planda 560 olay üretilir ve olay türlerinin ağırlıkları sabittir (GN6); saldırı üç yüzüncü saniyede başlar, kırk başarısız uzak giriş ve iki saniye sonra bir başarılı uzak giriş içerir (GN7); alan bilen süzgecin eşiği on başarısız giriş, penceresi altmış saniyedir (GN8).
Kâhin, kurguya yerleştirilen saldırıdır: kırk başarısız satır ve dizinin sonundaki bir başarılı uzak giriş — toplam 41 satır. Araç çıktısı, dört ayrı süzgecin döndürdüğü satır kümesidir. Yanlış tanı, boşuna okunan satır ile hiç okunmayan saldırı satırının toplamıdır.
TOHUM = 20260218 DONEM = 600 # gozlem penceresi: 600 saniye def uretec(tohum): d = tohum def sonraki(n): nonlocal d d = (d * 1103515245 + 12345) % 2147483648 return d % n return sonraki HESAP = ("kok", "uygulama", "yedek", "izleme", "operator") # GN5 def kimlik_gunlugu(tohum=TOHUM, arka=560, deneme=40, hedef="yedek", bas=300): """GN6 arka plan olaylari + GN7 KAHIN: bas saniyesinde baslayan parola deneme dizisi ve sonundaki BASARILI giris. Saldiri satirlari isaretlidir.""" r = uretec(tohum) kayit = [] for _ in range(arka): t = r(100) h = HESAP[r(len(HESAP))] uzak = r(10) < 4 if t < 6: tur, sonuc = "giris", "basarisiz" # parola yanlis yazildi elif t < 18: tur, sonuc = "yetki", "basarisiz" # kimlik dogru , yetki yok elif t < 26: tur, sonuc = "oturum", "kapandi" elif t < 34: tur, sonuc = "yetki", "basarili" else: tur, sonuc = "giris", "basarili" kayit.append({"saniye": r(DONEM), "hesap": h, "tur": tur, "sonuc": sonuc, "kaynak": "uzak" if uzak else "yerel", "saldiri": False}) for i in range(deneme): kayit.append({"saniye": bas + i, "hesap": hedef, "tur": "giris", "sonuc": "basarisiz", "kaynak": "uzak", "saldiri": True}) kayit.append({"saniye": bas + deneme + 2, "hesap": hedef, "tur": "giris", "sonuc": "basarili", "kaynak": "uzak", "saldiri": True}) kayit.sort(key=lambda k: k["saniye"]) return kayit def hesap_penceresi(kayitlar, esik=10, pencere=60): """GN8 alan bilen suzgec: bir hesabin pencere icinde esik kadar basarisiz uzak girisi ve o kumeden sonraki pencerede yer alan basarili uzak girisler.""" secili = set() for h in HESAP: d = [i for i, k in enumerate(kayitlar) if k["hesap"] == h and k["tur"] == "giris" and k["sonuc"] == "basarisiz" and k["kaynak"] == "uzak"] oburu = set() for i in d: pen = [j for j in d if 0 <= kayitlar[j]["saniye"] - kayitlar[i]["saniye"] <= pencere] if len(pen) >= esik: oburu.update(pen) if not oburu: continue son = max(kayitlar[j]["saniye"] for j in oburu) oburu.update(j for j, k in enumerate(kayitlar) if k["hesap"] == h and k["tur"] == "giris" and k["sonuc"] == "basarili" and k["kaynak"] == "uzak" and 0 <= k["saniye"] - son <= pencere) secili |= oburu return [kayitlar[j] for j in sorted(secili)] def olc(kayitlar, eslesen): """Yanlis tani = bosuna okunan satir + hic okunmayan saldiri satiri.""" gercek = sum(1 for k in kayitlar if k["saldiri"]) dogru = sum(1 for k in eslesen if k["saldiri"]) giris = sum(1 for k in eslesen if k["saldiri"] and k["sonuc"] == "basarili") return {"eslesen": len(eslesen), "dogru": dogru, "girisi_buldu": giris, "yanlis_tani": (len(eslesen) - dogru) + (gercek - dogru)} SUZGEC = ( ("basarisiz", lambda k: k["sonuc"] == "basarisiz"), ("giris basarisiz", lambda k: k["tur"] == "giris" and k["sonuc"] == "basarisiz"), ("uzak giris basarisiz", lambda k: k["tur"] == "giris" and k["sonuc"] == "basarisiz" and k["kaynak"] == "uzak"), ) for tohum in (TOHUM, 20260219): K = kimlik_gunlugu(tohum) print("tohum", tohum, "| satir", len(K), "| saldiri satiri", sum(1 for k in K if k["saldiri"])) for ad, f in SUZGEC: print(f" {ad:22s}", olc(K, [k for k in K if f(k)])) print(f" {'hesap penceresi':22s}", olc(K, hesap_penceresi(K)))
tohum 20260218 | satir 601 | saldiri satiri 41
basarisiz {'eslesen': 153, 'dogru': 40, 'girisi_buldu': 0, 'yanlis_tani': 114}
giris basarisiz {'eslesen': 67, 'dogru': 40, 'girisi_buldu': 0, 'yanlis_tani': 28}
uzak giris basarisiz {'eslesen': 51, 'dogru': 40, 'girisi_buldu': 0, 'yanlis_tani': 12}
hesap penceresi {'eslesen': 43, 'dogru': 41, 'girisi_buldu': 1, 'yanlis_tani': 2}
tohum 20260219 | satir 601 | saldiri satiri 41
basarisiz {'eslesen': 156, 'dogru': 40, 'girisi_buldu': 0, 'yanlis_tani': 117}
giris basarisiz {'eslesen': 79, 'dogru': 40, 'girisi_buldu': 0, 'yanlis_tani': 40}
uzak giris basarisiz {'eslesen': 60, 'dogru': 40, 'girisi_buldu': 0, 'yanlis_tani': 21}
hesap penceresi {'eslesen': 47, 'dogru': 41, 'girisi_buldu': 1, 'yanlis_tani': 6}
Çıktının Söylediği ile Sistemin Gerçeği
Üç sayı yan yana durur. Kâhin: 601 satırlık günlükte saldırıya ait 41 satır var. Araç çıktısı: en kaba süzgeç 153 satır döndürüyor, en dar metin süzgeci 51, alan bilen süzgeç 43. Yanlış tanı: sırasıyla 114, 28, 12 ve 2.
Sayılar süzgeç daraldıkça iyileşiyor, ama iyileşmenin kaynağı satır sayısı değildir. “Basarisiz” sözcüğünü arayan süzgeç 153 satır getirir; bunların yalnız 40’ı saldırıya aittir, kalan 113 satır yetkilendirme reddi ve dağınık parola hatasıdır. Olay türünü sınırlayan ikinci süzgeç yanlış tanıyı 28’e, kaynağı da sınırlayan üçüncüsü 12’ye indirir. Üçünün ortak yanı vardır: hiçbiri 41 satırın 40’ından fazlasını bulamaz.
Alan bilen süzgeç 43 satır döndürür ve saldırının 41 satırının 41’ini de içerir; fazladan gelen iki satır aynı hesabın penceredeki başka kayıtlarıdır. Yanlış tanı 2’ye iner. Kazancı sağlayan şey daha çok satır okumak değil, satırların hangi alana göre gruplandığıdır: tek tek satırlar değil, aynı hesabın altmış saniyelik penceredeki yoğunluğu sorgulanır.
İki yanılgı türünün ağırlığı da aynı değildir. Boşuna okunan satır zaman kaybettirir; hiç okunmayan saldırı satırı tanıyı yanlış yönlendirir. Ölçüde ikisi tek sayıda toplanıyor, ama operasyonel karşılıkları ayrıdır. Kaba süzgecin 114 yanlış tanısının 113’ü birinci türdendir: sonuç doğru yönü gösterir, yalnız pahalıdır. Üç metin süzgecinin ortak 1 eksiği ise ikinci türdendir ve pahalı olmakla kalmaz, sonucu değiştirir.
Süzgecin daralmasının bir sınırı da vardır. Kaynağı “uzak” olarak sınırlayan üçüncü süzgeç, saldırı yerel bir oturumdan gelseydi hiçbir şey bulamazdı; daraltma her zaman iyileştirmez, yalnız bu kurguda iyileştirir. Bir süzgecin doğruluğu kendi mantığından değil, aradığı şeyin gerçekte nerede durduğundan gelir.
Kanıtın En Önemli Satırı
Çıktının son sütunu asıl noktayı taşır. Üç metin süzgecinin girisi_buldu değeri 0,
alan bilen süzgecin değeri 1’dir. Kırk başarısız denemenin ardından gelen o tek
başarılı giriş satırı, olayın sonucunu belirleyen satırdır: denemeler başarısız kaldıysa
olay bir gürültüdür, sonuncusu başarılıysa olay bir ihlaldir. Başarısızlığı arayan hiçbir
süzgeç onu getirmez, çünkü o satır başarısız değildir.
Bu, kursun kuralının kimlik günlüklerindeki biçimidir. “Kaç başarısız giriş var” sorusunun yanıtı ne kadar doğru olursa olsun, tanıyı belirleyen soru değildir. Doğru soru şudur: bu deneme dizisinden sonra o hesapla giriş yapılabildi mi. Aynı ayrım oturum kayıtlarında da işler: açık kalmış oturumları saymak yerine, hangi açılışın kapanışı olmadığı sorulur.
Sorunun biçimi süzgecin biçimini de belirler. Başarısızlığı arayan bir süzgeç bir sayaç
üretir; sayaç bir eşikle karşılaştırılır ve eşik hep tartışmalıdır. Diziyi arayan bir süzgeç
ise bir örüntü üretir: aynı hesap, aynı kaynak, dar bir pencere ve sonunda değişen bir
sonuç. Ölçüdeki hesap_penceresi işlevi tam olarak bunu yapar; yanlış tanıyı 12’den 2’ye
indiren şey daha akıllı bir eşik değil, sorunun sayaçtan örüntüye çevrilmesidir.
Örüntünün bir bedeli vardır. Sayaç tek geçişte hesaplanır; örüntü, her hesap için pencere taraması gerektirir ve günlük büyüdükçe pahalılaşır. Kayıtlar alanlara ayrılmış biçimde duruyorsa bu tarama sorgu tarafında yapılabilir; yalnız düz metin varsa önce ayrıştırma gerekir. Önceki derste kurulan biçim ayrımının bedeli burada ödenir: düz metin, sorunun sayaç olarak sorulmasını dayatır.
İkinci Tohum
İkinci tohumla arka plan gürültüsü değişir; saldırı 41 satır olarak kalır çünkü kurguya öyle
yerleştirilmiştir. Kaba süzgeç 156 satır getirip 117 yanlış tanı üretir, olay türünü
sınırlayan süzgeç 40, kaynağı da sınırlayan 21, alan bilen süzgeç 6 verir.
Sayılar büyür, sıralama değişmez ve girisi_buldu sütunu yine yalnız alan bilen süzgeçte
1’dir. Yanlış tanı sayılarının kesin değeri kurguya bağlıdır; kurguya bağlı olmayan
şey, metin eşlemenin başarılı satırı yapısal olarak kaçırmasıdır.
Özet
- Kimlik doğrulama başarısızlığı ile yetkilendirme başarısızlığı iki ayrı olaydır; metin eşleyen bir süzgeç ikisini tek kovaya atar.
- Oturum kapanış kaydının eksik olması olağandır; açık oturum sayısını günlükten çıkaran tanı gerçekte açık olandan fazla sayar.
- Kâhin 41 saldırı satırı barındırır; kaba süzgeç 153 satır getirip 114, alan bilen süzgeç 43 satır getirip 2 yanlış tanı üretir.
- Üç metin süzgecinin hiçbiri saldırının başarılı giriş satırını bulamaz; alan bilen süzgeç onu bulur ve tanıyı ihlal ile gürültü arasında ayıran satır odur.
- Kazanç satır sayısını değiştirmekten değil, satırları hesap ve zaman penceresine göre gruplamaktan gelir.
Sonraki Adım
Bu dersin süzgeçleri elinde bütün günlük varken çalıştı: 601 satırın hepsi okunabiliyordu. Gerçek bir makinede bu varsayım her zaman geçerli değildir, çünkü günlük dosyaları sınırsız büyümez. Dosya belirli bir boyuta ulaştığında eskisi atılır ve atılan kısım geri gelmez. Sonraki ders süzme ile döndürmeyi birlikte ele alır ve 4000 satırlık bir günlükteki 86 hatanın döndürme boyutu küçüldükçe kaça düştüğünü sayar.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.