如果使用者輸入的是直接插入到一個SQL語句中的查詢,應用程式會很容易受到SQL注入,例如下面的範例:
<code><span>$unsafe_variable</span> = <span>$_POST</span>[<span>'user_input'</span>]; mysql_query(<span>"INSERT INTO table (column) VALUES ('"</span> . <span>$unsafe_variable</span> . <span>"')"</span>);</code>
這是因為使用者可以輸入類似VALUE”); DROP TABLE表; - ,讓查詢變成:
<code><span><span>INSERT</span><span>INTO</span><span>table</span> (<span>column</span>) <span>VALUES</span>(<span>'VALUE'</span>);</span><span><span>DROP</span><span>TABLE</span><span>table</span>;</span>'</code>
我們該怎麼防止這種情況呢?下面我們來看看Theo的回答
使用預備義語句和參數化查詢。對於帶有任何參數的sql語句都會被傳送到資料庫伺服器,並被解析!對於攻擊者想要惡意注入sql是不可能的!
要實現這一目標基本上有兩種選擇:
1.使用PDO(PHP Data Objects )
<code><span>$stmt</span> = <span>$pdo</span>->prepare(<span>'SELECT * FROM employees WHERE name = :name'</span>); <span>$stmt</span>->execute(<span>array</span>(<span>':name'</span> => <span>$name</span>)); <span>foreach</span> (<span>$stmt</span><span>as</span><span>$row</span>) { <span>// do something with $row</span> }</code>
2.使用mysqli
<code><span>$stmt</span><span>=</span><span>$dbConnection</span><span>-></span>prepare(<span>'SELECT * FROM employees WHERE name = ?'</span>); <span>$stmt</span><span>-></span>bind_param(<span>'s'</span>, <span>$name</span>); <span>$stmt</span><span>-></span>execute(); <span>$result</span><span>=</span><span>$stmt</span><span>-></span>get_result(); <span>while</span> (<span>$row</span><span>=</span><span>$result</span><span>-></span>fetch_assoc()) { <span>// do something with $row</span> }</code>
PDO(PHP資料物件)
注意當使用PDO存取MySQL資料庫真正的預備義語句並不是預設使用的!為了解決這個問題,你必須停用仿真準備好的語句。使用PDO建立連接的例子如下:
<code><span>$dbConnection</span><span>=</span><span>new</span> PDO(<span>'mysql:dbname=dbtest;host=127.0.0.1;charset=utf8'</span>, <span>'user'</span>, <span>'pass'</span>); <span>$dbConnection</span><span>-></span>setAttribute(PDO<span>::ATTR_EMULATE_PREPARES</span>, <span>false</span>); <span>$dbConnection</span><span>-></span>setAttribute(PDO<span>::ATTR_ERRMODE</span>, PDO<span>::ERRMODE_<strong>Exception</strong></span>);</code>
在上面例子中錯誤模式ERRMODE不是嚴格必須的,但建議添加它。當執行出錯產生致命錯誤時,這種方法腳本不會停止。並給開發人員捕捉任何錯誤的機會(當拋出PDOException異常時)。
setAttribute()那一行是強制性的,它告訴PDO禁用仿真預備義語句,使用真正的預備義語句。這可以確保語句和值在發送給MySQL資料庫伺服器前不被PHP解析(攻擊者沒有機會注入惡意的SQL).
當然你可以在建構子選項中設定字元集參數,特別注意’老’的PHP版本(5.3.6)會在DSN中忽略掉字符集參數。
Explanation(解釋)
在你傳遞的sql預備義語句 被資料庫伺服器解析和編譯會發生什麼事?透過指定的字元(在上面範例中像a?或像:name)告訴資料庫引擎你想要過濾什麼.然後呼叫execute執行結合好的預備義語句和你指定的參數值.
這裡最重要的是,該參數值是和預編譯的語句結合的,而不是和一個SQL字符串.SQL注入的工作原理是通過欺騙手段創建的SQL腳本包括惡意字符串發送到數據庫.因此,通過發送實際的分開的sql參數,你會降低風險.使用準備好的語句時,你發送的任何參數,將只被視為字符串(雖然數據庫引擎可能會做一些參數的優化,當然最終可能會為數字).在上面的例子中,如果變數$name包含'sarah';DELETE * FROM employees,結果只會是一個搜尋的字串「'sarah';DELETE * FROM employees」,你不會得到一個空表。
使用準備好的語句的另一個好處是,如果你在同一會話中多次執行相同的語句,這將只被解析和編譯一次,給你一些的速度增長。
哦,既然你問如何進行插入,這裡有一個例子(使用PDO):
<code><span>$preparedStatement</span><span>=</span><span>$db</span><span>-></span>prepare(<span>'INSERT INTO table (column) VALUES (:column)'</span>); <span>$preparedStatement</span><span>-></span>execute(<span>array</span>(<span>':column'</span><span>=></span><span>$unsafeValue</span>));</code>
http://www.jb51.net/article/36042.htm
以上就介紹了PHP防止SQL注入的方法(2),包括了方面的內容,希望對PHP教程有興趣的朋友有幫助。