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