SQL 注入仍是 OWASP Top 10 長年佔據前列的資安弱點。本文從攻擊者視角解析基於正則的盲注手法,並提供 PHP 端的偵測與防禦程式碼,幫助開發者建立多層次防護體系。
MySQL 5+ 的 information_schema 資料庫儲存了所有資料庫、資料表、欄位的中繼資料。攻擊者可透過布林盲注逐字推斷表名:
-- 1. 判斷第一個表名首字是否在 a-z 範圍
id=1 AND 1=(SELECT 1 FROM information_schema.tables
WHERE TABLE_SCHEMA="blind_sqli"
AND table_name REGEXP '^[a-z]' LIMIT 0,1) /*
-- 2. 縮小範圍至 a-n
id=1 AND 1=(SELECT 1 FROM information_schema.tables
WHERE TABLE_SCHEMA="blind_sqli"
AND table_name REGEXP '^[a-n]' LIMIT 0,1) /*
-- 3. 確定首字為 n
id=1 AND 1=(SELECT 1 FROM information_schema.tables
WHERE TABLE_SCHEMA="blind_sqli"
AND table_name REGEXP '^n' LIMIT 0,1) /*
-- 4. 遞迴推斷完整表名:news
'^n[a-z]' → '^ne[a-z]' → '^new[a-z]' → '^news[a-z]' → FALSE
驗證:table_name = 'news'
-- 5. 猜解下一個表:LIMIT 1,1 → LIMIT 2,1 ...
核心正則語法:
^ 字串開頭[a-z] 字元範圍REGEXP MySQL 正則比對運算子以下正則可用於 WAF、PHP 過濾器偵測常見攻擊向量:
<?php
// 命令執行特徵
$Exec_Commond = "(s|S)*(exec(s|+)+(s|x)pw+)(s|S)*";
// XSS 腳本標籤
$Simple_XSS = "(s|S)*((%3C)|<)((%2F)|/)*[a-z0-9%]+((%3E)|>)(s|S)*";
$Eval_XSS = "(s|S)*((%65)|e)(s)*((%76)|v)(s)*((%61)|a)(s)*((%6C)|l)(s|S)*";
$Image_XSS = "(s|S)*((%3C)|<)((%69)|i|I|(%49))((%6D)|m|M|(%4D))((%67)|g|G|(%47))[^n]+((%3E)|>)(s|S)*";
$Script_XSS = "(s|S)*((%73)|s)(s)*((%63)|c)(s)*((%72)|r)(s)*((%69)|i)(s)*((%70)|p)(s)*((%74)|t)(s|S)*";
// SQL 注入綜合特徵(含編碼繞過)
$SQL_Injection = "(s|S)*((%27)|(')|(%3D)|(=)|(/)|(%2F)|(")|((%22)|(-|%2D){2})|(%23)|(%3B)|(;))+(s|S)*";
?>
<?php
// 自訂錯誤處理
function customError($errno, $errstr, $errfile, $errline) {
echo "<b>Error number:</b> [$errno], error on line $errline in $errfile<br />";
die();
}
set_error_handler("customError", E_ERROR);
// GET/POST/COOKIE 過濾規則
$getfilter = "'|(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)";
$postfilter = "\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)";
$cookiefilter = "\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)";
// 統一攔截函式
function StopAttack($StrFiltKey, $StrFiltValue, $ArrFiltReq) {
if (is_array($StrFiltValue)) {
$StrFiltValue = implode($StrFiltValue);
}
// 白名單機制:攜帶 securityToken 的請求略過檢查
if (preg_match("/" . $ArrFiltReq . "/is", $StrFiltValue) == 1 && !isset($_REQUEST['securityToken'])) {
// 記錄攻擊日誌
slog("<br><br>攻擊 IP: " . $_SERVER["REMOTE_ADDR"] . "<br>攻擊參數: " . $StrFiltKey . "<br>攻擊內容: " . $StrFiltValue);
exit("非法請求已攔截");
}
}
// 對所有超全域變數套用過濾
foreach ($_GET as $key => $value) StopAttack($key, $value, $getfilter);
foreach ($_POST as $key => $value) StopAttack($key, $value, $postfilter);
foreach ($_COOKIE as $key => $value) StopAttack($key, $value, $cookiefilter);
?>
正則過濾只能作為輔助防線,核心防禦必須使用預處理語句:
<?php
$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 username = :username AND status = :status");
$stmt->execute([
':username' => $_GET['username'],
':status' => 1
]);
$user = $stmt->fetch();
?>
<?php
$mysqli = new mysqli("localhost", $user, $pass, "test");
$stmt = $mysqli->prepare("SELECT * FROM users WHERE username = ?");
$stmt->bind_param("s", $_GET['username']);
$stmt->execute();
$result = $stmt->get_result();
?>
| 層級 | 措施 | 工具/技術 |
|---|---|---|
| 網路層 | WAF 規則攔截 | ModSecurity、Cloudflare WAF、OpenResty + Lua |
| 應用層 | 參數化查詢(核心) | PDO / MySQLi Prepared Statements |
| 應用層 | 輸入驗證與白名單 | filter_var、Respect\Validation、嚴格型別提示 |
| 應用層 | ORM/Query Builder | Eloquent、Doctrine、Medoo(內建參數化) |
| 資料庫層 | 最小權限原則 | 僅授予 SELECT/INSERT/UPDATE,禁止 DROP/ALTER |
| 資料庫層 | 錯誤訊息隱藏 | 關閉 display_errors,自訂錯誤頁面 |
| 監控層 | 攻擊日誌與告警 | ELK Stack、Sentry、自建審計表 |
addslashes() / mysql_real_escape_string():編碼問題導致繞過,已棄用理解基於正則的 SQL 盲注原理有助於建立威脅模型,但實務防禦的核心永遠是參數化查詢。正則過濾、WAF、輸入驗證屬於纵深防禦的輔助層。建立「不信任任何輸入」的開發文化,配合代碼審查與自動化掃描,才能有效降低 SQL 注入風險。