防止PHP中的SQL注入
SQL注入是一種漏洞,當未經修改的使用者輸入錯誤地插入SQL查詢時就會出現這種漏洞。這可能導致攻擊者執行任意SQL程式碼,進而對應用程式造成災難性後果。
為了防止SQL注入,至關重要的是將資料與SQL分離,確保資料始終保持為數據,而絕不會被SQL解析器解釋為命令。這可以透過使用帶有參數的預處理語句來實現,預處理語句將SQL查詢與任何參數分開傳送到資料庫伺服器進行解析。這樣,攻擊者就無法注入惡意SQL。
有兩種方法可以實現:
<code class="language-php">$stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name'); $stmt->execute(['name' => $name]); foreach ($stmt as $row) { // 处理 $row }</code>
PHP 8.2 :
<code class="language-php">$result = $db->execute_query('SELECT * FROM employees WHERE name = ?', [$name]); while ($row = $result->fetch_assoc()) { // 处理 $row }</code>
PHP 8.1及更低版本:
<code class="language-php">$stmt = $db->prepare('SELECT * FROM employees WHERE name = ?'); $stmt->bind_param('s', $name); // 's' 指定变量类型 -> 'string' $stmt->execute(); $result = $stmt->get_result(); while ($row = $result->fetch_assoc()) { // 处理 $row }</code>
如果您連接到非MySQL資料庫,您可以參考特定於驅動程式的第二個選項(例如,PostgreSQL的pg_prepare()
和pg_execute()
)。 PDO是一個通用的選擇。
正確的連接配置
使用PDO存取MySQL資料庫時,預設不會使用真正的預處理語句。為了解決這個問題,需要停用預處理語句的模擬。以下是如何使用PDO建立連線的範例:
<code class="language-php">$dbConnection = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8mb4', 'user', 'password'); $dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); $dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);</code>
對於MySQLi,需要執行相同的操作:
<code class="language-php">mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); // 错误报告 $dbConnection = new mysqli('127.0.0.1', 'username', 'password', 'test'); $dbConnection->set_charset('utf8mb4'); // 编码</code>
說明
您傳遞給prepare
的SQL查詢由資料庫伺服器解析和編譯。透過指定參數(無論是?
還是命名參數,如上面的:name
範例),您告訴資料庫核心您想要根據什麼進行篩選。然後,當呼叫execute
時,預處理查詢會與您提供的參數值結合。
重要的是,參數值與已編譯的查詢結合,而不是與SQL字串結合。 SQL注入透過欺騙腳本,在建立要傳送到資料庫的SQL時包含惡意字串來運作。因此,透過將實際的SQL與參數分開發送,您可以降低獲得意外結果的風險。
使用預處理語句傳送的任何參數都將被簡單地視為字串(儘管資料庫核心可能會執行一些最佳化,因此參數也可能是數字)。在上面的範例中,如果變數$name
包含'Sarah'; DELETE FROM employees
,結果將只是搜尋字串"'Sarah'; DELETE FROM employees "
,您的表格不會被清空。
使用預處理語句的另一個優點是,如果您在同一個會話中執行多次相同的查詢,則只解析和編譯一次,從而提高速度。
以上是如何防止PHP應用中的SQL注入?的詳細內容。更多資訊請關注PHP中文網其他相關文章!