SQL Injection'dan korunma: parametreli sorgu (Python, PHP, Node.js örnekleri)

SQL Injection hâlâ OWASP Top 10 listesinde. Sebebi basit: kullanıcıdan gelen veriyi metin birleştirerek sorguya koymak.

:cross_mark: 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.

:white_check_mark: 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ı DROP ve GRANT yetkisine 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.