首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 防 SQL 注入實戰(一):注入原理深度剖析與查詢構建陷阱

     編輯:PHP 綜合知識

本系列首篇,從最基礎的查詢構建過程切入,還原 SQL 注入產生的根本原因——「數據與代碼未分離」,為後續防禦方案奠定堅實認知基礎。

引言:PHP 的雙刃劍

PHP 以低門檻、高效率著稱,讓新手也能快速構建動態站點。但這份便利往往掩蓋了安全陷阱:當開發者習慣將用戶輸入直接拼接進 SQL 字符串,便為惡意數據打開了大門。

什麼是 SQL 注入?

本質上,注入發生在應用程序將不可信輸入作為代碼片段執行時。數據庫本意是存取數據,但當查詢構建邏輯允許外部數據改變 SQL 語義結構,攻擊者便能注入任意指令——讀取、篡改、刪除,甚至執行管理操作。

注入誕生的完整還原

以葡萄酒查詢為例,正常流程:

  1. 表單提交 variety=lagrein
  2. PHP 獲取:$variety = $_POST['variety']; // 值為 "lagrein"
  3. 構建查詢:$query = "SELECT * FROM wines WHERE variety='$variety'";
  4. 最終 SQL:SELECT * FROM wines WHERE variety='lagrein' ✅ 正常執行

但查詢實際構建過程是:

$query = "SELECT * FROM wines WHERE variety = '"; // 固定部分,單引號開啟
$query .= $variety;                              // 用戶輸入直接拼接
$query .= "'";                                   // 單引號閉合

攻擊者如何利用這一機制?

提交 variety=lagrein' OR 1=1;--,拼接後變為:

SELECT * FROM wines WHERE variety = 'lagrein' OR 1=1;--'

單引號提前閉合,OR 1=1 恆真條件生效,-- 註釋掉尾部單引號。結果:返回 wines 表所有記錄。

核心洞見:邊界模糊是禍根

SQL 解析器無法區分「開發者寫的代碼」與「用戶傳的數據」。在字符串拼接模式下,用戶輸入中的特殊字符(單引號、分號、註釋符)會被解析器視為 SQL 語法元素,從而改變查詢語義。

為什麼「過濾特殊字符」不可靠?

  • 黑名單永遠不全:編碼繞過(URL encode、Unicode、十六進制)、多字節字符集陷阱(GBK 雙字節吃掉反斜線)、新語法特性(MySQL 8.0 新函數/運算符)。
  • 上下文敏感:數值型字段無需引號,注入載荷 1 OR 1=1 完全不需要特殊字符。
  • 副作用大:過度過濾導致合法數據截斷(如 O'Reilly 變成 OReilly)。

正確的思維模型:代碼與數據分離

參數化查詢(預處理)通過預先編譯 SQL 模板,再綁定參數值,確保數據永遠不會被解析為 SQL 代碼:

// PDO 範例
$stmt = $pdo->prepare("SELECT * FROM wines WHERE variety = ?");
$stmt->execute([$variety]); // $variety 純粹作為數據值傳遞,無論內容如何都不改變 SQL 結構

本系列後續規劃

  1. 《註入攻擊類型全解析與多查詢風險》—— 知敵知己
  2. 《建立安全抽象層與改造現有應用》—— 工程落地
  3. 《實戰案例:從漏洞掃描到修復驗證》—— 閉環實踐

掌握原理,方能不被工具束縛;堅持參數化,方能高枕無憂。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved