SQL 注入是 Web 應用程式中最常見也最危險的安全漏洞之一。其核心成因在於開發者未對用戶輸入數據進行有效驗證與過濾,導致惡意 SQL 代碼被拼接進查詢語句並執行。攻擊者可透過精心構造的輸入參數,竊取、篡改甚至刪除數據庫中的敏感數據。
假設一個查詢用戶資料的頁面 user.php?id=2,後端 SQL 為:
SELECT * FROM users WHERE id = 2
若攻擊者提交 id=2 AND EXISTS (SELECT id FROM admin),且程式未過濾,最終執行的 SQL 變為:
SELECT * FROM users WHERE id = 2 AND EXISTS (SELECT id FROM admin)
攻擊者即可根據頁面回應判斷 admin 表是否存在,進而推測資料庫結構。
使用 PDO 或 MySQLi 的預處理語句,將 SQL 邏輯與數據分離,從根本上杜絕注入:
<?php
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$stmt = $pdo->prepare('SELECT * FROM users WHERE id = :id');
$stmt->execute(['id' => $_GET['id']]);
$user = $stmt->fetch();
?>
(int)$_GET['id'] 強制轉為整數mysqli_real_escape_string() 或 PDO::quote()(僅作為輔助,不可替代參數化查詢)資料庫帳號僅授予必要權限(如僅 SELECT、INSERT),禁止 DROP、TRUNCATE 等高危操作。
生產環境關閉 display_errors,避免 SQL 錯誤洩露表結構:
ini_set('display_errors', '0');
error_reporting(E_ALL & ~E_NOTICE);
| 配置項 | 建議值 | 說明 |
|---|---|---|
| register_globals | Off | 防止變量覆蓋漏洞(PHP 5.4+ 已移除) |
| allow_url_fopen | Off | 禁止遠程文件包含 |
| expose_php | Off | 隱藏 PHP 版本資訊 |
| session.cookie_httponly | 1 | 防止 XSS 竊取 Session ID |
| session.use_strict_mode | 1 | 拒絕未初始化的 Session ID |
部署 ModSecurity + OWASP CRS 規則集,攔截已知攻擊特徵。
啟用慢查詢日誌、審計日誌,異常查詢實時告警。
使用 SQLMap、OWASP ZAP 等工具進行自動化滲透測試。
SQL 注入防禦的核心在於「不信任任何輸入」。採用參數化查詢作為第一道防線,配合輸入驗證、最小權限、錯誤隱藏等纵深防禦體系,才能構建真正安全的 PHP 應用。