SQL 注入與跨站腳本攻擊 (XSS) 是 Web 應用最常見的兩大安全漏洞。本文透過實際程式碼示範攻擊原理,並提供針對性修復方案與最佳實踐。
<?php
// 直接拼接使用者輸入,極度危險
$conn = mysql_connect("localhost", "root", "123456");
mysql_select_db("test1");
$user = $_POST['uid'];
$pwd = $_POST['pass'];
// 惡意輸入:uid = "admin' --" 即可繞過密碼驗證
$sql = "SELECT * FROM admin WHERE username = '$user' AND password = '$pwd'";
$result = mysql_query($sql);
if (mysql_num_rows($result) > 0) {
echo "登入成功";
} else {
echo "帳號或密碼錯誤";
}
?>
uid: admin' -- → SQL 變為 WHERE username = 'admin' --' AND password = '...',註解掉密碼檢查。uid: ' OR '1'='1 → 條件永真,返回第一筆資料 (通常是管理員)。uid: ' UNION SELECT null, username, password FROM admin -- → 聯合查詢竊取所有帳密。唯一根治之道,將 SQL 邏輯與資料分離:
<?php
// 使用 PDO (推薦)
$pdo = new PDO("mysql:host=localhost;dbname=test1;charset=utf8", "root", "123456");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->prepare("SELECT * FROM admin WHERE username = ? AND password = ?");
$stmt->execute([$_POST['uid'], $_POST['pass']]); // 參數綁定,自動處理跳脫
$user = $stmt->fetch();
if ($user) {
echo "登入成功";
} else {
echo "帳號或密碼錯誤";
}
?>
mysqli 寫法:
$stmt = $mysqli->prepare("SELECT * FROM admin WHERE username = ? AND password = ?");
$stmt->bind_param("ss", $_POST['uid'], $_POST['pass']);
$stmt->execute();
mysql_real_escape_string():舊版 mysql_* 專用,易漏掉、編碼問題多,**不推薦**。| 類型 | 特徵 | 範例 |
|---|---|---|
| 反射型 | 惡意腳本經 URL 參數反射回響應頁面 | search?q= |
| 儲存型 | 惡意腳本儲存於資料庫,所有瀏覽者受害 | 留言板、評論區植入 |
| DOM 型 | 純前端 JS 處理 URL 片段導致 | document.write(location.hash) |
<?php
// 直接輸出未過濾的使用者輸入
echo $_POST['comment'];
?>
<!-- 攻擊者提交: -->
根據輸出位置選擇正確編碼函數:
| 輸出語境 | PHP 函數 | 範例 |
|---|---|---|
| HTML 內文/屬性 | htmlspecialchars($str, ENT_QUOTES, 'UTF-8') | <div>= h($comment) ?></div> |
| JavaScript 字串 | json_encode($str) (含引號) | var msg = = json_encode($comment) ?>; |
| URL 參數 | urlencode($str) | <a href="?q== urlencode($kw) ?>"> |
| CSS 值 | 無內建函數,需嚴格白名單 | 僅允許顏色代碼、數字等 |
若需允許使用者輸入有限 HTML (如富文本編輯器),**必須使用白名單過濾器**:
require_once 'HTMLPurifier.auto.php';
$config = HTMLPurifier_Config::createDefault();
$config->set('HTML.Allowed', 'p,b,i,u,em,strong,a[href|title],ul,ol,li,br,img[src|alt]');
$purifier = new HTMLPurifier($config);
$clean_html = $purifier->purify($dirty_html);
Content-Security-Policy 限制腳本來源;X-Content-Type-Options: nosniff;HttpOnly Cookie 防竊取。安全是系統工程,**參數化查詢解決 SQL 注入,語境感知輸出編碼解決 XSS**。沒有銀彈,唯有分層防禦、持續更新、程式碼審查才能降低風險。