İçeriğe atla
0 XP 0
13 dkderinleşmeyle 14 dk55 XP7 etkinlik

SQL enjeksiyonu

Bu derste
  • SQL enjeksiyonunun neden doğduğunu, sınıflarını, kör durumda nasıl kanıtlandığını ve parametreli sorguyla nasıl kapatıldığını öğrenirsin.
  • Tek tırnak sorgunun mantığını kırar; gerisi saldırganın yazdığı şartlara kalır.
  • Çözüm filtre değil, veriyi koddan ayıran parametreli sorgudur.

Puan bütün etkinlikleri cevaplayınca hesaba yazılır. Bu dersi tamamlayınca +55 XP alacaksın. Giriş yapmadan ilerlersen puan yalnız bu tarayıcıda durur.

Bir giriş formu düşün. Uygulama kullanıcı adını alır ve doğrudan sorgu metnine yapıştırır. Veritabanı gelen dizgiyi bir bütün olarak okur. Adın nerede bitip sorgunun nerede başladığını ayırt edemez.

SQL enjeksiyonu tam burada doğar: girdi veri olarak taşınmaz, kodun içine karışır. Kullanıcı tek tırnak yazarsa dizgiyi kapatır ve sonrasında yazdığı her şey sorgunun parçası olur. Bu derste açığın neden ortaya çıktığını, hangi sınıflara ayrıldığını, kör durumda nasıl kanıtlandığını ve kalıcı çözümün neden parametreli sorgu olduğunu adım adım göreceksin.

Girdi ne zaman koda dönüşür

Uygulama sorguyu dizgi birleştirmeyle kurduğunda iki farklı şey aynı kanaldan akar. Bir yanda geliştiricinin yazdığı sabit SQL, öbür yanda kullanıcının gönderdiği değer. Veritabanı sürücüsü bu ikisini ayıramaz, çünkü kendisine tek bir metin ulaşır. Sabit sorgu SELECT id FROM users WHERE name='...' biçiminde başlar ve tırnaklar değerin sınırını çizer.

Kullanıcı bu tırnağı kendi girdisiyle kapatırsa sınır kayar. Kapanıştan sonra yazılan sözcükler artık değer değil, sorgunun mantığıdır. Sürücü onları yürütür, çünkü söz dizimi geçerlidir. Açığın kaynağı zayıf parola ya da eksik kriptografi değildir; girdi ile kodun aynı düzlemde birleşmesidir.

# Zafiyetli
q = "SELECT id FROM users WHERE name='" + ad + "' AND pw='" + pw + "'"
db.execute(q)

# Sağlam
q = "SELECT id FROM users WHERE name=%s AND pw=%s"
db.execute(q, (ad, pw))
Aynı sorgu, iki yaklaşım. İkincisinde girdi her zaman değer kalır.

Yukarıdaki iki sürüm aynı işi tarif eder ama farklı bir sözleşmeyle. Zafiyetli sürüm girdiyi doğrudan dizgeye ekler; sürücü ne okuduğunu bilmez, yalnız metni birleştirir. Sağlam sürümde ise ad ve parola alanları yer tutucu olarak durur, sürücü onları ayrı birer değer gibi veritabanına iletir.

Sorgu iskeleti hiç değişmez, yalnız doldurulan değerler değişir. Girdi içinde tırnak, noktalı virgül ya da yorum işareti olsa bile sürücü onu hâlâ tek bir değer olarak okur, sorgunun yapısını değiştiremez. Aşağıdaki fonksiyonda hangi satırın bu ayrımı bozduğunu bulacaksın.

Derinleş:Enjeksiyonun kısa tarihi

SQL enjeksiyonu yeni bir açık değildir. Bilinen ilk kamuya açık anlatım 1998'in son haftasında, Phrack dergisinin 54. sayısında çıktı; Jeff Forristal, rain.forest.puppy imzasıyla web uygulamalarının veritabanı sorgularına girdi karıştırdığını gösterdi. Aradan yıllar geçti, çerçeveler olgunlaştı, yine de OWASP enjeksiyonu her listesinde ilk sıralarda tuttu.

2025 listesinde enjeksiyon üçüncü sıradan beşinciye indi; bu düşüş açığın azaldığını değil, otomatik kaçış yapan çerçevelerin yaygınlaştığını gösterir. OWASP verilerinde SQL enjeksiyonu düşük sıklıkta ama yüksek etkili bir açık olarak geçer ve on dört binden çok CVE kaydına dayanır. Sorun teknik olarak çözülmüştür, ama yanlış yazılan tek bir sorgu bugün de kapıyı açar. Tarihin dersi net: kolay görünen dizgi birleştirme, en uzun ömürlü açığı üretir.

Etkinlik 1 / 7

Enjeksiyona açık satırı bul.

Zafiyetli satıra tıkla.

Klasik yük ve enjeksiyon sınıfları

Klasik kimlik atlatma yükünü herkes bilir: tek tırnak, ardından OR 1=1 ve iki tire. Tırnak, kullanıcı adının dizgisini kapatır. OR 1=1 koşulu her satır için doğru olur, çünkü bir her zaman bire eşittir. İki tire ise satırın kalanını, yani parola kontrolünü yoruma çevirir.

Geriye WHERE koşulu hep doğru olan bir sorgu kalır. Veritabanı ilk kullanıcıyı döndürür, uygulama da o kullanıcıyı giriş yapmış sayar.

Parola hiç kontrol edilmez. Küçük bir ayrıntı da veritabanına göre değişir: MySQL iki tireyi ancak ardından bir boşluk gelirse yorum sayar. Bu yüzden MySQL hedefli yüklerde iki tireden sonra boşluk ya da # işareti görürsün.

Bu yük neden bu kadar öğretici? Çünkü açığın özünü tek satırda gösterir: girdi, sorgunun mantığını dışarıdan yeniden yazar. Aynı mantık farklı yüklerle sayısız biçime bürünür.

Kimlik atlatma tek sınıf değildir. Veritabanının verdiği her sinyal ayrı bir yol açar. UNION temelli enjeksiyonda saldırgan kendi SELECT ifadesini var olan sorguya ekler ve başka tablolardan sütun çeker; önce sütun sayısını ORDER BY ile ya da NULL doldurarak bulur.

Hata temelli enjeksiyonda uygulama veritabanı hatasını ekrana basar, saldırgan veriyi bu hata metninin içine sızdırır. Kör boolean enjeksiyonda yanıt gövdesi değişmez, yalnız doğru ve yanlış koşul farklı sayfa üretir. Kör zaman temelli enjeksiyonda fark bir gecikme fonksiyonuyla ölçülür.

İkinci dereceden enjeksiyonda yük önce kaydedilir, sonra başka bir sayfada sorguya girer. Bant dışı yöntemde veri, veritabanının kurduğu bir dış bağlantı üstünden taşınır. Sınıfı belirleyen şey, veritabanının sana ne kadar geri bildirim verdiğidir.

Derinleş:Bant dışı enjeksiyon ve OAST

Bazı enjeksiyonlarda veritabanı sana hiçbir sinyal vermez. Sayfa hep aynı döner, hata çıkmaz, ölçülebilir bir gecikme de kuramazsın. Bu durumda bant dışı yöntem gündeme gelir. Fikir şudur: veritabanına, sonucu senin izleyebildiğin bir dış kanaldan göndermesini söyletirsin.

Örneğin veritabanı motoru bir ad çözmeye ya da bir bağlantı kurmaya zorlanır; o istek senin kontrolündeki bir dinleyiciye ulaşırsa, girdinin yorumlandığı kanıtlanır. Bu tekniğin adı bant dışı uygulama güvenliği testi, kısaca OAST'tır. Yetkili testte bu kanal her zaman senin altyapın olmalı; müşterinin verisini üçüncü taraf bir hizmete taşımak kapsam belgesinde yazmıyorsa veri aktarımı sorunu doğurur. Bant dışı yöntem, kör enjeksiyonun en sessiz biçimini bile görünür kılar.

Etkinlik 2 / 7

Kullanıcı adı alanına ' OR 1=1 -- yazılırsa sorgu nasıl kapanır?

Önce kodu oku, sonra çıktıyı seç.

SELECT id FROM users WHERE name='<GIRDI>' AND pw='x'

