問題

原有 a.com/hello 當中嵌入 a.com/world iframe 本身沒問題,後來因為公司政策改變需要調整為 hello.a.comworld.a.com 而原有的 a.com/hello 以及 a.com/world 拜訪後會 redirect 到 hello.a.comworld.a.com 當中,而在這中間發現 iframe 失效並嘗試進行解決。

依照同源政策規則,調整為 hello.a.com 與 world.a.com 視為不同源,因此需要額外配置。

同源定義

所謂同源是指兩份網頁具備相同協定、埠號 (如果有指定) 以及主機位置,下表提供了一些例子展示那些來源和 http://store.company.com/dir/page.html 屬於同源:

URL Outcome Reason
http://store.company.com/dir2/other.html 同源
http://store.company.com/dir/inner/another.html 同源
https://store.company.com/secure.html 不同源 協定不同
http://store.company.com:81/dir/etc.html 不同源 埠號不同
http://news.company.com/dir/other.html 不同源 ✅ 主機位置不同 ✅

MDN 說明

出錯點

Refused to display 'https://world.a.com/' in a frame because it set 'X-Frame-Options' to 'sameorigin'.

問題思路與解法

X-Frame-Options

MDN 說明

X-Frame-Options 提供三種參數,並且功能如下

DENY 表示網頁無論如何都無法被嵌入到 frame 中,即使於相同網域內嵌入也不允許。

SAMEORIGIN

唯有當符合同源政策下,才能被嵌入到 frame 中。

ALLOW-FROM uri 已棄用

唯有列表許可的 URI 才能嵌入到 frame 中。新版瀏覽器已不再支援此指令。

其中 SAMEORIGIN 為預設參數

原本是採用 ALLOW-FROM  但已經被棄用,官方則推薦使用 content-security-policy 當中得 frame-ancestors 作為替代:

The Content-Security-Policy HTTP header has a frame-ancestors directive which you can use instead.

初探 Content-Security-Policy (CSP)

MDN 說明 MDN 延伸說明 iframe:frame-ancestors frame-ancestors

指定可能嵌入页面的有效父项 <frame><iframe><object> 或 <embed>

這邊應該跟 browser 告知加入幾個 allow 項目:

self
*.a.com //支持 wildcard 配置
*.google-analytics.com // GA
*.googletagmanager.com // GTM

Nuxt 2 配置

在要被嵌套的服務(這邊是 a.com/world)下 nuxt.config.js  當中配置相關 csp:

export default {
render: {
    csp: {
      policies: {
        'script-src': [
          "'self'",
          "'unsafe-inline'",
          '*.a.com',
          '*.google-analytics.com',
          '*.googletagmanager.com',
        ],
        'frame-ancestors': [
          "'self'",
          '*.a.com',
          '*.google-analytics.com',
          '*.googletagmanager.com',
        ],
      }
    }
  },
}

Nuxt3

需要額外配置組件 Nuxt Security