延續前兩篇關於注入類型與多查詢攻擊的分析,本文聚焦工程落地:如何通過抽象層封裝防護邏輯,以最小成本改造現有應用,構建可復用、可審計的安全防線。
在每個用戶輸入點手動調用轉義函數,不僅繁瑣易漏,更難保證團隊長期執行力。抽象層帶來三大核心收益:
針對存量專案,最平滑的改造是引入 safe() 函數,封裝「加引號 + 實體轉義」:
function safe($string) {
return "'" . mysql_real_escape_string($string) . "'";
}
// 使用範例
$variety = safe($_POST['variety']);
$query = "SELECT * FROM wines WHERE variety=" . $variety;
惡意輸入:lagrein' or 1=1;
WHERE variety = 'lagrein' or 1=1;' → 返回全表數據。WHERE variety = 'lagrein\' or 1=1\;' → 單引號被轉義為字面量,查詢無結果,注入失敗。對於新架構或重構專案,建議封裝 Database 類,內建參數化查詢支援:
class Database {
private $pdo;
public function __construct($dsn, $user, $pass) {
$this->pdo = new PDO($dsn, $user, $pass, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false, // 關鍵:使用真實預處理
]);
}
public function query($sql, array $params = []) {
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
}
// 業務代碼極簡安全
$users = $db->query("SELECT * FROM users WHERE email = ? AND status = ?", [$email, 1]);
grep -r "mysql_query\|mysqli_query" --include="*.php" 定位所有原始查詢點。safe() 包裹變量。common.php)引入抽象層,禁用裸 mysql_* 函數。safe() 邊界情況(NULL、陣列、編碼字符)。safe()(雙重轉義)。LIKE 子句中直接使用 safe(),需額外轉義 %、_、\。SET NAMES utf8mb4),防止多字節編碼繞過轉義(如 GBK 雙字節攻擊)。