SQL Enjeksiyon saldırısı, web yazılımcılarının korkulu bir rüyasıdır. Bilgisayar korsanlarının, verileri doğrudan veritabanından almak için kötü amaçlı SQL sorguları kullandıkları yaygın olarak bilinmektedir. Web sayfası üzerinde giriş alanları doğru şekilde filtrelenmediği zaman çevrimiçi uygulamalarda en çok karşımıza çıkan saldırı yöntemidir. Web uygulamalarınızın yanlış kodlanmasından faydalanılarak saldırganların SQL komutlarını enjekte etmesine izin veren ve veritabanında tutulan verilere erişebilmelerini sağlayan bir giriş formu olduğunu bizlere söyleyen bir saldırı türüdür. Temelde, SQL enjeksiyon saldırısı, kullanıcı girişi için uygun olan alanların, SQL ifadelerinin doğrudan veritabanını geçmesine ve sorgulamasına izin verdiği için ortaya çıkmaktadır. SQL enjeksiyon’da bilgisayar korsanı web uygulaması üzerinden hassas kurumsal verilerin veritabanına ulaşmak için SQL sorgularını ve yaratıcılığını kullanır.
Saldırgan bir sistemin SQL enjeksiyon saldırılarına karşı savunmasız olduğunu fark ettiğinde, site üzerindeki bir giriş formu alanı üzerinden SQL sorgu komutlarını enjekte edebilir. Bu durum saldırgan’a veritabanınızı teslim edilmesi veya veritabanına DROP TABLE gibi herhangi bir SQL komutu çalıştırmasına izin vermekle eşdeğerdir. Hatta bazı durumlarda altta çalışan işletim sisteminde dosyaları okumak, yazmak ve kabuk komuklarını bile çalıştırmak mümkündür. Microdoft SQL Server gibi bazı SQL sunucuları saklı ve genişletilmiş yetkiler içerir. Bir saldırgan bu yetkilere erişim sağlarsa felakate neden olabilir. Ne yazık ki, SQL enjeksiyon saldırısının farkına veritabanından bir hırsızlık yapıldığında ortaya çıkar. Veriler istenmeyen şekilde bu gibi saldırılarla çalınmaktadır.
Aşağıda SQL enjeksiyon zafiyeti olan bir örnek kodu sizinle paylaşıyorum ve sonrasında bu güvenlik açığını önlemek için neler yapabiliriz detaylı olarak inceleyelim.
<html>
<head>
<title>Giriş Ekranı</title>
</head>
<body>
<?php
if(!isset($_POST[‘submit’]))
{
$msg = “”;
form();
}
else
{
$username = $_POST[‘username’];

$password = $_POST[‘password’];
$conn = mysqli_connect(“ozdenercin.com”,”root”,””,”xxxxxxx”) or die(“Error”. mysqli_error($conn));
$query = “SELECT user,pass FROM login WHERE username=’$username’ AND password=’$password’”;
$result = mysqli_query($conn,$query) or die (mysqli_error());
$count = mysqli_num_rows($result);
if($count == 1)
{
$msg = “Giriş Başarılı !”;
form();
}
else
{
$msg = “Giriş Hatalı !”;
form();
}

mysqli_close($conn);
}
?>
</body>
</html>
<?php
function form()
{
$msg = “”;
echo ”
<form method=’POST’ name=’login’>
<table>
<tr><td>Kullanıcı Adı:</td><td><input type=’text’ name=’username’ /></td></tr>
<tr><td>Şifre: </td><td><input type=’password’ name=’password’ /></td></tr>
<tr><td colspan=’2′ align=’center’><input type=’submit’ name=’submit’ value=’Giriş’/></td></tr>

</table>
</form>
“.$GLOBALS[‘msg’];
}
?>

Yukarıda sizlerle paylaştığım php kodunda filtrelerin olmadığını görüyoruz ve SQL enjeksiyon saldırısına açıktır. Şimdi yukarıdaki kodları SQL enjeksiyon saldırısına karşı nasıl önleyebileceğinize dair dört yöntemi sizinle paylaşacağım.

1) Prepared Statements
PHP’deki SQL enjeksiyon saldırılarını önlemenin en kolay yolu “Prepared Statements” kullanmaktır. Aşağıdaki şekilde “Prepared Statements” kullanabilirsiniz.
<?php
$username = $_POST[“username”];
$password = $_POST[“password”];

$stmt = $mysqli->prepare(“SELECT FROM login WHERE username=? AND password=?”);
$stmt->mysqli_bind_param(“ss”,$username,$password);
$stmt->execute();
$stmt->close();
$mysqli->close();
?>

Buradaki önemli nokta, parametre değerlerinin SQL dizesiyle değil, derlenmiş deyimle birleştirilmesidir. SQL enjeksiyonu, veritabanına göndermek için kötü niyetli dizeleri dahil ederek betiği kandırarak çalışır. Bu şekilde kodlarsanız gönderdiğiniz tüm parametreler sadece karakter dizisi olarak kabul edilir. WordPress kullanıyorsanız, aynı şekilde hazır ifadelerde olduğu gibi veritabanına gönderilen sorguyu dezenfekte edecek wpdb::prepare deyimini kullanabilirsiniz.
2) Escaping Strings
Escaping Strings, SQL deyimlerinde kullanılmak üzere özel karakterkeri silmeye yardımcı olur. Ayrıca bağlantının mevcut karakter dizisini de dikkate alır. Aşağıdaki şekilde Escaping Strings ifadelerini kullanabilirsiniz.
<?php
$username = mysqli_real_escape_string($conn,$_POST[“username”]);
$password = mysqli_real_escape_string($conn,$_POST[“password”]);
mysqli_close($conn);
?>

3) trim() ve strip_tags() İşlevlerini Kullanma
trim() ve strip_tags() girişlerinizi filtrelemenin geleneksel yoludur. trim(), boşlukları dizgenin başından ve sonundan çıkarmak için kullanılır. strip_tags(), HTML ve PHP etiketlerini çıkarmak için kullanılır. Her ikisi de birlikte, genellikle bilgisayar korsanları tarafından kullanılan ek kodların ve boşlukların kaldırılmasında yardımcı olur. Aşağıdaki şekilde trim() ve strip_tags() ifadelerini kullanabilirsiniz.
<?php
$username = strip_tags(trim($_POST[“username”]));
$password = strip_tags(trim($_POST[“password”]))
?>

4) PDO Kullanma
PDO veya PHP veri nesneleri çok kullanışlı bir yöntemdir. SQL enjeksiyon saldırılarını önlemede en etkili yöntemlerden bir tanesidir. PDO ayrıca “prepared statements”‘ları kullanır ve çalışma zamanında değerleri bağlar. Aşağıdaki şekilde PDO’yu kullanabilirsiniz.
$stmt = db::con()->prepare(“SELECT * FROM table WHERE id=? AND name=?”);
$stmt->bindValue(1, $id, PDO::PARAM_INT);
$stmt->bindValue(2, $name, PDO::PARAM_STR);
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

Yukarıdaki kod örneğinde birden fazla parametreyi bağlamak için “?” yerine adlandırılmış yer tutucularını kullanabilirsiniz. Bu kolon adını temsil etmektedir, bu şekilde yazılan bir kod parçası aşağıdaki gibi olmalıdır.
$stmt = db::con()->prepare(“SELECT * FROM table WHERE id=:id AND name=:name”);
$stmt->bindValue(‘:id’, $id, PDO::PARAM_INT);

$stmt->bindValue(‘:name’, $name, PDO::PARAM_STR);
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);