首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

PHP 防 SQL 注入 7 大鐵律:從參數過濾到 PDO 預處理的纵深防禦

     編輯:MySQL 資料庫相關知識

前言

SQL 注入仍是 Web 應用頭號風險。單一防禦易失效,**纵深防禦**才是正道。本文總結 7 大必做防範點,構建多層防線。

七大防注入鐵律

1. 數字型參數:強制類型轉換

// ❌ 危險:$id = $_GET['id']; "SELECT * FROM users WHERE id=$id"
// ✅ 安全:強制轉整型/浮點
$id = intval($_GET['id']);        // 整數
$price = floatval($_GET['price']); // 浮點
$sql = "SELECT * FROM users WHERE id=$id";

原理:`intval`/`floatval` 會截取數字部分,非數字字符串變為 0,徹底消除注入可能。

2. 字符串型參數:使用驅動級轉義函數

// ❌ 危險:addslashes() 不處理字符集、多字節繞過
// ✅ 安全:mysqli_real_escape_string / PDO::quote (需連接上下文)
$name = $mysqli->real_escape_string($_GET['name']);
$sql = "SELECT * FROM users WHERE name='$name'";

⚠️ **注意**:`mysqli_real_escape_string` 需要**已建立連接**且**字符集一致** (推薦 `SET NAMES utf8mb4`)。

3. 棄用拼接 SQL,全面擁抱 PDO 預處理 (核心防線)

// ✅ 最佳實踐:預處理 + 參數綁定
$pdo = new PDO("mysql:host=localhost;dbname=test;charset=utf8mb4", $user, $pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ? AND status = ?");
$stmt->execute([$id, $status]);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

優勢:SQL 解析與數據傳輸分離,參數永遠作為數據而非代碼執行,**從根本上杜絕注入**。

4. URL Rewrite 隱藏真實參數 + 正則過濾可疑輸入

  • Nginx/Apache Rewrite 將 `/user/123` 映射到 `/user.php?id=123`,隱藏參數名。
  • WAF/中間件層攔截含 `union select`, `sleep(`, `benchmark(`, `/*`, `--`, `'` 等特徵的請求。

5. 關閉錯誤回顯,不洩露敏感信息

; php.ini
display_errors = Off
log_errors = On
error_log = /var/log/php_errors.log

生產環境**絕不**向用戶顯示 SQL 錯誤堆棧 (表結構、字段名、SQL 片段全暴露)。

6. 錯誤日志記錄與定期審計

  • PHP `error_log` 記錄所有錯誤。
  • MySQL `general_log` / `slow_log` 記錄疑似注入的慢查詢/異常 SQL。
  • Web 訪問日志 (Nginx/Apache) 定期分析異常參數模式。

7. 數據庫賬號最小權限:禁用 FILE 權限、拒絕 Root 直連

-- 應用賬號僅授予增刪改查
GRANT SELECT, INSERT, UPDATE, DELETE ON app_db.* TO 'app_user'@'%' IDENTIFIED BY 'StrongPass!';
-- 禁止: GRANT FILE, GRANT ALL, GRANT SUPER, GRANT SHUTDOWN

原理:即使注入成功,攻擊者無法 `LOAD_FILE('/etc/passwd')`、`INTO OUTFILE` 寫 webshell、操作系統表。

纵深防禦體系圖

[客戶端輸入] 
    ↓ (1. 前端校驗 - 體驗非安全)
[WAF/網關層] 
    ↓ (2. 正則攔截明顯攻擊特徵 - 3. Rewrite 隱藏結構)
[應用層 - PHP] 
    ↓ (4. intval/real_escape_string - 5. PDO Prepared Statements 核心)
[數據庫層 - MySQL] 
    ↓ (6. 最小權限賬號 - 7. 錯誤不回顯 - 審計日志)
[業務邏輯]

常見誤區避坑

誤區風險正確做法
用 `addslashes()` 防注入多字節字符集 (GBK) 可繞過用驅動級 `real_escape_string` 或 PDO
信任 `PDO::ATTR_EMULATE_PREPARES = true` (默認)模擬預處理,本質仍是拼接,有繞過風險設置 `$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);` 使用原生預處理
框架 ORM 就安全了原生查詢 / 拼接片段 仍可能注入審計所有 `whereRaw`、`execute`、拼接 SQL 代碼
只過濾關鍵字 `select union`大小寫、編碼、註釋繞過無窮無盡參數化查詢才是銀彈

總結

**PDO 預處理 (關閉模擬) 是核心銀彈**,配合**最小權限賬號**、**關閉錯誤回顯**、**WAF 前置過濾**、**日志審計**,構建纵深防禦。安全無絕對,但提高攻擊成本至不可接受,即是勝利。

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