arrow_backAlan notlarına dön
WEB SECURITY Yayınlandı 8 Aug 2026

SQL Injection Nedir ve Nasıl Önlersiniz?

SQL injection saldırılarının pratik bir dökümü, gerçek örnekler ve bunları üretim kodunda gerçekten durduran somut çözümler.

SQL injection 1990'ların sonundan beri var ve web uygulamalarının tehlikeye atılmasının en yaygın yollarından biri olmaya devam ediyor. Hata basit: saldırgan, düz veri yerine SQL kodu olarak yorumlanan bir girdi gönderir ve veritabanı hiç yapması gerekmeyen bir şeyi yapır.

Saldırı aslında nasıl çalışır

PHP'de şöyle bir sorgu oluşturan bir giriş formunu hayal edin:

$query = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";

Uygulama girdiyi temizlemezse, saldırgan kullanıcı adı alanına admin' -- yazar. Sorgu şu hale gelir:

SELECT * FROM users WHERE username = 'admin' --' AND password = ''

-- satırın geri kalanını açıklama yapar, böylece parola kontrolü asla gerçekleşmez. Bu klasik bir yetkilendirme atlamasıdır. Saldırganlar ayrıca diğer tablolardan veri çekmek için UNION SELECT kullanırlar veya sürücü birden fazla ifadeye izin veriyorsa DROP TABLE users; gibi yıkıcı bir şey çalıştırmak için sorguları noktalı virgülle yığarlar.

Bilgi tabanında veren kör SQL injection de vardır, uygulamanın sorgu sonuçlarını doğrudan göstermediği. Saldırganlar zamanlama (MySQL'de SLEEP(5)) veya boolean yanıtları (sayfa doğru mü yanlış mı koşula farklı davranıyor mu) aracılığıyla bilgi çıkarırlar. sqlmap gibi araçlar, savunmasız bir parametre bulunduktan sonra bu tür çıkarmaları otomatikleştirir.

String birleştirmesi neden kök sorundur

Bu saldırının her varyantı bir şeye geri gelir: kodu ve verileri aynı dizede karıştırmak. Veritabanı, yasal bir değer ile enjekte edilmiş söz dizimi arasında fark göremez çünkü aynı kanaldan gelirler. Tırnak işaretini kaçırmak bazı durumlarda yardımcı olur ama kırılgandır — farklı kodlamalar, ikinci derecen injection (veri bir kez depolanır, sonra daha sonra güvenli olmayan şekilde yeniden kullanılır) ve sürücüye özgü tuhaflıklar hepsi bypass yolları oluşturur. Kaçış bir yama, bir çözüm değildir.

Parametrelendirilmiş sorgular gerçek çözümdür

Çözüm, parametrelendirilmiş sorgular (hazırlanmış ifadeler de denilir) kullanarak sürücü düzeyinde SQL kodunu kullanıcı verilerinden ayırmaktır. Veritabanı önce sorgu yapısını alır, sonra değerleri bağlar, böylece kullanıcı girişi sorgunun anlamını asla değiştiremez.

psycopg2 ile Python'da:

cur.execute("SELECT * FROM users WHERE username = %s AND password = %s", (username, password))

mysql2 ile Node.js'de:

connection.execute('SELECT * FROM users WHERE username = ? AND password = ?', [username, password]);

JDBC ile Java'da:

PreparedStatement stmt = conn.prepareStatement("SELECT * FROM users WHERE username = ? AND password = ?");
stmt.setString(1, username);
stmt.setString(2, password);

Deseni fark edin: yer tutucular (%s, ?) veri için yeri tutar ve gerçek değerler ayrı olarak iletilir. String birleştirme yok, manuel kaçış gerekli değil. Bu, normal bir uygulamada yazacağınız sorguların büyük çoğunluğu için işe yarar.

Peki dinamik tablo veya sütun adları ne olacak?

Parametrelendirme değerleri işler ama tanımlayıcıları değil — bir tablo adını parametre olarak bağlayamazsınız. Uygulamanız dinamik olarak bir tablo seçmesi gerekiyorsa (nadir ve genellikle bir tasarım kokusu), izin verilen değerleri doğrudan kullanıcı girişine güvenmek yerine sabit kodlanmış bir listeye göre beyaz liste yapın:

allowed_tables = {'orders', 'invoices', 'customers'}
if table_name not in allowed_tables:
    raise ValueError("Invalid table")

Kullanıcı girişinden hiç string biçimlendirmesi ile tanımlayıcı adları oluşturmayın, kaçış olsun olmasın.

Sorgunun kendisinin ötesinde katmanlı defanslar

Parametrelendirilmiş sorgular birincil kontroldür, ancak birkaç diğer şey önemlidir:

  • Veritabanı hesabında en az ayrıcalık. Uygulamanın DB kullanıcısının DROP, ALTER veya ilgisiz şemalara erişimi olmamalıdır. Bir injection kaymaktan geçerse, sınırlı ayrıcalıklar hasarı sınırlar.
  • ORM'ler varsayılan olarak yardımcı olur. Django'nun ORM'i, SQLAlchemy ve Hibernate, standart sorgu oluşturma yöntemlerini kullandığınızda tüm sorguları otomatik olarak parametreleştirirler. Ham SQL'e düştüğünüzde veya string interpolasyonuyla .extra()/text() çağrılarını kullandığınızda risk yeniden ortaya çıkar — bu yüzden bu noktaları özel olarak denetleyin.
  • Girdi doğrulama, değiştirme değil ikincil bir katmandır. Bir e-posta alanının bir e-posta gibi görünüp görünmediğini kontrol etmek iyi bir uygulamadır, ancak tek başına injeksiyonu durdurmaz — saldırganlar gevşek doğrulamayı geçen yaratıcı yükleri bulurlar.
  • Bir WAF bilinen saldırı kalıplarını yakalayabilir, ancak altta yatan kod için bir düzeltme değil, bir algılama katmanıdır.

Kendi kodunuzu bu bug için test edin

Sorguları CI'nin bir parçası olarak statik bir analiz aracından geçirin (Python için Bandit, SQL injection kuralı kümeleriyle Semgrep). Manuel test için, her girdi alanına tek bir tırnak işareti (') enjekte etmeyi deneyin ve yanıtta sızıntı yapan SQL hata iletilerine bakın — bu genellikle bir sorgunun parametrelendirilmediğinin ilk işaretidir.

Bunun hakkında daha derine inmek istiyorsanız, Korra Studio'nun Web Security track'i injeksiyonu XSS ve auth bypass'le birlikte kapsar ve Databases segmentleri bu hata sınıfından kaçınan sorgu tasarım modellerini adım adım gösterir.

AI yardımıyla yazıldı, Michal Pilch (CISSP), Korra Studio tarafından incelendi ve yayınlandı.

Daha ileri gitmek için hazır mısın?

Bu, Korra Studio bilgi tabanından bir nottur — platform her konuyu 1-to-1 mentoring ile eşleştirir.

Ücretsiz başlaarrow_forward