位置:首頁 > 數據庫 > SQL教學 > SQL注入

SQL注入

如果需要通過網頁需要用戶輸入的數據並將其插入到一個SQL數據庫,可能會留下敞開稱為SQL注入安全問題。

這一課將教你如何防止這種情況的發生,並幫助您保護服務器端腳本,如Perl腳本中使用的SQL語句。

注入通常當要求一個用戶輸入,就如他們的名字,但他們給你不是一個名字,會在不知不覺中對數據庫運行SQL語句時發生問題。

千萬不要信任用戶提供的數據,處理這些數據隻是驗證後;作為一項規則,通過模式匹配進行。

在下麵的例子中,該名稱被限製為字母數字字符加下劃線並以8至20個字符之間的長度(根據需要修改這些規則)。

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}'");

函數調用應該檢索來自CUSTOMERS表,其中name列相匹配用戶指定名稱的記錄。在正常情況下,$name應該隻包含字母數字字符和或許空格,如字符串ilia。 但在這裡,通過附加一個全新的查詢$name,調用數據庫變成災難:注入DELETE查詢刪除所有記錄的客戶。

幸運的是,如果你使用MySQL,在mysql_query()函數不允許查詢堆疊或一個函數調用執行多個SQL查詢。 如果您嘗試堆疊查詢,調用失敗。

然而,其他PHP數據庫擴展,如SQLite和PostgreSQL,愉快地進行堆查詢,執行都在一個字符串提供的查詢,並創建一個嚴重的安全問題。

防止SQL注入:

您可以在腳本語言,如Perl和PHP巧妙地處理所有轉義字符。MySQL擴展為PHP提供的函數mysql_real_escape_string()來轉義特殊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問題,一個自定義的轉義機製必須將用戶提供的'%'和'_'字符文字。 使用addslashes()函數,可以讓你指定一個字符範圍轉義。

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