← Tüm yazılar

SQL enjeksiyonu saldırısı nedir ve nasıl önlenir?

Burncode Team 4 dk okuma

SQL enjeksiyonu yirmi yılı aşkın süredir bilinen ve iyi belgelenmiş bir güvenlik açığı, ancak her yıl hâlâ gerçek veri ihlallerinde karşımıza çıkıyor. Bunun sebebi önlenmesinin zor olması değil; özellikle eski kodlarda ya da teslim tarihi baskısı altında yazılan kodlarda yanlışlıkla ortaya çıkmasının kolay olması.

SQL enjeksiyonu aslında nedir?

Web uygulamalarının çoğu verileri bir veritabanında saklar ve bu verileri okuyup yazmak için SQL adlı bir sorgu dili kullanır. SQL enjeksiyonu, bir uygulama kullanıcının yazdığı bir metni — bir arama kutusu, bir giriş formu, bir URL parametresi — önce güvenilmeyen bir girdi olarak ele almadan doğrudan bir veritabanı sorgusuna eklediğinde gerçekleşir. Bir saldırgan normal bir değer yerine SQL koduna benzeyen bir şey yazarsa ve uygulama bunu körü körüne sorguya dâhil ederse, veritabanı yalnızca uygulamanın amaçladığı komutları değil, saldırganın yazdığı komutları da çalıştırmış olur.

Basit bir örnek

Sade bir ifadeyle şöyle kurulmuş bir giriş kontrolü düşünün: “Kullanıcı adı [kullanıcının yazdığı şey] ve şifresi [kullanıcının yazdığı şey] olan kullanıcıyı bul.” Uygulama bu sorguyu kullanıcının girdisini doğrudan SQL metnine yapıştırarak oluşturuyorsa, saldırgan kullanıcı adı alanına sorgunun asıl anlamını değiştiren akıllıca bir şey yazabilir. Örneğin koşulu şifreden bağımsız olarak her zaman doğru hâle getirebilir ve böylece şifresini hiç bilmeden herhangi bir kullanıcı olarak giriş yapabilir.

Bu basit bir örnek. Daha gelişmiş SQL enjeksiyonu, kullanıcının asla görmemesi gereken verileri — diğer kullanıcıların kişisel bilgileri, ödeme bilgileri, şifre hash'leri — okumak için, en kötü durumlarda ise verileri doğrudan değiştirmek ya da silmek için kullanılabilir.

Neden hâlâ bu kadar yaygın?

  • Test edilene kadar görünmezdir. Güvenlik açığı olan bir form, her normal kullanıcı için kusursuz çalışır. Sorun yalnızca biri onu kasıtlı olarak kötü niyetli girdilerle test ettiğinde ortaya çıkar; bu da normal geliştirme sürecinde nadiren tesadüfen olur.
  • “Sadece bu seferlik” yazılan kodlarda saklanır. Hızlı bir yönetici betiği, tek seferlik bir rapor sorgusu, aceleyle geliştirilmiş bir özellik: Geliştiricilerin güvenli kalıbı kullanmak yerine metinleri doğrudan birleştirerek sorgu oluşturma ihtimalinin en yüksek olduğu yerler tam olarak bunlardır, çünkü o an daha hızlı gibi gelir.
  • Eski kodlara geri dönülmez. Kod tabanının nadiren dokunulan bir köşesine yıllar önce eklenmiş bir kalıp, biri nihayet bakmaya karar verene kadar orada sessizce durabilir.

Gerçekte nasıl önlenir?

Çözüm, belirsiz bir ilke olarak “kullanıcı girdisini temizleyin” demek değildir. Tutarlı şekilde kullanıldığında sorunu fiilen ortadan kaldıran, belirli ve köklü bir teknik vardır.

  • Her zaman parametreli sorgular (prepared statement) kullanın. Sorguyu metinleri birbirine yapıştırarak oluşturmak yerine, yer tutucularla yazarsınız ve kullanıcının değerlerini ayrıca iletirsiniz. Veritabanı bu değerleri, hangi karakterleri içerirlerse içersinler, kesinlikle komutun bir parçası olarak değil, yalnızca veri olarak ele alır. Neredeyse tüm modern veritabanı kütüphaneleri bunu destekler; bu, yalnızca biri hatırladığında uygulanan bir istisna değil, varsayılan olmalıdır.
  • Bir ORM ya da sorgu oluşturucu kullanın ve onu doğru kullanın. Laravel'deki Eloquent gibi araçlar, arka planda varsayılan olarak parametreli sorgular oluşturur. Risk, özellikle bir geliştirici aracın kolayca desteklemediği bir şeyi yapmak için ham bir sorgu metnine başvurduğunda yeniden ortaya çıkar. Yavaşlayıp iki kez kontrol etmeniz gereken yer tam olarak orasıdır.
  • Veritabanı hesaplarına en az yetki ilkesini uygulayın. Uygulamanızın bağlandığı veritabanı kullanıcısı yalnızca gerçekten ihtiyaç duyduğu yetkilere sahip olmalıdır. Bir sorgu bir şekilde istismar edilirse, bu, saldırganın onunla gerçekte neler yapabileceğini sınırlar.
  • Girdi tiplerini ana savunma olarak değil, ikinci bir katman olarak doğrulayın. Bir alanın sayı olması gerekiyorsa, sorguya ulaşmadan önce gerçekten sayı olmasını zorunlu kılın. Bu tek başına her şeyi yakalamaz, ama olası saldırıların alanını daraltır ve bariz hataları erkenden yakalar.

Bu neden yalnızca iyi alışkanlıklar değil, gerçek bir inceleme gerektirir?

SQL enjeksiyonunun can sıkıcı yanı şudur: Bir kod tabanı 999 yerde tertemiz görünebilir ve nadiren dokunulan bir yönetim aracındaki tek bir ham sorgu bunların hepsini boşa çıkarabilir. Otomatik tarayıcılar bunların bir kısmını yakalar, ama önemli olan vakaları gerçekten bulan şey, yalnızca bir ORM'nin var olup olmadığına değil, sorguların gerçekte nasıl oluşturulduğuna dair gerçek ve dikkatli bir manuel incelemedir.

Bu tür manuel uygulama güvenliği denetimi — yalnızca bir tarayıcı çalıştırıp işi bitmiş saymak değil, sorgularınızın ve erişim kontrolü mantığınızın gerçekte nasıl çalıştığını okumak — altyapı sıkılaştırma ve ekipleri gerçek bir uyumluluk denetimine hazırlamanın yanı sıra Burncode'un güvenlik çalışmalarının özünü oluşturur.