如果需要通過網(wǎng)頁需要用戶輸入的數(shù)據(jù)并將其插入到一個SQL數(shù)據(jù)庫,可能會留下敞開稱為SQL注入安全問題。
這一課將教你如何防止這種情況的發(fā)生,并幫助您保護服務(wù)器端腳本,如Perl腳本中使用的SQL語句。
注入通常當要求一個用戶輸入,就如他們的名字,但他們給你不是一個名字,會在不知不覺中對數(shù)據(jù)庫運行SQL語句時發(fā)生問題。
千萬不要信任用戶提供的數(shù)據(jù),處理這些數(shù)據(jù)只是驗證后;作為一項規(guī)則,通過模式匹配進行。
在下面的例子中,該名稱被限制為字母數(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)用應(yīng)該檢索來自CUSTOMERS表,其中name列相匹配用戶指定名稱的記錄。在正常情況下,$name應(yīng)該只包含字母數(shù)字字符和或許空格,如字符串ilia。 但在這里,通過附加一個全新的查詢$name,調(diào)用數(shù)據(jù)庫變成災(zāi)難:注入DELETE查詢刪除所有記錄的客戶。
幸運的是,如果你使用MySQL,在mysql_query()函數(shù)不允許查詢堆疊或一個函數(shù)調(diào)用執(zhí)行多個SQL查詢。 如果您嘗試堆疊查詢,調(diào)用失敗。
然而,其他PHP數(shù)據(jù)庫擴展,如SQLite和PostgreSQL,愉快地進行堆查詢,執(zhí)行都在一個字符串提供的查詢,并創(chuàng)建一個嚴重的安全問題。
您可以在腳本語言,如Perl和PHP巧妙地處理所有轉(zhuǎn)義字符。MySQL擴展為PHP提供的函數(shù)mysql_real_escape_string()來轉(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問題,一個自定義的轉(zhuǎn)義機制必須將用戶提供的'%'和'_'字符文字。 使用addslashes()函數(shù),可以讓你指定一個字符范圍轉(zhuǎn)義。
$sub = addcslashes(mysql_real_escape_string("%str"), "%_"); // $sub == \%str\_ mysql_query("SELECT * FROM messages WHERE subject LIKE '{$sub}%'");