SQL 注入仍是 Web 應用首要風險。本文提供一套基於正則表達式的請求參數過濾類,並分析其優缺點與現代最佳實踐對比。
<?php
class SqlInjectionFilter {
private $patterns = [
'get' => "'|(and|or)\\b.+?(>|<|=|in|like)|/\\*.+?\\*/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)",
'post' => "\\b(and|or)\\b.{1,6}?(=|>|<|\\bin\\b|\\blike\\b)|/\\*.+?\\*/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)",
'cookie' => "\\b(and|or)\\b.{1,6}?(=|>|<|\\bin\\b|\\blike\\b)|/\\*.+?\\*/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)",
];
public function __construct() {
// 註冊自定義錯誤處理器,避免洩露路徑
set_error_handler(function($errno, $errstr, $errfile, $errline) {
error_log("[SQL_FILTER] {$errstr} in {$errfile}:{$errline}");
die('Illegal operation detected');
}, E_ERROR);
}
public function checkAll() {
foreach ($_GET as $k => $v) $this->check($k, $v, 'get');
foreach ($_POST as $k => $v) $this->check($k, $v, 'post');
foreach ($_COOKIE as $k => $v) $this->check($k, $v, 'cookie');
}
private function check($key, $value, $type) {
if (is_array($value)) $value = implode('', $value);
// 白名單機制:包含 securityToken 的請求跳過檢查
if (isset($_REQUEST['securityToken'])) return;
if (preg_match("/{$this->patterns[$type]}/is", $value)) {
$this->logAttack($key, $value, $type);
die('Illegal operation!');
}
}
private function logAttack($key, $value, $type) {
$log = sprintf(
"[%s] IP:%s | Type:%s | Key:%s | Value:%s\n",
date('c'),
$_SERVER['REMOTE_ADDR'] ?? 'unknown',
strtoupper($type),
$key,
$value
);
file_put_contents(__DIR__ . '/logs/sql_injection.log', $log, FILE_APPEND);
}
}
// 使用方式:在入口檔案最早期實例化
// new SqlInjectionFilter()->checkAll();
$patterns = [
'exec' => '(?i)(?s)*exec\\s+\\(\\s*\\w+\\)', // exec() 命令執行
'xss_simple'=> '(?i)(?s)*(<|%3C)\\s*/?\\s*[a-z0-9%]+\\s*(>|%3E)', // 簡單 XSS
'xss_eval' => '(?i)(?s)*(%65|e)\\s*(%76|v)\\s*(%61|a)\\s*(%6C|l)', // eval 關鍵字編碼
'xss_img' => '(?i)(?s)*(<|%3C)\\s*(img|IMG)[^>]*(>|%3E)', // 圖片標籤 XSS
'xss_script'=> '(?i)(?s)*(%73|s)\\s*(%63|c)\\s*(%72|r)\\s*(%69|i)\\s*(%70|p)\\s*(%74|t)', // script 標籤編碼
'sql_inject'=> '(?i)(?s)*((%27|\\')|(%3D|=)|(/|%2F)|(\\||%7C)|(%23|#)|(%3B|;))+' // SQL 特殊字符
];
| 維度 | 正則過濾方案 | 參數化查詢(Prepared Statements) |
|---|---|---|
| 防護原理 | 黑名單匹配,攔截可疑字符 | 白名單機制,數據與代碼分離 |
| 誤報率 | 高(正常內容可能含關鍵字) | 極低 |
| 漏報風險 | 高(繞過技巧層出不窮) | 極低(驅動層保證) |
| 效能影響 | 每請求多次正則匹配 | 可復用執行計劃,效能更好 |
| 維護成本 | 需持續更新正則 | 一次編寫,長期有效 |
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = ? AND status = ?');
$stmt->execute([$email, 1]);
結論:正則過濾可作為「深度防禦」的輔助層(如攔截明顯掃描器流量),但絕不能作為唯一防線。參數化查詢才是 SQL 注入的根治方案。