SQL injection nedir ve kodda nasıl önlenir?
SQL injection, yıllardır web uygulamalarındaki en tehlikeli açıklar arasında. Saldırgan, kullanıcıdan alınan veriyi sorguya ekleme biçimindeki bir hatayı kullanarak veritabanında istediği sorguyu çalıştırabilir: veri okuyabilir, silebilir, hatta bazı durumlarda sunucuya erişebilir.
Açık nasıl oluşur?
Kullanıcı verisini sorgu metnine doğrudan eklemek:
$sql = "SELECT * FROM users WHERE email = '" . $_POST['email'] . "'";
Kullanıcı e-posta yerine ' OR '1'='1 yazarsa sorgu şuna dönüşür:
SELECT * FROM users WHERE email = '' OR '1'='1'
Koşul her zaman doğru olduğu için tüm kullanıcılar döner. Aynı mantıkla giriş ekranları atlatılabilir veya başka tablolar okunabilir.
Çözüm: parametreli sorgular
Veriyi sorgu metnine eklemek yerine yer tutucu kullan; veritabanı sürücüsü değeri sorgudan ayrı gönderir. Değer ne olursa olsun SQL komutu olarak yorumlanmaz.
PHP (PDO):
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = ?');
$stmt->execute([$_POST['email']]);
Python:
cursor.execute("SELECT * FROM users WHERE email = %s", (email,))
Node.js (mysql2):
const [rows] = await db.execute("SELECT * FROM users WHERE email = ?", [email]);
Python örneğinde %s bir string biçimlendirme değil, sürücünün yer tutucusudur. "... = '%s'" % email yazmak yine açık oluşturur.
ORM kullanıyorsam güvende miyim?
Çoğunlukla evet; ORM'ler sorguları parametreli üretir. Ama ORM içinde ham sorgu yazarken (raw, query, createNativeQuery vb.) metin birleştirme yaparsan aynı açık geri gelir.
Parametreyle çözülemeyen yerler
Tablo adı, sütun adı veya ORDER BY yönü yer tutucuyla verilemez. Bunları kullanıcıdan alıyorsan izin listesi kullan:
$izinli = ['created_at', 'title', 'views'];
$sutun = in_array($_GET['sirala'], $izinli, true) ? $_GET['sirala'] : 'created_at';
Ek savunma katmanları
- Uygulamanın veritabanı kullanıcısına yalnızca gereken yetkileri ver;
DROPveya başka veritabanlarına erişim yetkisi olmasın. - Hata mesajlarında SQL hatasını kullanıcıya gösterme; logla.
- Kaçış fonksiyonları (
addslashes, elle tırnak değiştirme) güvenilir bir çözüm değildir. Parametreli sorgunun yerini tutmaz.
Kendi kodunda emin olamadığın bir sorgu varsa, gizli bilgileri çıkararak konu açabilirsin.