SQL 注入

Table of content


如果您透過網頁獲取使用者輸入並將其插入 SQL 資料庫,則您可能存在一個名為SQL 注入的安全漏洞風險。本章將教您如何預防此問題,並幫助您保護伺服器端指令碼(例如 PERL 指令碼)中的指令碼和 SQL 語句的安全。

SQL 注入

SQL 注入是一種安全攻擊,它利用資料庫中的漏洞來執行惡意查詢。這將允許攻擊者訪問敏感資料,篡改資料以及永久刪除資料。

注入通常發生在您向用戶索取輸入(例如他們的姓名)時,他們提供的不是姓名,而是一個您會在不知情的情況下在資料庫上執行的 SQL 語句。永遠不要信任使用者提供的資料,只有在驗證後才能處理此資料;通常,這是透過模式匹配完成的。

示例

在下面的示例中,name 限制為字母數字字元加上下劃線,長度在 8 到 20 個字元之間(您可以根據需要修改這些規則)。

if (preg_match("/^\w{8,20}$/", $_GET['username'], $matches)) {
   $result = mysqli_query("SELECT * FROM CUSTOMERS 
      WHERE name = $matches[0]");
} else {
   echo "user name not accepted";
}

為了演示這個問題,請考慮以下摘錄:

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

此函式呼叫應該從 CUSTOMERS 表中檢索一條記錄,其中 name 列與使用者指定的 name 匹配。在正常情況下,$name 只包含字母數字字元和空格。但是在這裡,透過將一個全新的查詢附加到 $name,對資料庫的呼叫變成了災難;注入的 DELETE 查詢刪除了 CUSTOMERS 表中的所有記錄。

幸運的是,如果您使用的是 MySQL,mysqli_query() 函式不允許查詢堆疊或在一個函式呼叫中執行多個 SQL 查詢。如果您嘗試堆疊查詢,則呼叫會失敗。

但是,其他 PHP 資料庫擴充套件(例如SQLitePostgreSQL)會愉快地執行堆疊查詢,執行一個字串中提供的所有查詢,並造成嚴重的安全問題。

防止 SQL 注入

您可以在 PERL 和 PHP 等指令碼語言中巧妙地處理所有跳脫字元。PHP 的 MySQL 擴充套件提供了函式mysql_real_escape_string() 來轉義對 MySQL 特殊的輸入字元。

if (get_magic_quotes_gpc()) {
   $name = stripslashes($name);
}
$name = mysql_real_escape_string($name);
mysqli_query("SELECT * FROM CUSTOMERS WHERE name='{$name}'");

LIKE 難題

為了解決 LIKE 難題,自定義轉義機制必須將使用者提供的 '%' 和 '_' 字元轉換為字面量。使用addcslashes(),這是一個允許您指定要轉義的字元範圍的函式。

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