SQL Injection hâlâ OWASP Top 10 listesinde. Sebebi basit: kullanıcıdan gelen veriyi metin birleştirerek sorguya koymak.
Yanlış (savunmasız)
kullanici = request.form["kullanici"]
cursor.execute(f"SELECT * FROM uyeler WHERE ad = '{kullanici}'")
Kullanıcı adı alanına özel karakterler girildiğinde sorgunun anlamı değişir ve saldırgan veritabanında istemediğin işlemler yapabilir.
Doğru: parametreli sorgu
Veri ile komut ayrı gönderilir; veritabanı girdiyi asla komut olarak çalıştırmaz.
Python (sqlite3 / psycopg)
cursor.execute("SELECT * FROM uyeler WHERE ad = ?", (kullanici,)) # sqlite3
cursor.execute("SELECT * FROM uyeler WHERE ad = %s", (kullanici,)) # psycopg (PostgreSQL)
PHP (PDO)
$stmt = $pdo->prepare("SELECT * FROM uyeler WHERE ad = :ad");
$stmt->execute(["ad" => $_POST["kullanici"]]);
$uye = $stmt->fetch();
Node.js (mysql2)
const [rows] = await db.execute("SELECT * FROM uyeler WHERE ad = ?", [kullanici]);
Ek savunma katmanları
- ORM kullan (SQLAlchemy, Prisma, Eloquent). Bunlar varsayılan olarak parametreli çalışır. Ama ORM içinde “raw query” yazarken yine dikkat et.
- En az yetki: Uygulamanın veritabanı kullanıcısı
DROPveGRANTyetkisine sahip olmasın. - Tablo veya kolon adı kullanıcıdan geliyorsa parametre işe yaramaz. İzin verilen değerlerden oluşan bir liste (whitelist) kullan:
IZINLI = {"ad", "tarih", "puan"}
sirala = request.args.get("sirala", "tarih")
if sirala not in IZINLI:
sirala = "tarih"
cursor.execute(f"SELECT * FROM uyeler ORDER BY {sirala}") # artık güvenli
- Hata mesajlarını kullanıcıya gösterme. Ayrıntılı SQL hatası saldırgana yol haritası verir.
Kendi uygulamanızı test etmek isterseniz yalnızca kendi sistemlerinizde veya PortSwigger Web Security Academy gibi yasal laboratuvarlarda çalışın.