在現代網頁安全防護中,X-Frame-Options 是一個重要但常被忽視的 HTTP 響應標頭。它能有效防止網站被嵌入惡意框架中,保護用戶免受 點擊劫持(Clickjacking) 攻擊。本文將深入探討 X-Frame-Options 的作用、設定方式,以及與現代替代方案的比較。
目錄
- 什麼是 X-Frame-Options?
- X-Frame-Options 的主要作用
- 三種設定模式詳解
- 如何設置 X-Frame-Options
- 點擊劫持攻擊實例
- X-Frame-Options vs CSP frame-ancestors
- 最佳實踐建議
- 常見問題與除錯
什麼是 X-Frame-Options?
X-Frame-Options 是一個 HTTP 響應標頭(HTTP Response Header),用於控制網頁是否能被 <frame>、<iframe>、<embed> 或 <object> 等標籤嵌入。
基本資訊
| 項目 | 說明 |
|---|---|
| 類型 | HTTP 響應標頭 |
| 標準 | RFC 7034(2013 年發布) |
| 目的 | 防止點擊劫持攻擊 |
| 支援瀏覽器 | 所有現代瀏覽器(IE8+、Chrome、Firefox、Safari) |
| 狀態 | 已被 CSP Level 2 取代,但仍廣泛使用 |
歷史背景
X-Frame-Options 最早由 Microsoft 在 2009 年提出,作為對點擊劫持攻擊的防禦機制。2013 年,IETF 將其標準化為 RFC 7034。雖然現在已有更強大的 Content Security Policy (CSP) 取代,但由於其簡單易用,至今仍被廣泛採用。
X-Frame-Options 的主要作用
🛡️ 防止點擊劫持(Clickjacking)
點擊劫持 是一種攻擊手法,攻擊者將目標網站嵌入惡意頁面的透明框架中,誘使用戶在不知情的情況下點擊按鈕或連結。
攻擊場景:
- 攻擊者建立惡意網站,嵌入銀行的轉帳頁面
- 使用 CSS 將轉帳按鈕覆蓋在「免費抽獎」按鈕下方
- 用戶以為點擊抽獎,實際上是確認轉帳
X-Frame-Options 的防護:
- 阻止網站被嵌入框架
- 瀏覽器會拒絕載入被禁止的框架內容
- 用戶無法在惡意網站中看到目標網站
🛡️ 保護品牌與用戶信任
當你的網站被嵌入惡意框架時:
- 用戶可能誤以為是釣魚網站
- 品牌形象受損
- 可能導致法律糾紛
設置 X-Frame-Options 可確保:
- 網站只能在授權的上下文中顯示
- 用戶看到的始终是真實網站
- 降低被濫用的風險
三種設定模式詳解
X-Frame-Options 支援三種設定模式,每種有不同的安全級別:
1️⃣ DENY(最嚴格)
X-Frame-Options: DENY
效果: 完全禁止任何網站(包括自己)嵌入此頁面
適用場景:
- 高度敏感的頁面(登入、轉帳、個資)
- 不需要嵌入功能的網站
- 安全性優先的應用
優點:
- 最高安全級別
- 設定簡單
- 無需維護白名單
缺點:
- 無法嵌入自己的頁面(如內部系統儀表板)
- 靈活性較低
2️⃣ SAMEORIGIN(推薦)
X-Frame-Options: SAMEORIGIN
效果: 只允許同源網站嵌入此頁面
同源定義: 協議、網域、埠號完全相同
| 比較項目 | 當前頁面 | 是否允許嵌入 |
|---|---|---|
| 同源 | https://example.com |
✅ 允許 |
| 不同協議 | http://example.com |
❌ 禁止 |
| 不同子網域 | https://sub.example.com |
❌ 禁止 |
| 不同網域 | https://other.com |
❌ 禁止 |
| 不同埠號 | https://example.com:8080 |
❌ 禁止 |
適用場景:
- 需要內部框架嵌入的網站
- 多頁面應用(MPA)
- 後台管理系統
優點:
- 平衡安全性與靈活性
- 允許內部嵌入
- 阻止外部惡意嵌入
缺點:
- 子網域無法互相嵌入
- 需要其他方案支援跨網域嵌入
3️⃣ ALLOW-FROM(已棄用)
X-Frame-Options: ALLOW-FROM https://trusted.com
效果: 只允許指定網域嵌入
⚠️ 重要: 此模式已被現代瀏覽器棄用
瀏覽器支援情況:
| 瀏覽器 | 支援狀態 |
|---|---|
| Chrome | ❌ 不支援(Chrome 4+) |
| Firefox | ⚠️ 部分支援(已棄用) |
| Safari | ❌ 不支援 |
| Edge | ❌ 不支援 |
| IE | ✅ 支援(IE11) |
建議: 不要使用 ALLOW-FROM,改用 CSP frame-ancestors
如何設置 X-Frame-Options
方法一:Apache 伺服器
# 在 .htaccess 或 httpd.conf 中添加
Header always set X-Frame-Options "DENY"
# 或只對特定目錄設置
<Directory "/var/www/html/admin">
Header always set X-Frame-Options "SAMEORIGIN"
</Directory>
重啟 Apache:
sudo systemctl restart apache2
方法二:Nginx 伺服器
# 在 server 或 location 區塊中添加
add_header X-Frame-Options "SAMEORIGIN" always;
# 或全局設置
http {
add_header X-Frame-Options "DENY" always;
}
重啟 Nginx:
sudo nginx -t && sudo systemctl restart nginx
方法三:Node.js (Express)
const express = require('express');
const app = express();
// 全局設置
app.use((req, res, next) => {
res.setHeader('X-Frame-Options', 'SAMEORIGIN');
next();
});
// 或對特定路由設置
app.get('/admin/*', (req, res, next) => {
res.setHeader('X-Frame-Options', 'DENY');
next();
});
方法四:Node.js (Nuxt 3)
// nuxt.config.ts
export default defineNuxtConfig({
routeRules: {
// 全局設置
'/**': {
headers: {
'X-Frame-Options': 'SAMEORIGIN'
}
},
// 管理後台更嚴格
'/admin/**': {
headers: {
'X-Frame-Options': 'DENY'
}
}
}
})
方法五:PHP
<?php
// 在頁面最頂部添加
header('X-Frame-Options: SAMEORIGIN');
// 或對特定頁面
if ($page === 'checkout') {
header('X-Frame-Options: DENY');
}
?>
方法六:ASP.NET
<!-- Web.config -->
<configuration>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="X-Frame-Options" value="SAMEORIGIN" />
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>
方法七:Cloudflare(邊緣設置)
// Cloudflare Workers
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request));
});
async function handleRequest(request) {
const response = await fetch(request);
const newResponse = new Response(response.body, response);
newResponse.headers.set('X-Frame-Options', 'SAMEORIGIN');
return newResponse;
}
點擊劫持攻擊實例
攻擊程式碼範例
<!-- 攻擊者的惡意網站 -->
<!DOCTYPE html>
<html>
<head>
<style>
.iframe-container {
position: relative;
width: 800px;
height: 600px;
}
.target-frame {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0.3; /* 半透明,用戶看不到 */
z-index: 1;
}
.fake-button {
position: absolute;
top: 300px;
left: 350px;
width: 100px;
height: 50px;
background: red;
color: white;
z-index: 2;
text-align: center;
line-height: 50px;
cursor: pointer;
}
</style>
</head>
<body>
<div class="iframe-container">
<!-- 嵌入受害網站的轉帳頁面 -->
<iframe
src="https://victim-bank.com/transfer"
class="target-frame"
></iframe>
<!-- 覆蓋的假按鈕 -->
<div class="fake-button">
🎉 點擊抽獎
</div>
</div>
</body>
</html>
攻擊流程
- 建立惡意網站:攻擊者建立看似無害的網站(抽獎、遊戲)
- 嵌入目標網站:使用
<iframe>嵌入銀行的轉帳頁面 - 視覺偽裝:使用 CSS 將轉帳按鈕與假按鈕對齊
- 誘導點擊:用戶點擊「抽獎」,實際執行轉帳操作
防護效果
未設置 X-Frame-Options:
✅ 惡意網站成功嵌入銀行頁面
❌ 用戶在不知情下完成轉帳
已設置 X-Frame-Options: DENY:
❌ 瀏覽器拒絕載入框架
✅ 顯示錯誤訊息:「此網站拒絕被嵌入」
✅ 用戶無法被攻擊
X-Frame-Options vs CSP frame-ancestors
雖然 X-Frame-Options 仍被廣泛使用,但 Content Security Policy (CSP) 的 frame-ancestors 指令是更現代的替代方案。
功能比較
| 特性 | X-Frame-Options | CSP frame-ancestors |
|---|---|---|
| 標準 | RFC 7034 | CSP Level 2 (W3C) |
| 發布年份 | 2013 | 2016 |
| 設定模式 | 3 種(DENY, SAMEORIGIN, ALLOW-FROM) | 多個網域白名單 |
| ALLOW-FROM 支援 | ❌ 已棄用 | ✅ 完整支援 |
| 多網域白名單 | ❌ 不支援 | ✅ 支援 |
| 子網域控制 | ❌ 不精細 | ✅ 可指定 *.example.com |
| 瀏覽器支援 | ✅ 所有瀏覽器 | ✅ 現代瀏覽器(IE 不支援) |
| 優先級 | 低 | 高(CSP 優先) |
語法比較
X-Frame-Options:
X-Frame-Options: DENY
X-Frame-Options: SAMEORIGIN
X-Frame-Options: ALLOW-FROM https://example.com # 已棄用
CSP frame-ancestors:
Content-Security-Policy: frame-ancestors 'none'
Content-Security-Policy: frame-ancestors 'self'
Content-Security-Policy: frame-ancestors 'self' https://trusted.com https://*.example.com
同時使用兩者
最佳實踐:同時設置兩者
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self' https://trusted.com
原因:
- 向後相容:舊瀏覽器只支援 X-Frame-Options
- 現代功能:新瀏覽器優先使用 CSP
- 雙重防護:增加安全性
瀏覽器行為:
- 現代瀏覽器(Chrome、Firefox、Edge):優先使用 CSP,忽略 X-Frame-Options
- 舊瀏覽器(IE11):使用 X-Frame-Options
- 同時設置不會衝突
最佳實踐建議
🎯 推薦設定策略
| 頁面類型 | 建議設定 | 理由 |
|---|---|---|
| 公開頁面 | SAMEORIGIN |
允許內部嵌入,阻止外部 |
| 登入/註冊頁 | DENY |
高度敏感,完全禁止嵌入 |
| 後台管理 | DENY |
防止惡意嵌入 |
| 金流/支付頁 | DENY |
最高安全級別 |
| API 端點 | DENY |
不應被嵌入 |
| 文件/說明頁 | SAMEORIGIN |
可被內部系統嵌入 |
📋 完整設定範例(Nuxt 3)
// nuxt.config.ts
export default defineNuxtConfig({
routeRules: {
// 全局預設
'/**': {
headers: {
'X-Frame-Options': 'SAMEORIGIN',
'Content-Security-Policy': "frame-ancestors 'self'"
}
},
// 管理後台(更嚴格)
'/admin/**': {
headers: {
'X-Frame-Options': 'DENY',
'Content-Security-Policy': "frame-ancestors 'none'"
}
},
// 登入頁面(最嚴格)
'/login': {
headers: {
'X-Frame-Options': 'DENY',
'Content-Security-Policy': "frame-ancestors 'none'"
}
},
// 支付頁面(最嚴格)
'/checkout/**': {
headers: {
'X-Frame-Options': 'DENY',
'Content-Security-Policy': "frame-ancestors 'none'"
}
}
}
})
✅ 檢查清單
- [ ] 所有敏感頁面設置
DENY - [ ] 一般頁面設置
SAMEORIGIN - [ ] 同時設定 CSP
frame-ancestors - [ ] 測試框架嵌入是否被正確阻止
- [ ] 檢查瀏覽器開發者工具確認標頭存在
- [ ] 定期審查白名單網域(如有)
常見問題與除錯
Q1:設置後框架仍能被嵌入?
可能原因:
- 標頭未正確設置
- 被其他標頭覆蓋
- 使用了 ALLOW-FROM(已棄用)
除錯步驟:
# 使用 curl 檢查響應標頭
curl -I https://example.com
# 應該看到:
# X-Frame-Options: SAMEORIGIN
檢查瀏覽器開發者工具:
- 開啟 DevTools(F12)
- 切換到 Network 標籤
- 重新整理頁面
- 點擊請求,查看 Response Headers
Q2:自己的網站也無法嵌入?
原因: 設置了 DENY 模式
解決方案:
- 如需內部嵌入,改為
SAMEORIGIN - 或使用 CSP
frame-ancestors 'self'
Q3:子網域無法互相嵌入?
原因: SAMEORIGIN 要求完全同源
解決方案: 使用 CSP
Content-Security-Policy: frame-ancestors 'self' https://*.example.com
Q4:如何測試防護是否生效?
測試工具:
<!-- 建立測試頁面 -->
<!DOCTYPE html>
<html>
<head><title>Frame Test</title></head>
<body>
<h1>Frame Embedding Test</h1>
<iframe src="https://your-site.com" width="800" height="600"></iframe>
</body>
</html>
預期結果:
- ✅ 設置
DENY:框架顯示空白或錯誤 - ✅ 設置
SAMEORIGIN:只有同源頁面能嵌入 - ❌ 未設置:框架正常載入
Q5:X-Frame-Options 與 CSP 衝突時怎麼辦?
瀏覽器行為:
- 現代瀏覽器:CSP 優先
- 舊瀏覽器:X-Frame-Options 生效
建議: 保持一致
# 正確:兩者一致
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self'
# 避免:兩者衝突
X-Frame-Options: DENY
Content-Security-Policy: frame-ancestors 'self' https://other.com
結論
X-Frame-Options 是防護點擊劫持攻擊的基礎安全標頭,雖然已被 CSP 取代,但由於其簡單易用且相容性佳,仍是現代網站的標準設定。
關鍵要點
- 所有網站都應設置:無論規模大小
- 優先使用 SAMEORIGIN:平衡安全與靈活性
- 敏感頁面使用 DENY:登入、支付、個資頁面
- 同時設定 CSP:獲得更強防護
- 定期檢查:確保標頭正確發送
快速開始
# 最簡單的設定(推薦起點)
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self'
設置 X-Frame-Options 只需幾分鐘,但能有效保護你的網站和用戶免受點擊劫持攻擊。現在就檢查你的網站是否已正確設定!
參考資源
- RFC 7034 - X-Frame-Options
- MDN - X-Frame-Options
- MDN - CSP frame-ancestors
- OWASP - Clickjacking
- Can I Use - CSP
作者: LinkPortal 編輯團隊
分類: 資訊安全
發布日期: 2026-04-30
閱讀時間: 約 12 分鐘