鍍金池/ 教程/ 數(shù)據(jù)庫(kù)/ SQL 注入
SQL AND 和 OR 連接運(yùn)算符
SQL 刪除數(shù)據(jù)庫(kù)
SQL 使用序列
SQL CONCAT 函數(shù)
SQL 使用視圖
SQL SELECT 語(yǔ)句
SQL 別名
SQL MAX 函數(shù)
SQL 創(chuàng)建表
SQL NULL 值
SQL 數(shù)據(jù)類型
SQL RAND 函數(shù)
SQL 臨時(shí)表
SQL INSERT 語(yǔ)句
SQL ALTER TABLE 命令
SQL 關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng)
SQL SUM 函數(shù)
SQL 子查詢
SQL UPDATE 語(yǔ)句
SQL 表達(dá)式
SQL 操作符
SQL ORDER BY 子句
SQL WHERE 子句
SQL 對(duì)結(jié)果進(jìn)行排序
SQL 注入
SQL AVG 函數(shù)
SQL 選擇數(shù)據(jù)庫(kù),USE 語(yǔ)句
SQL 克隆數(shù)據(jù)表
SQL COUNT 函數(shù)
SQL 語(yǔ)法
SQL DELETE 語(yǔ)句
SQL 約束
SQL 刪除表
SQL TOP、LIMIT 和 ROWNUM 子句
SQL 日期函數(shù)
SQL TRUNCATE TABLE 命令
SQL DISTINCT 關(guān)鍵字
SQL 處理重復(fù)數(shù)據(jù)
SQL 使用連接
SQL 索引
SQL 事務(wù)
SQL GROUP BY 子句
SQL HAVING 子句
SQL MIN 函數(shù)
SQL 概覽
SQL SQRT 函數(shù)
SQL LIKE 子句
SQL 通配符
SQL UNION 子句
SQL 數(shù)據(jù)庫(kù)
SQL 創(chuàng)建數(shù)據(jù)庫(kù)

SQL 注入

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

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

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

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

下面的例子中,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";
}

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

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

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

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

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

阻止 SQL 注入:

你可以在 Perl 或者 PHP 等腳本語(yǔ)言中巧妙地處理所有的轉(zhuǎn)義字符。PHP 的 MySQL 擴(kuò)展提供了一個(gè) mysql_real_escape_string() 函數(shù),來(lái)轉(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}%'");