Geçen hafta bir müşteride — büyük bir sigorta şirketi, işim vermeyeyim — ilginç bir durumla karşılaştık. Ekipteki güvenlik mühendisi CodeQL taramalarında sürekli “false positive” alıyordu. Yanı şirketin kendi yazdığı HTML escape fonksiyonu vardı, bayağı da sağlamdı aslında, ama CodeQL bunu tanımıyordu. Her PR’da aynı XSS uyarıları düşüyor, ekip de “aa yine o” deyip kapatıyordu.
Araya gireyim: İşin kötüsü şu: Bir süre sonra insanlar gerçek uyarıları da kapatmaya başlıyor. Çünkü gürültü çok. Açıkçası bu, statik analiz araçlarının en büyük düşmanı (şaşırtıcı ama gerçek)
Neyse, geçtiğimiz günlerde GitHub, CodeQL 2.25.2 ile birlikte models-as-data yaklaşımına sanitizer ve validator desteğini ekledi. Yanı artık kendi projenizdeki özel sanitization fonksiyonlarınızı — CodeQL’in garip sorgu dilini öğrenmeden — sade bir YAML dosyasıyla tanımlayabiliyorsunuz. Bu bana fena heyecan verdi, anlatayım nedenini.
Meselenin Özü: Barrier ve Barrier Guard Ne İşe Yarıyor?
CodeQL’in göbeğinde taint tracking var. Kısaca şöyle düşünün: kullanıcıdan gelen veri, mesela bir form input’u, önce kirli kabul ediliyor; sonra bu veri kodun içinde oradan oraya dolaşıyor, bazen fonksiyon parametresi oluyor, bazen değişkene yazılıyor, bazen de bir sorgunun içine sızıyor. CodeQL de bu akışı izliyor. Eğer o kirli veri exec() ya da innerHTML gıbı riskli bir yere varırsa, işte orada alarm veriyor.
Peki neden her şey bu kadar düz ilerlemiyor? Çünkü bazen aradaki bir fonksiyon veriyi temizliyor. Tam burada barrier devreye giriyor; yanı sanitizer gıbı düşünebilirsiniz. Veri o noktadan geçince CodeQL artık önü temiz sayıyor. Evet.
Bir de barrier guard var, biraz daha ince ayar gıbı. Diyelim ki elinizde isValidEmail() diye bir kontrol var ve true/false dönüyor; true gelirse o veriyi kullanmak güvenli kabul ediliyor. İşte böyle koşullu kontroller barrier guard oluyor, yanı if bloğunun doğru tarafında taint akışı kesiliyor (yanlış tarafta işe akış zaten devam ediyor) (şaşırtıcı ama gerçek). Hani ne farkı var diyorsunuz, değil mi? İlginç olan şu: mesele sadece “temizledim” demek değil, hangı koşulda temiz sayılacağını da anlatmak gerekiyor (şaşırtıcı ama gerçek)
Önceden bu barrier’ları tanımlamak için CodeQL’in kendi sorgu dilini (QL) bilmek zorundaydınız. Dürüst olayım: QL öğrenmek sabır ister. Artık YAML yeterli.
Neyse, çok dağıtmayayım; yukarıdaki cümle aslında işin en rahat kısmıydı. Şimdi can alıcı nokta şu: YAML ile bunu tanımlayabiliyorsanız, günlük kullanım baya kolaylaşıyor,. Yine de modelin neyi “güvenli” gördüğünü iyi okumak lazım. Aksi hâlde her şey temiz sanılır, sonra bir bakarsınız veri hâlâ dolaşıyor.
Neden Bu Kadar Önemli?
Şimdi bakın, Türkiye’deki kurumsal müşterilerde sık gördüğüm bir durum var. En çok da bankacılık ve sigorta tarafında, güvenlikle ilgili utility fonksiyonları yıllar içinde birikiyor; bir SecurityUtils.sanitizeHtml() çıkıyor, araya bir InputValidator.cleanSql() giriyor, sonra da kimsenin dokunmaya cesaret edemediği 2014 yapımı bir LegacyEscaper sınıfı kalıyor ortada (buna dikkat edin)
Evet, doğru duydunuz. TypeScript 7.0 Beta: Go ile 10 Kat Hızlanan Derleyici yazımızda bu konuya da değinmiştik. Azure DevOps MCP Server Nisan Güncellemesi: Neler Değişti? yazımızda bu konuya da değinmiştik.
CodeQL bunları tanımıyor, açık konuşayım tanıması da pek beklenmez. Standart kütüphane olmadıkları için modellemek mümkün ölmüyor, ta ki siz QL yazana kadar. Işte burada küçük bir pürüz var, QL yazmak için de genelde birinin zaman ayırması gerekiyor. Hani şu “biz CodeQL’e geçiyoruz” deyip 6 ay sonra hâlâ aynı yerde duran projeler var ya? Sebep çoğu zaman tam olarak bu.
Doğrusu, Şimdi bir geliştirici, 10-15 satırlık bir YAML dosyasıyla bu işi toparlayabiliyor. Fena değil. Bir bakıma, en çok da de de Azure DevOps Advanced Security: Tek Tıkla CodeQL Devri sonrası CodeQL’e geçen Türk şirketleri için zamanlama bayağı yerinde öldü; yanı geç kalmış gıbı görünse de, pratikte elini baya rahatlatıyor. Bu konuyla ilgili Azure Developer CLI ve Copilot: Terminalde AI Dönemi yazımıza da göz atmanızı tavsiye ederim.
Evet, doğru duydunuz.
Gerçek Bir Örnek: XSS Sanitizer Tanımlamak
Teorik anlatınca iş biraz dağılıyor. Somut gidelim. Diyelim ki JavaScript projenizde şöyle bir fonksiyon var, hani ilk bakışta gayet masum duruyor ama CodeQL önü tanımadığı için size gereksiz XSS uyarısı yağdırıyor:
// src/security/htmlSafe.js
function escapeHtml(input) {
return String(input)
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
module.exports = { escapeHtml };
Aslında, Bu fonksiyonun yaptığı şey net aslında. HTML escape ediyor. Ama CodeQL “ben bunu güvenli sanitizer olarak bilmiyorum” deyince, siz de her innerHTML = escapeHtml(userInput) satırında aynı uyarıyı görüyorsunuz; biraz can sıkıcı, biraz da beklenmedik bir durum oluyor açıkçası.
Peki ne yapıyoruz? Data extension ile CodeQL’e küçük bir ipucu veriyoruz. Şöyle bir dosya ekleyince mesele büyük ölçüde çözülüyor:
extensions:
— addsTo:
pack: codeql/javascript-all
extensible: barrierModel
data:
— ["src/security/htmlSafe.js", "Member[escapeHtml].ReturnValue", "html-injection"]
Hepsi bu kadar. .github/codeql/extensions/ klasörüne koyuyorsunuz ve kullanıyorsunuz. Sonra CodeQL, escapeHtml‘in dönüş değerini html-injection için güvenli kabul ediyor. Ama dür bir saniye — burada html-injection kısmı önemli, (buna dikkat edin). Bir fonksiyon HTML tarafında temiz olabilirken SQL injection ya da başka bir akışta hiç de güvenli olmayabiliyor.
Evet.
Barrier Guard Örneği
Guard tarafı biraz daha ilginç. Mesela elinizde böyle bir validator varsa:
function isValidUrl(url) {
return /^https:\/\/trusted\.com\//.test(url);
}
Bunun için YAML tarafına şu modeli yazıyorsunuz:
extensions:
— addsTo:
pack: codeql/javascript-all
extensible: barrierGuardModel
data:
— ["src/validators.js", "Member[isValidUrl]", "true", "url-redirection"]
Buradaki true, akışın hangı dönüş değerinde kesileceğini söylüyor. Yanı fonksiyon true dönerse, if bloğunun içinde URL artık güvenli kabul ediliyor. Nasıl desem, işin aslı bu satır CodeQL’e “burada dür” demenin düzenli yolu gıbı çalışıyor.
Tuhaf ama, Peki neden önemli? Çünkü yanlış yerde bariyer tanımlarsanız uyarıları susturursunuz ama gerçek riski de kaçırabilirsiniz. O yüzden modelin adı kadar query kind’ı da doğru olmalı; yoksa sonuç idare eder görünür ama sahada tatsız sürpriz çıkar.
Desteklenen Diller ve Kapsam
Şu an iş 8 dilde dönüyor. Hani “ana dillerin çoğu” deseniz, pek de yanlış sayılmaz:
| Dil | Pack Adı | Olgunluk |
|---|---|---|
| C/C++ | codeql/cpp-all | Yeni, test edilmeli |
| C# | codeql/csharp-all | Stabil |
| Go | codeql/go-all | Stabil |
| Java/Kotlin | codeql/java-all | Stabil |
| JavaScript/TypeScript | codeql/javascript-all | Stabil |
| Python | codeql/python-all | Stabil |
| Ruby | codeql/ruby-all | Stabil |
Bu içerik işinize yaradı mı?
Benzer içerikleri kaçırmamak için beni sosyal medyada takip edin.



