Web 輸入向量:GET、POST、COOKIE、HTTP 標頭。注入載荷必含 SQL 關鍵字:SELECT、UPDATE、DELETE、INSERT、UNION、LOAD_FILE、INTO OUTFILE 等。
function inject_check($sql_str) {
// 使用 preg_match 替代已棄用的 eregi
return preg_match(
'/select|insert|update|delete|\'|\/\*.*?\*\/|\.\.\/|\.\/|union|into|load_file|outfile/i',
$sql_str
);
}
注意: 僅作輔助攔截,不可作為唯一防禦,繞過手法極多(編碼、註釋、大小寫變形)。
function verify_id($id = null) {
if (!$id) exit('缺少參數!');
if (inject_check($id)) exit('參數非法!');
if (!is_numeric($id)) exit('參數非法!');
return intval($id);
}
function str_check($str) {
if (!get_magic_quotes_gpc()) {
$str = addslashes($str); // 相容舊版
}
// LIKE 查詢特殊字元跳脫
$str = str_replace('_', '\_', $str);
$str = str_replace('%', '\%', $str);
return $str;
}
function post_check($post) {
if (!get_magic_quotes_gpc()) {
$post = addslashes($post);
}
$post = str_replace('_', '\_', $post);
$post = str_replace('%', '\%', $post);
$post = nl2br($post); // 換行轉 <br>
$post = htmlspecialchars($post); // HTML 實體編碼
return $post;
}
唯一徹底解決 SQL 注入的方案。
<?php
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'user', 'pass', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false, // 使用真實預處理
]);
$stmt = $pdo->prepare('SELECT * FROM users WHERE username = ? AND status = ?');
$stmt->execute([$username, $status]);
$user = $stmt->fetch();
?>
<?php
$mysqli = new mysqli('localhost', 'user', 'pass', 'test');
$stmt = $mysqli->prepare('SELECT * FROM users WHERE username = ? AND status = ?');
$stmt->bind_param('ss', $username, $status);
$stmt->execute();
$result = $stmt->get_result();
$user = $result->fetch_assoc();
?>
| 層級 | 技術 | 防禦範圍 | 維護成本 |
|---|---|---|---|
| 1. WAF/網關 | 規則引擎、語意分析 | 已知攻擊特徵、自動化掃描 | 低(運維層) |
| 2. 框架/中介層 | 全域輸入過濾、CSRF Token | 通用注入、跨站請求偽造 | 中(框架升級) |
| 3. 業務邏輯層 | 參數化查詢、型別驗證、權限檢查 | 業務特定注入、橫向越權 | 高(開發責任) |
| 4. 資料庫層 | 最小權限帳號、審計日誌、資料加密 | 資料外洩、內部威脅 | 中(DBA 責任) |
0xbf27 → 0xbf5c27)mysql_* 舊擴充套件PDO::ATTR_EMULATE_PREPARES 使用真實預處理composer audit、資料庫權限審計