SQL 注入

2022-05-20 16:35 更新

SQL 注入


 如果你從網(wǎng)頁中獲取用戶輸入,并將其插入到 SQL 數(shù)據(jù)庫中的話,那么你很可能已經(jīng)暴露于一種被稱作 SQL 注入的安全風(fēng)險(xiǎn)之下了。

 本節(jié)將會(huì)教你如何防止 SQL 注入,以及如何保護(hù) Perl 這樣的服務(wù)器端腳本中的程序和 SQL 語句。

 注入通常發(fā)生在獲取用戶輸入的時(shí)候,例如預(yù)期得到用戶的名字,但是得到的卻是一段很可能會(huì)在你不知情的情況下運(yùn)行的 SQL 語句。

 絕對(duì)不要相信用戶提供的數(shù)據(jù),處理這些數(shù)據(jù)之前必須進(jìn)行驗(yàn)證;通常,驗(yàn)證工作由模式匹配來完成。

 下面的例子中,name 僅限由字母、數(shù)字和下劃線組成,并且長(zhǎng)度在 8 到 20 之間(你可以根據(jù)需要修改這些規(guī)則)。

if (preg_match("/^\w{8,20}$/", $_GET['username'], $matches))
{
   $result = mysql_query("SELECT * FROM CUSTOMERS 
                          WHERE name=$matches[0]");
}
else 
{
   echo "user name not accepted";
}

 為了展示問題所在,請(qǐng)考慮下面這段代碼:

// supposed input
$name = "Qadir'; DELETE FROM CUSTOMERS;";
mysql_query("SELECT * FROM CUSTOMSRS WHERE name='{$name}'");

 下面的函數(shù)調(diào)用本來是要從 CUSTOMERS 表中取得 name 字段與用戶給定的輸入相匹配的記錄。通常情況下,$name 只包含字母和數(shù)字,或許還有空格,例如字符串 ilia。但是,這里通過在 $name 上附加一段全新的查詢語句,將原有的函數(shù)調(diào)用變?yōu)榱藬?shù)據(jù)庫的災(zāi)難:注入的 DELETE 語句將會(huì)刪除表中所有的記錄。

 幸運(yùn)的是,如果你在使用 MySQL 的話,mysql_query() 函數(shù)不允許查詢堆積(query stacking),或者說在一次函數(shù)調(diào)用中執(zhí)行多次 SQL 查詢。如果你試圖進(jìn)行堆積式查詢的話,函數(shù)調(diào)用將會(huì)失敗。

 然而,其他的 PHP 數(shù)據(jù)庫擴(kuò)展,例如 SQLite 和 PostgreSQL 會(huì)愉快地接受堆積式查詢,執(zhí)行字符串中所有的查詢,并由此產(chǎn)生嚴(yán)重的安全問題。


阻止 SQL 注入


 你可以在 Perl 或者 PHP 等腳本語言中巧妙地處理所有的轉(zhuǎn)義字符。PHP 的 MySQL 擴(kuò)展提供了一個(gè) mysql_real_escape_string() 函數(shù),來轉(zhuǎn)義那些對(duì) MySQL 有特殊意義的字符。

if (get_magic_quotes_gpc()) 
{
  $name = stripslashes($name);
}
$name = mysql_real_escape_string($name);
mysql_query("SELECT * FROM CUSTOMERS WHERE name='{$name}'");

LIKE 困境


 要破解 LIKE 困境,必須有一種專門的轉(zhuǎn)義機(jī)制,將用戶提供的 '%' 和 '_' 轉(zhuǎn)換為字面值。為此你可以使用 addcslashes() 函數(shù),該函數(shù)允許指定要進(jìn)行轉(zhuǎn)義的字符的范圍。

$sub = addcslashes(mysql_real_escape_string("%str"), "%_");
// $sub == \%str\_
mysql_query("SELECT * FROM messages 
             WHERE subject LIKE '{$sub}%'");
以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)