PHP中如何防止SQL注入攻擊?
P粉939473759
2023-08-22 10:23:01
<p>如果使用者輸入未經修改地插入SQL查詢中,則應用程式將變得容易受到SQL注入攻擊,就像以下範例所示:</p>
<pre class="lang-php prettyprint-override"><code>$unsafe_variable = $_POST['user_input'];
mysql_query("INSERT INTO `table` (`column`) VALUES ('$unsafe_variable')");
</code></pre>
<p>這是因為使用者可以輸入類似 <code>value'); DROP TABLE table;--</code> 的內容,查詢將變成:</p>
<pre class="brush:php;toolbar:false;">INSERT INTO `table` (`column`) VALUES('value'); DROP TABLE table;--')</pre>
<p>如何防止這種情況發生? </p>
要使用參數化查詢,您需要使用Mysqli或PDO。要使用mysqli重寫您的範例,我們需要類似以下的程式碼。
您可能需要閱讀的關鍵函數是
mysqli::prepare
。此外,正如其他人建議的那樣,您可能會發現使用PDO等更高級的抽象層會更有用/更容易。
請注意,您提到的情況相當簡單,更複雜的情況可能需要更複雜的方法。特別是:
mysql_real_escape_string
中。在這種情況下,最好將使用者的輸入透過白名單傳遞,以確保只允許通過「安全」值。無論您使用哪個資料庫,避免SQL注入攻擊的正確方法是將資料與SQL分離,讓資料保持資料的形式,永遠不會被SQL解析器解釋為指令。可以建立具有正確格式化資料部分的SQL語句,但如果您不完全了解細節,您應該始終使用預處理語句和參數化查詢。這些是將SQL語句與任何參數分開傳送並由資料庫伺服器分析的SQL語句。這樣,攻擊者就無法注入惡意SQL。
基本上有兩種方法可以實現這一點:
使用PDO(適用於任何支援的資料庫驅動程式):
使用MySQLi(適用於MySQL):
自PHP 8.2 以來,我們可以使用
execute_query()
方法來準備、綁定參數和執行SQL語句:在PHP8.1之前:
如果您連接的是MySQL以外的資料庫,可以參考特定於驅動程式的第二個選項(例如,對於PostgreSQL,可以使用
pg_prepare()
和pg_execute()
)。 PDO是通用選項。正確設定連接
PDO
請注意,當使用PDO存取MySQL資料庫時,預設會不會使用真正的預處理語句。為了解決這個問題,您需要停用預處理語句的模擬。以下是使用PDO建立連線的範例:
在上面的範例中,錯誤模式並不是嚴格必要的,但建議添加它。這樣PDO將透過拋出
PDOException
來通知您所有的MySQL錯誤。然而,必須的是第一行
setAttribute()
,它告訴PDO禁用模擬的預處理語句並使用真正的預處理語句。這樣確保語句和值在傳送到MySQL伺服器之前不會由PHP解析(使潛在的攻擊者無法注入惡意SQL)。雖然您可以在建構函式的選項中設定
charset
,但需要注意的是,「舊版」PHP(5.3.6之前)在DSN中靜默忽略了charset參數。Mysqli
對於mysqli,我們需要遵循相同的例程:
解釋
您傳遞給
prepare
的SQL語句由資料庫伺服器解析和編譯。透過指定參數(在上面的範例中,可以是?
或命名參數,例如:name
),您告訴資料庫引擎您要在哪裡進行過濾。然後,當您呼叫execute
時,準備好的語句將與指定的參數值組合。這裡重要的是參數值與編譯後的語句組合,而不是與SQL字串組合。 SQL注入是透過欺騙腳本在建立要傳送到資料庫的SQL時包含惡意字串來運作的。因此,透過將實際的SQL與參數分開發送,可以限制意外結果的風險。
使用預處理語句傳送的任何參數都將被視為字串(儘管資料庫引擎可能會對參數進行一些最佳化,因此參數最終可能是數字)。在上面的範例中,如果
$name
變數包含'Sarah'; DELETE FROM employees
,結果將僅是搜尋字串"'Sarah'; DELETE FROM employees"
,您將不會得到一個空表。使用預處理語句的另一個好處是,如果在同一會話中執行多次相同的語句,它只會被解析和編譯一次,從而提高一些速度。
哦,既然您問到如何對插入進行操作,這裡有一個範例(使用PDO):
預處理語句是否適用於動態查詢?
雖然您仍然可以對查詢參數使用預處理語句,但動態查詢本身的結構無法進行參數化,並且某些查詢功能也無法進行參數化。
對於這些特定的場景,最好的做法是使用白名單過濾器來限制可能的值。