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

SQL 注入

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

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

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

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

下面的例子中,name 僅限由字母、數(shù)字和下劃線組成,并且長度在 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";
}

為了展示問題所在,請考慮下面這段代碼:

// 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ù)庫的災難:注入的 DELETE 語句將會刪除表中所有的記錄。

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

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

阻止 SQL 注入:

你可以在 Perl 或者 PHP 等腳本語言中巧妙地處理所有的轉(zhuǎn)義字符。PHP 的 MySQL 擴展提供了一個 mysql_real_escape_string() 函數(shù),來轉(zhuǎn)義那些對 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)義機制,將用戶提供的 '%' 和 '_' 轉(zhuǎn)換為字面值。為此你可以使用 addcslashes() 函數(shù),該函數(shù)允許指定要進行轉(zhuǎn)義的字符的范圍。

$sub = addcslashes(mysql_real_escape_string("%str"), "%_");
// $sub == \%str\_
mysql_query("SELECT * FROM messages 
             WHERE subject LIKE '{$sub}%'");