我必須在一個主要安全問題的舊站點上工作:SQL注入非常容易執行。準備語句時防止SQL注入的最佳方法是不可能的
很顯然,防止這種攻擊的最好方法就是逃避查詢中使用的內容(使用PDO編寫語句,使用MySql編寫mysql_real_escape_string等),但我們無法快速完成這些工作:整個站點都是程序化的PHP(沒有課程),查詢到處都是「準備好」的,每天有數百頁和數千用戶,而且新版本將盡快出現。
因此,從今天上午開始,每個請求都會調用以下函數,根據關鍵字檢測可疑的POST或GET參數。
const SQLI_UNSAFE = 3;
const SQLI_WARNING = 2;
const SQLI_SAFE = 1;
const SQLI_MAIL_DEST = '[email protected]';
function sqlicheck() {
$params = array_merge($_GET, $_POST);
$is_warning = false;
foreach($params as $key=>$param) {
switch(getSafeLevel($param)) {
case SQLI_SAFE:
break;
case SQLI_WARNING:
$is_warning = true;
break;
case SQLI_UNSAFE:
mail(SQLI_MAIL_DEST, 'SQL INJECTION ATTACK', print_r($_REQUEST, true).' '.print_r($_SERVER, true));
header('Location: http://monsite/404.php');
exit();
}
}
if($is_warning === true) {
mail(SQLI_MAIL_DEST, 'SQL INJECTION WARNING', print_r($_REQUEST, true).print_r($_SERVER, true));
}
}
function getSafeLevel($param) {
$error_words = array('select%20','drop%20','delete%20','truncate%20','insert%20','%20tbclient','select ','drop ','delete ','truncate ','insert ',);
$warning_words = array('%20','select','drop','delete','truncate', ';','union');
foreach($error_words as $error_word) {
if(stripos($param, $error_word) !== false) return SQLI_UNSAFE;
}
foreach($warning_words as $warning_word) {
if(stripos($param, $warning_word) !== false) return SQLI_WARNING;
}
return SQLI_SAFE;
}
這似乎可以檢測到某種類型的攻擊,但它顯然非常基本。任何想法來改善它?任何重大問題?
有什麼用途來確定試圖進行注射的位置? – 2011-06-09 14:02:20
準確地說:目的是檢測到哪裏和可能是誰,如果有任何風險立即糾正它,並且我們確定將黑客重定向到404。 – LFI 2011-06-09 14:13:23
您還應該包含一個安全的詞,它是'香蕉'。 – 2011-06-09 14:18:59