← 返回文章列表

什麼是 X-Frame-Options 作用為何?完整防護指南

在現代網頁安全防護中,X-Frame-Options 是一個重要但常被忽視的 HTTP 響應標頭。它能有效防止網站被嵌入惡意框架中,保護用戶免受 點擊劫持(Clickjacking) 攻擊。本文將深入探討 X-Frame-Options 的作用、設定方式,以及與現代替代方案的比較。


目錄


什麼是 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)

點擊劫持 是一種攻擊手法,攻擊者將目標網站嵌入惡意頁面的透明框架中,誘使用戶在不知情的情況下點擊按鈕或連結。

攻擊場景:

  1. 攻擊者建立惡意網站,嵌入銀行的轉帳頁面
  2. 使用 CSS 將轉帳按鈕覆蓋在「免費抽獎」按鈕下方
  3. 用戶以為點擊抽獎,實際上是確認轉帳

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>

攻擊流程

  1. 建立惡意網站:攻擊者建立看似無害的網站(抽獎、遊戲)
  2. 嵌入目標網站:使用 <iframe> 嵌入銀行的轉帳頁面
  3. 視覺偽裝:使用 CSS 將轉帳按鈕與假按鈕對齊
  4. 誘導點擊:用戶點擊「抽獎」,實際執行轉帳操作

防護效果

未設置 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

原因:

  1. 向後相容:舊瀏覽器只支援 X-Frame-Options
  2. 現代功能:新瀏覽器優先使用 CSP
  3. 雙重防護:增加安全性

瀏覽器行為:

  • 現代瀏覽器(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:設置後框架仍能被嵌入?

可能原因:

  1. 標頭未正確設置
  2. 被其他標頭覆蓋
  3. 使用了 ALLOW-FROM(已棄用)

除錯步驟:

# 使用 curl 檢查響應標頭
curl -I https://example.com

# 應該看到:
# X-Frame-Options: SAMEORIGIN

檢查瀏覽器開發者工具:

  1. 開啟 DevTools(F12)
  2. 切換到 Network 標籤
  3. 重新整理頁面
  4. 點擊請求,查看 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 取代,但由於其簡單易用且相容性佳,仍是現代網站的標準設定。

關鍵要點

  1. 所有網站都應設置:無論規模大小
  2. 優先使用 SAMEORIGIN:平衡安全與靈活性
  3. 敏感頁面使用 DENY:登入、支付、個資頁面
  4. 同時設定 CSP:獲得更強防護
  5. 定期檢查:確保標頭正確發送

快速開始

# 最簡單的設定(推薦起點)
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self'

設置 X-Frame-Options 只需幾分鐘,但能有效保護你的網站和用戶免受點擊劫持攻擊。現在就檢查你的網站是否已正確設定!


參考資源


作者: LinkPortal 編輯團隊
分類: 資訊安全
發布日期: 2026-04-30
閱讀時間: 約 12 分鐘