Veritabanı sorguları söz konusu olduğunda, her zaman hazırlanmış parametreli sorguları deneyin ve kullanın. mysqli
Ve PDO
kütüphaneler bu destekler. Bu, gibi kaçan işlevleri kullanmaktan son derece güvenlidir mysql_real_escape_string
.
Evet, mysql_real_escape_string
aslında sadece bir dizge kaçan işlevdir. Bu sihirli bir mermi değil. Tek yapacağı, tek bir sorgu dizesinde güvenli bir şekilde kullanılabilmeleri için tehlikeli karakterlerden kaçınmaktır. Ancak, girdilerinizi önceden sterilize etmezseniz, belirli saldırı vektörlerine karşı savunmasız olacaksınız.
Aşağıdaki SQL'i hayal edin:
$result = "SELECT fields FROM table WHERE id = ".mysql_real_escape_string($_POST['id']);
Bunun istismara açık olduğunu görebilmelisiniz. Parametrenin ortak saldırı vektörünü içerdiğini
düşünün id
:
1 OR 1=1
Orada kodlanacak riskli karakter yoktur, bu nedenle doğrudan kaçan filtreden geçecektir. Bizi terk ederek:
SELECT fields FROM table WHERE id= 1 OR 1=1
Bu hoş bir SQL enjeksiyon vektörüdür ve saldırganın tüm satırları döndürmesine izin verir. Veya
1 or is_admin=1 order by id limit 1
hangi üretir
SELECT fields FROM table WHERE id=1 or is_admin=1 order by id limit 1
Bu, saldırganın bu tamamen kurgusal örnekte ilk yöneticinin ayrıntılarını geri vermesini sağlar.
Bu işlevler yararlı olsa da, dikkatli kullanılmalıdır. Tüm web girişlerinin bir dereceye kadar doğrulanmasını sağlamanız gerekir. Bu durumda, bir sayı olarak kullandığımız bir değişkenin aslında sayısal olup olmadığını kontrol etmediğimiz için sömürülebileceğimizi görüyoruz. PHP'de, girdilerin tamsayılar, yüzer sayılar, alfasayısal vb. Olduğunu kontrol etmek için yaygın olarak bir dizi işlev kullanmanız gerekir. Ancak, SQL söz konusu olduğunda, hazırlanan ifadenin değerinin çoğuna dikkat edin. Yukarıdaki kod, hazırlanmış bir ifade olsaydı, veritabanı işlevleri bunun 1 OR 1=1
geçerli bir literal olmadığını bildiği için güvenli olurdu .
Gelince htmlspecialchars()
. Bu kendi başına bir mayın tarlası.
PHP'de gerçek bir sorun var, çünkü html ile ilgili farklı kaçış işlevlerinden oluşan bir seçki var ve tam olarak hangi işlevlerin ne yaptığına dair net bir kılavuz yok.
Öncelikle, bir HTML etiketinin içindeyseniz, gerçekten başınız belada demektir. Bakmak
echo '<img src= "' . htmlspecialchars($_GET['imagesrc']) . '" />';
Zaten bir HTML etiketinin içindeyiz, bu nedenle tehlikeli bir şey yapmamıza <veya> ihtiyacımız yok. Saldırı vektörümüz şöyle olabilir:javascript:alert(document.cookie)
Artık ortaya çıkan HTML şöyle görünüyor:
<img src= "javascript:alert(document.cookie)" />
Saldırı doğrudan geçer.
Daha da kötüleşiyor. Neden? çünkü htmlspecialchars
(bu şekilde çağrıldığında) yalnızca çift tırnakları kodlar ve tek değil. Yani olsaydı
echo "<img src= '" . htmlspecialchars($_GET['imagesrc']) . ". />";
Kötü saldırganımız artık tamamen yeni parametreler enjekte edebilir
pic.png' onclick='location.href=xxx' onmouseover='...
bize verir
<img src='pic.png' onclick='location.href=xxx' onmouseover='...' />
Bu durumlarda sihirli bir mermi yoktur, sadece girdiyi kendiniz ölçmeniz gerekir. Kötü karakterleri filtrelemeye çalışırsanız kesinlikle başarısız olursunuz. Beyaz liste yaklaşımını benimseyin ve sadece iyi olan karakterlere izin verin. Vektörlerin ne kadar çeşitli olabileceğine dair örnekler için XSS hile sayfasına bakın
htmlspecialchars($string)
HTML etiketlerinin dışında kullansanız bile , çok baytlı karakter kümesi saldırı vektörlerine karşı hala savunmasızsınız.
Olabileceğiniz en etkili yöntem, mb_convert_encoding ve htmlentities kombinasyonunu aşağıdaki gibi kullanmaktır.
$str = mb_convert_encoding($str, 'UTF-8', 'UTF-8');
$str = htmlentities($str, ENT_QUOTES, 'UTF-8');
Bu bile IE6'yı UTF'yi işleme biçimi nedeniyle savunmasız bırakır. Ancak, IE6 kullanımı düşene kadar ISO-8859-1 gibi daha sınırlı bir kodlamaya geri dönebilirsiniz.
Çok baytlı problemlerle ilgili daha derinlemesine bir çalışma için bkz. Https://stackoverflow.com/a/12118602/1820