標籤:
如果使用者的輸入不加修改就插入到SQL查詢裡,這個應用程式會容易受到SQL注入,就像下面這樣:
$unsafe_variable = $_POST[‘user_input‘];
mysql_query("INSERT INTO `table` (`column`) VALUES (‘$unsafe_variable‘)");
這是因為使用者能夠輸入像value‘); DROP TABLE table;--之類的代碼,然後這個查詢就變成了:
INSERT INTO `table` (`column`) VALUES(‘value‘); DROP TABLE table;--‘)
怎麼才能防止這樣的情況發生呢?
支援率最高回答:
使用預先處理語句很參數化查詢。這些是被資料庫伺服器獨立於任何參數進行發送和解析的SQL語句。這種方法讓攻擊者注入惡意代碼變得不可能。
你基本上有兩種選擇來實現:
1.使用PDO:
$stmt = $pdo->prepare(‘SELECT * FROM employees WHERE name = :name‘);
$stmt->execute(array(‘name‘ => $name));
foreach ($stmt as $row) {
// do something with $row
}
2.使用MySQLi:
$stmt = $dbConnection->prepare(‘SELECT * FROM employees WHERE name = ?‘);
$stmt->bind_param(‘s‘, $name);
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
// do something with $row
}
PDO
需要注意的時,當使用PDO訪問MySQL資料庫時,預設情況下不使用真正的預先處理語句。要解決這個問題你必須金庸預先處理語句的模擬。使用PDO建立連結的一個樣本如下:
$dbConnection = new PDO(‘mysql:dbname=dbtest;host=127.0.0.1;charset=utf8‘, ‘user‘,
‘pass‘);
$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
上面的樣本裡的錯誤模式不是嚴格必須的,但是建議添加上它。這樣的指令碼在出現錯誤時不會因為致命錯誤而終止,並且他還讓開發人員有機會捕捉到PDO異常拋出的任何錯誤。
第一行的setAttribute( )是強制性的,它告訴PDO禁用類比預先處理語句並使用真正的預先處理語句。這保證了語句和值在被發送到MySQL伺服器之前不會被PHP解析(不給潛在的攻擊者注入惡意的SQL的機會)。
雖然你可以在建構函式的選項中設定字元集,但要注意舊版本的PHP(小於5.3.6)會在DSN中自動忽略字元集參數。
解釋
上面的代碼會讓你傳給prepare的SQL語句被資料庫伺服器解析並編譯。通過指定參數(可以是一個問號或者上面例子裡的像:name的具名引數)你告訴資料庫引擎過濾哪些部分。然後你調用執行,預先處理語句和你指定的參數值就結合起來了。
這裡重要的是,參數值是與已經編譯的語句進行結合,而不是與SQL字串。SQL注入通過在它建立SQL發送到資料庫時用包含惡意的字串欺騙指令碼的方式來實現。所以通過發送獨立於參數的實際的SQL,你就會限制住一些你並不希望出現的事情的風險。你使用預先處理語句發送的任何參數都只會被視為字串(儘管資料庫引擎可能會做一些最佳化,然後參數也可能成為數字)。在上面的樣本中,如果$name變數包含‘Sarah‘;DELETE FROM employees結果僅僅是對字串"‘Sarah‘;DELETE FROM employees"的搜尋,你不會得到一個空表。
使用預先處理語句的另一個好處就是如果你在同一個會話中多次執行相同的語句只會被解析和編譯一次,這會給你一些速度上的益處。既然你問到了如何插入,這裡有一個使用PDO的樣本:
$preparedStatement = $db->prepare(‘INSERT INTO table (column)
VALUES (:column)‘);
$preparedStatement->execute(array(‘column‘ => $unsafeValue));
原文:http://www.php100.com/html/it/focus/2014/1020/7539.html
[轉]PHP防止SQL注入攻擊