Bir enjeksiyon noktasında hangi sınıfla karşı karşıya olduğunu, veritabanının tepkisi söyler. Ekranda başka tablodan veri beliriyorsa UNION yolu açıktır. Bir hata metni sızıyorsa hata temelli yöntem işler.

Yanıt hiç değişmiyor ama sayfa doğru ve yanlış koşulda farklılaşıyorsa kör boolean yolu gündemdedir. Hiçbir görsel fark yokken yalnız yanıt süresi değişiyorsa kör zaman temelli yöntem devrededir. Aşağıdaki eşleştirmede her sınıfı, onu ele veren kendi işaretiyle bir araya getir.

Etkinlik 3 / 7

Her enjeksiyon sınıfını onu ele veren sinyalle eşle.

Soldan bir tane seç, sağdan eşini seç. Kullanılmış bir seçeneği yeniden seçersen yeni öğeye taşınır.

Kör enjeksiyonu kanıtlamak

Her enjeksiyon ekrana veri basmaz. Kör enjeksiyonda uygulama, sorgunun sonucunu doğrudan göstermez; yanıt her denemede aynı görünür. O zaman dolaylı sinyale bakarsın. Yüke bir koşul eklersin ve sayfanın nasıl değiştiğini izlersin.

Doğru koşulda ürün açıklaması görünüyor, yanlış koşulda kayboluyorsa, veritabanı senin koşulunu değerlendiriyor demektir. Bu farkı kullanarak veriyi bit bit çekersin: her soru evet ya da hayır yanıtı verir, yanıtları birleştirince gizli değer ortaya çıkar. Yavaştır ama işe yarar. Kör enjeksiyon, geri bildirim kesilse bile açığın orada durduğunu gösterir.

# Doğru koşul: sayfa dolu döner
GET /urun?id=42 AND 1=1
-> 200, ürün açıklaması görünür

# Yanlış koşul: açıklama kaybolur
GET /urun?id=42 AND 1=2
-> 200, açıklama yok

# Zaman farkı: yük yorumlanırsa yanıt gecikir
GET /urun?id=42 AND SLEEP(5)
-> yanıt yaklaşık 5 sn sonra döner
Kör enjeksiyonda veri görünmez; fark koşullu yanıtta ve gecikmede ölçülür.

Yukarıdaki üç istek aynı açığı üç ayrı sinyalle yoklar. İlk ikisi boolean farkını kullanır: 1=1 her zaman doğru olduğu için sayfa dolu döner, 1=2 her zaman yanlış olduğu için açıklama kaybolur.

Üçüncü istek zaman temelli yöntemi gösterir. SLEEP fonksiyonu veritabanını beş saniye bekletir; yanıt gecikmeli geldiyse girdi sorgu olarak yorumlanmıştır. Zaman temelli yöntem en körü durumları çözer, çünkü sayfada hiçbir görsel fark olmasa bile saat farkı ölçülebilir. Tek dikkat noktası şudur: ağ gecikmesi de yanıtı yavaşlatabilir, bu yüzden ölçümü birkaç kez tekrarlayıp eşiği net tutarsın.

Etkinlik 4 / 7

MySQL'de kör enjeksiyonu zaman farkıyla doğrulayan fonksiyon: ____

Enjeksiyon nerede aranır ve otomasyon

Enjeksiyon yalnız görünen arama kutusunda aranmaz. Veritabanına giden her girdi adaydır. Sorgu parametresi ilk akla gelenidir, ama istek başlıkları, çerezler, JSON gövdesindeki alanlar ve dosya adları da sorguya ulaşabilir.

Kullanıcı aracısı satırını loglayan bir uygulama, o satırı sonradan bir yönetim panelinde sorguya sokarsa, açık görünmeyen bir alandan doğar. Bu yüzden testte yalnız formları değil, isteğin her parçasını denersin. Bir alanın ekranda görünmemesi, veritabanına gitmediği anlamına gelmez. Kapsamı geniş tutmak, en sık atlanan enjeksiyon noktalarını yakalamanın tek yoludur.

İkinci dereceden enjeksiyon zamanı böler. Yük önce zararsız görünen bir kayda yazılır; kayıt sırasında hiçbir şey olmaz. Sonra başka bir sayfa o kaydı okuyup yeni bir sorguya gömer.

