雖然現代框架已內建防護,但理解核心原理仍不可或缺。本文涵蓋 htmlspecialchars、mysqli_real_escape_string/PDO 參數化、關鍵字黑名單過濾的優缺點與最佳實踐。
<?php
// 所有輸出到 HTML 內容、屬性、JS、CSS、URL 都需對應編碼
echo htmlspecialchars($userInput, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
// ENT_QUOTES 轉換單雙引號,ENT_SUBSTITUTE 替換無效碼點
// 屬性值
echo '';
// JavaScript 內容
echo ''; // json_encode 含編碼
?>
<?php
// PDO 參數化 (推薦)
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = ? AND status = ?');
$stmt->execute([$email, 1]);
// mysqli 參數化
$stmt = $mysqli->prepare('SELECT * FROM users WHERE email = ?');
$stmt->bind_param('s', $email);
$stmt->execute();
// ❌ 永遠不要手動拼接
// $sql = "SELECT * FROM users WHERE email = '$email'"; // 高風險
?>
注意:過濾/清洗輸入無法替代輸出編碼與參數化,僅作為深層防禦。
<?php
// 移除控制字元、正規化空白
function clean_input(string $str): string {
$str = trim($str);
$str = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/', '', $str); // 非列印字元
$str = preg_replace('/\s+/u', ' ', $str); // 多重空白合併
return $str;
}
// 關鍵字黑名單 (示範用,實務效果有限)
$blacklist = ['select','union','insert','update','delete','drop','alter','script','onload','onerror'];
function contains_blacklist(string $str, array $list): bool {
$str = strtolower($str);
foreach ($list as $word) {
if (str_contains($str, $word)) return true;
}
return false;
}
?>
/**/、字串拼接皆可繞過簡單 str_replace。htmlspecialchars 包裝函式。Content-Security-Policy: default-src 'self'; script-src 'self' 徹底封殺內聯腳本。filter_var、Respect\Validation 等白名單驗證格式 (Email, URL, 數字範圍)。