Hatalı bir güvenlik kuralı, hiç kural olmamasından kötüdür
Haftalarca LLM tabanlı bir kod güvenlik tarayıcısı yazdım. En zor ders prompt'larla ilgili değildi: ince biçimde yanlış bir tespit kuralı, gerçek açıkları saklarken bir yandan olmayan açıklar uyduruyor. Pratikte bu neye benziyor, anlatıyorum.
Son birkaç aydır bir LLM motoru üzerinde çalışan bir kod güvenlik tarayıcısı geliştiriyorum. Söylemesi kolay, iyi yapması zor bir fikir: bir depoya doğrultuyorsun ve enjeksiyonu, zayıf kriptoyu, eksik güvenlik başlıklarını, sızmış sırları, bağımlılık sorunlarını ve birkaç düzine başka açık sınıfını dosya ve satır bilgisiyle, düzeltme önerisiyle raporluyor. Sonunda 44 tespit sınıfına ulaştım. Ürünün adı CodeHarden.
Zor kısmın prompt mühendisliği olacağını sanıyordum. Değildi. Zor kısım, motorun okuduğu tespit kurallarını yazmaktı; çünkü kavraması biraz zamanımı alan bir özellik var: kurallar yer gerçeği hâline geliyor. Model, yazdığım şeyi gerçek kabul ediyor. Bu da ince biçimde yanlış bir kuralı, hiç kural olmamasından daha kötü yapıyor, çünkü aynı anda iki yönden birden hata veriyor. Gerçek açıkları güvenli işaretliyor, güvenli kodu açık gibi bayrağa dikiyor. Kapsamdaki bir boşluk sana yalnızca hiç bakmadığın açıkları kaybettirir. Yanlış bir kural ise baktığın açıkları da kaybettirir, üstüne bir de yanlış alarmı okuyan herkesin güvenini.
Kuralları ilk yazdığımda birçoğu neredeyse doğruydu. "Neredeyse doğru" tam da tehlikeli bölge. Temizlik turundan birkaç örnek, çünkü ayrıntılar ilkeden daha ikna edici.
Bir kuralım, Laravel'in Auth::attempt metodunun olmayan bir kullanıcı ile yanlış parola
arasında zamanlamayı eşitlemediğini, dolayısıyla hesabın var olup olmadığını sızdırdığını
söylüyordu. Framework kaynağını gerçekten okuduğumda sonuç doğruydu ama gerekçe yanlıştı:
modern Laravel zamanlamayı eşitliyor, sadece sabit iş yaparak değil. Kontrolü bir Timebox
içine alıp tüm işlemi sabit bir süreye yastıklıyor. Orijinal açıklamamı yayınlasaydım,
düzeltme önerisi geliştiricileri yanlış yere yönlendirecekti. Daha kötüsü, bunu "Laravel
zamanlamayı hiç eşitlemiyor" diye "düzelten" bir gözden geçiren, doğru bir bulguyu yanlışa
çevirmiş olurdu.
Loglama üzerine bir kuralım, %ex içermeyen bir Logback deseninin stack trace'i sessizce
düşürdüğünü varsayıyordu. Kaynağı okuyunca PatternLayout'un throwable dönüştürücüsünü
otomatik eklediği, yani stack trace'in yerinde durduğu ortaya çıktı. Gerçek sızıntı daha dar
ve gözden kaçması daha kolay: maskelenen %msg alanının dışına basılan bir exception mesajı.
Kuralın yanlış mekanizmayı tarif ediyorsa, yanlış şekli ararsın ve asıl sorunun yanından
geçip gidersin.
Ve favorim: Go'nun gorilla/csrf kütüphanesinin, birçok kütüphanenin yaptığı gibi çok kısa
bir kimlik doğrulama anahtarında panikleyeceğini varsaymıştım. Paniklemiyor. Kaynakta uzunluk
kontrolü hiç yok. Bunun yerine token doğrulamasını sessizce başarısız kılıyor; bu da bir
denetçi açısından panikten daha kötü, çünkü ne çöküyor ne uyarıyor. Sistem seni korumayı
usulca bırakıyor, o kadar.
Üçünde de örüntü aynı. "Kulağa doğru geliyor" bir ölçüt değil. Güvenlik iddiaları yüzde 90 doğru olmaya meyillidir ve açık, o eksik yüzde 10'da yaşar. Bu yüzden benimsediğim ve artık tüm motorun üzerinde koştuğu kural şu: her teknik iddia, yayına girmeden önce birincil bir kaynağa karşı doğrulanmak zorunda; spec metni, framework'ün kendi kaynak kodu, RFC. Bir blog yazısı değil, hafıza değil, başka bir modelin kendinden emin çıktısı değil.
Tek bir tura da bu yüzden güvenmiyorum. Bir kuralı yazarken ya da düzeltirken bir ajan taslağı yazıyor, ikinci bir ajan "övme, sadece kusur bul" talimatıyla gözden geçiriyor, üçüncüsüne ise "değiştirmeden önce kendin bağımsızca doğrula, çürütemiyorsan dokunma" deniyor. Sonra yapısal kontrolleri ben yapıyor, kritik iddialardan örnekliyorum. Paranoyakça geliyor. Gözden geçirenin de yanılabildiğini güvenilir biçimde yakalayan tek yöntem bu; ki birden çok kez oldu.
Burada AI'ın güvenlik araçlarındaki yeri hakkında daha geniş bir nokta var ve ne alışıldık hype ne de alışıldık kıyamet. Bir LLM, kodu bağlamıyla gerçekten iyi okuyor. Bir regex'in asla fark edemeyeceği şeyleri görüyor. Ama ona söylediğin şeyin doğruluğunu hiç sürtünmesiz dev alıyor; bu da disiplini yukarı, kurallara ve doğrulamaya taşıyor. Ürün model değil. Arkasındaki doğrulanmış bilgi.
Bu kanaat CodeHarden'a biraz inatçı olduğum bir biçimde işlenmiş durumda. Statik kodu ve yapılandırmayı tarıyor ve her rapor bunu açık dille söylüyor. Canlı test, ağ testi ya da sızma testi yapmıyor ve yaptığını da ima etmiyor. Bir taramanın tam olarak neyi kapsadığını sana söylemeyi, temiz bir raporun olmadığı bir anlama gelmesine yeğlerim. Buraya kadar okuduysan felsefenin tamamı bu: bildiğin konusunda kesin ol, bilmediğin konusunda dürüst. codeharden.com yakında yayında.