Asıl yürütme o anda gerçekleşir. Bu yüzden anlık yanıta bakan bir test ikinci dereceden açığı kaçırır. Kaydettiğin değerin nerede yeniden kullanıldığını izlemen gerekir.

Profil adı, etiket, yorum gibi saklanan alanlar bu sınıfın klasik giriş noktalarıdır. Testi yalnız gönderdiğin istekle değil, veriyi gösteren diğer ekranlarla birlikte yürütürsün.

Etkinlik 5 / 7

sqlmap ile kaydedilmiş istek dosyasını kullanarak q parametresini test et, risk ve seviye varsayılan kalsın.

ogrenci@lab

Savunma: veriyi koddan ayır

Savunma tek cümleyle özetlenir: veriyi koddan ayır. Hazır ifadede sorgu iskeleti önceden veritabanına gider. Değerler sonradan, ayrı bir kanaldan, birer parametre olarak iletilir.

Bazı sürücüler değeri istemci tarafında yerleştirir, ama kaçışı geliştiriciye bırakmaz, kendisi yapar. İki durumda da değer hiçbir zaman kod olarak okunmaz.

Girdi içinde tırnak, noktalı virgül ya da yorum işareti olsa bile değer olarak kalır, çünkü sorgunun yapısı zaten kilitlenmiştir. Bu yaklaşım filtreye benzemez; kötü karakterleri temizlemeye çalışmaz, girdinin bulunduğu düzlemi değiştirir. Filtre er geç bir kaçış biçimini atlar, parametreli sorguda atlanacak bir sınır kalmaz.

Çerçeve kullanmak tek başına koruma vermez. ORM içinde ham sorgu dizgisi birleştirirsen açık aynen geri gelir. Arama, sıralama ve sayfalama kodları bu hatanın en sık göründüğü yerlerdir, çünkü geliştirici oraya dinamik alan adı eklemek ister.

Sütun adı ya da tablo adı girdiden geliyorsa parametre kullanamazsın; parametre yalnız değer taşır, tanımlayıcı taşımaz. Bu durumda izin verilen adları beyaz listeyle sabitlersin. Sıralama yönü için yalnız iki seçenek tanır, gelen değeri o listeye eşlersin.

Beyaz liste, tanımlayıcıyı saldırganın belirlemesini kökten engeller. Kod incelemesinde ham sorgu kuran çağrıları aramak, bu hatayı testten daha hızlı yakalar.

Ek katmanlar etkiyi küçültür ama açığı kapatmaz. En az yetkili veritabanı kullanıcısı, bir enjeksiyon gerçekleşse bile saldırganın erişebileceği veriyi daraltır; yalnız okuma yetkisi olan hesap tablo düşüremez. Web uygulama güvenlik duvarı bilinen yükleri süzer, ama yeni bir yazımla aşılır, bu yüzden yalnız ek katmandır.

Hata mesajını gizlemek ise hiçbir şeyi çözmez; açık yerinde durur, saldırgan kör tekniklere geçer. Sağlam mimari parametreli sorguyu merkeze koyar ve öbür katmanları onun yerine değil, yanına ekler.

Etkinlik 6 / 7

SQL enjeksiyonunu kökten kapatan yöntem hangisidir?

Son bir noktayı da ayırt et. Hata mesajını gizlemek çekici görünür, çünkü saldırgana verilen bilgiyi kesiyormuş gibi durur. Ama açık kodda yerinde kaldığı sürece, kör teknikler aynı veriyi süre ve koşul farkıyla yine çeker.

Ayrıntılı hata metnini kullanıcıya göstermemek yine de doğrudur; o metin sunucu günlüğüne yazılır ve tespit ekibine sinyal olur. Yani hata gizleme iyi bir alışkanlıktır, çözüm değildir. Görünürdeki geri bildirimi kısmayı, açığın kendisini kapatmakla karıştırma.

Etkinlik 7 / 7

Doğru mu, yanlış mı?

Hata mesajını kapatmak enjeksiyon açığını giderir.

Bu derste bir hata mı gördün? Bildir