天天看點

PHP中該怎樣防止SQL注入?

  因為使用者的輸入可能是這樣的:

<a href="http://www.admin10000.com/document/4451.html">?</a>

1

<code>value'); DROP TABLE table;--</code>

  那麼SQL查詢将變成如下:

<code>INSERT</code> <code>INTO</code> <code>`</code><code>table</code><code>` (`</code><code>column</code><code>`)</code><code>VALUES</code><code>(</code><code>'value'</code><code>);</code><code>DROP</code> <code>TABLE</code> <code>table</code><code>;</code><code>--')</code>

  應該采取哪些有效的方法來防止SQL注入?

  使用預處理語句和參數化查詢。預處理語句和參數分别發送到資料庫伺服器進行解析,參數将會被當作普通字元處理。這種方式使得攻擊者無法注入惡意的SQL。 你有兩種選擇來實作該方法:

  1、使用PDO:

2

3

4

5

6

7

<code>$stmt</code> <code>=</code><code>$pdo</code><code>-&gt;prepare(</code><code>'SELECT * FROM employees WHERE name = :name'</code><code>);</code>

<code>$stmt</code><code>-&gt;execute(</code><code>array</code><code>(</code><code>'name'</code> <code>=&gt;</code><code>$name</code><code>));</code>

<code>foreach</code> <code>(</code><code>$stmt</code> <code>as</code> <code>$row</code><code>) {</code>

<code>    </code><code>// do something with $row</code>

<code>}</code>

  2、使用mysqli:

8

9

<code>$stmt = $dbConnection-&gt;prepare(</code><code>'SELECT * FROM employees WHERE name = ?'</code><code>);</code>

<code>$stmt-&gt;bind_param(</code><code>'s'</code><code>, $name);</code>

<code>$stmt-&gt;execute();</code>

<code>$result = $stmt-&gt;get_result();</code>

<code>while</code> <code>($row = $result-&gt;fetch_assoc()) {</code>

  注意,在預設情況使用PDO并沒有讓MySQL資料庫執行真正的預處理語句(原因見下文)。為了解決這個問題,你應該禁止PDO模拟預處理語句。一個正确使用PDO建立資料庫連接配接的例子如下:

<code>$dbConnection</code> <code>=</code><code>new</code> <code>PDO(</code><code>'mysql:dbname=dbtest;host=127.0.0.1;charset=utf8'</code><code>,</code><code>'user'</code><code>,</code><code>'pass'</code><code>);</code>

<code>$dbConnection</code><code>-&gt;setAttribute(PDO::ATTR_EMULATE_PREPARES, false);</code>

<code>$dbConnection</code><code>-&gt;setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);</code>

  當你将SQL語句發送給資料庫伺服器進行預處理和解析時發生了什麼?通過指定占位符(一個?或者一個上面例子中命名的 :name),告訴資料庫引擎你想在哪裡進行過濾。當你調用execute的時候,預處理語句将會與你指定的參數值結合。 關鍵點就在這裡:參數的值是和經過解析的SQL語句結合到一起,而不是SQL字元串。SQL注入是通過觸發腳本在構造SQL語句時包含惡意的字元串。是以,通過将SQL語句和參數分開,你防止了SQL注入的風險。任何你發送的參數的值都将被當作普通字元串,而不會被資料庫伺服器解析。回到上面的例子,如果$name變量的值為 ’Sarah’; DELETE FROM employees ,那麼實際的查詢将是在 employees 中查找 name 字段值為 ’Sarah’; DELETE FROM employees 的記錄。 另一個使用預處理語句的好處是:如果你在同一次資料庫連接配接會話中執行同樣的語句許多次,它将隻被解析一次,這可以提升一點執行速度。 如果你想問插入該如何做,請看下面這個例子(使用PDO):

<code>$preparedStatement = $db-&gt;prepare(</code><code>'INSERT INTO table (column) VALUES (:column)'</code><code>);</code>

<code>$preparedStatement-&gt;execute(array(</code><code>'column'</code> <code>=&gt; $unsafeValue));</code>