GSS 技術部落格
在這個園地裡我們將從技術、專案管理、客戶對談面和大家分享我們多年的經驗,希望大家不管是喜歡或是有意見,都可以回饋給我們,讓我們有機會和大家對話並一起成長!
若有任何問題請來信:gss_crm@gss.com.tw
字體大小: +
8 分鐘閱讀時間 (1665 個字)

The frame attempting navigation is sandboxed, and is therefore disallowed from navigating its ancestors.

joshua-sortino-LqKhnDzSF-8-unsplash

前言

最近遇到一個 iframe 的問題,在一個頁面(index.htm)中加入 iframe 後,該 iframe 的 Page (parentFrame.htm)中又有 iframe (childFrameA.htm)。
而在 childFrameA.htm 中有一個 Link 要將 Parent 頁面取代掉,會出現以下的錯誤,

Unsafe JavaScript attempt to initiate navigation for frame with URL ‘http://10.211.55.3/iframesandbox/parentFrame.htm' from frame with URL ‘http://10.211.55.3/iframesandbox/childFrameA.htm'. The frame attempting navigation is sandboxed, and is therefore disallowed from navigating its ancestors.


它的意思是說 childFrameA.htm 想要瀏覽到那個 parentFrame.htm 的 Frame 去,但因為這些 Frame 有設定 Sandbox ,所以不允許瀏覽到祖先,也就是不允許讓你將Link 的網頁,取代掉 Parent(parentFrame.htm) 的 Frame。 那怎麼辦呢?

研究與解法

即然是 sandbox ,那就先來了解一下,iframe 的 sandbox 到底是怎麼一回事 …

IFRAME SANDBOX

iframe sandbox 屬性會啟用針對 iframe 內容額外的限制,限制如下,

  • treat the content as being from a unique origin
  • block form submission
  • block script execution
  • disable APIs
  • prevent links from targeting other browsing contexts
  • prevent content from using plugins (through , 
  • prevent the content to navigate its top-level browsing context
  • block automatically triggered features (such as automatically playing a video or automatically focusing a form control)

所以當 iframe 加入 sanbox 屬性後,就會去針對內容進行一些限制,例如,

  • 不允許 javascript 執行,javascript src=”…” 也不允許
  • 不允許存取 cookies 及任何的 storage
  • 不允許建立新視窗,例如 window.open 或是按下 link target=”_blank”
  • 不允許 Form 的 Submit
  • 不允許載入 Plugins
  • 不允許瀏覽到 top window ,例如 window.top.location 或是按下 link target=”_top”
  • 不允許自動觸發功能,例如 autofocused form elements, autoplaying videos …
  • iframe 上的 seamless 屬性會被忽略
  • iframe 中無法獲得 mouse 移動的軌跡

所以使用了 sandbox 後,會再依網頁需要的權限來設定允許的行為

案例

為了解說方便,我們使用 5 個 html 檔來測試, 首頁(index.htm) 放一個 iframe src 為 parentFrame.htm , parentFrame.htm 放一個 iframe src 為 childFrameA.htm ,childframeA.htm 放一個 iframe src 為 childFrameAchildFrameA-ChildFrame.htm 中放了 5 個 link ,分別設定 target 為 _self, _parent, _top, _blank 及透過 javascript

index.htm

<html>
    <head>
        <title>Sandboxed Iframes</title>
        <style>
            #parentFrame {
              width:500px;
              height: 473px;
              margin: auto;
              border: 3px solid #73AD21;
            }
        </style>
    </head>
    <body>
        <iframe id="parentFrame" src="/parentFrame.htm" sandbox></iframe>
    </body>
</html>

parentFrame.htm

<html>
    <head>
        <style>
            #childFrameA {
              width:450px;
              height: 400px;
              margin: auto;
              border: 2px solid #772277;
            }
        </style>
        <script>console.log(window.location.href);</script>
    </head>
    <body>
        <h2>This is Parent Frame </h2>
        <div>
            <iframe id="childFrameA" src="/childFrameA.htm" frameborder="1" ></iframe>
        </div>
    </body>
</html>

childFrameA.htm

<html>
    <head>
        <title>Sandboxed Iframes</title>
        <style>
            #childFrameA-ChildFrame {
              width:400px;
              height: 305px;
              margin: auto;
              border: 2px solid #224477;
            }
        </style>
        <script>console.log(window.location.href);</script>
    </head>
    <body>
        <h2>This is childFrameA's Page </h2>
        <div>
            <iframe id="childFrameA-ChildFrame" src="/childFrameA-ChildFrame.htm" frameborder="1"></iframe>
        </div>
    </body>
</html>

childFrameA-ChildFrame.htm

<html>
    <head>
        <script>console.log(window.location.href);</script>
    </head>
    <body>
        <h2>This is Child Frame  A's iframe page ... </h2>
        <a href="/drilldown.htm" target="_self">link ...Self</a>
        <br>
        <a href="/drilldown.htm" target="_parent">link ...Parent</a>
        <br>
        <a href="/drilldown.htm" target="_top">link ...Top</a>
        <br>
        <a href="/drilldown.htm" target="_blank">link ...Blank popup</a>
        <br>
        <a href="javascript:window.location.assign('drilldown.htm')">link ...javascript</a>
    </body>
</html>

drilldown.htm

<html>
    <body>
        <h2>This is Drill Down Page... </h2>
        <a href="/childFrameA-ChildFrame.htm" target="_self">backto ChildFrameA-ChildFrame ...self</a>
    </body>
</html>

因為在 index.htm 的 iframe 中有加入 sandbox ,可以發現在 console 中,顯示那3個 iframe 的內容中的 javascript 執行都會被 block 住,同時也提醒我們可以加入 allow-scripts 去允許javascript 的執行,如下,

Blocked script execution in ‘‘ because the document’s frame is sandboxed and the ‘allow-scripts’ permission is not set.

SANDBOX 屬性的限制關係

target=”_self”

  • 當我們按下第 1 個 link (1.link …Self)可以順利將目前的頁面轉頁到 drilldown.htm ,所以預設在 iframe 切頁是沒有問題的
javascript:window.location.assign(‘drilldown.htm’)

  • 當我們按下第 5 個 link (5.link …javascript),可以發現是沒有作用的,而在 console 中會顯示不允許執行 script 的訊息。

那我們如果將該 iframe 也加上 sandbox 並設定允許 javascript 執行(sandbox=”allow-scripts”)是否可行呢?

childFrameA.htm

<html>
    <head>
        <title>Sandboxed Iframes</title>
        <style>
            #childFrameA-ChildFrame {
              width:400px;
              height: 305px;
              margin: auto;
              border: 2px solid #224477;
            }
        </style>
    </head>
    <body>
        <h2>This is childFrameA's Page </h2>
        <div>
            <iframe id="childFrameA-ChildFrame" src="/childFrameA-ChildFrame.htm" frameborder="1" sandbox="allow-scripts"></iframe>
        </div>
    </body>
</html>

結果還是沒有作用,但這次 console 卻也沒有任何的錯誤訊息出現。
所以在 Child Frame 去開放權限也會被 Root sandbox 所限制住。

  • 接著在 index.htm 的 iframe sandbox 屬性去設定 allow-scripts ,並將 childFrameA.htm 中 iframe sandbox 拿掉,重新整理頁面,可以發現每個 iframe 的 script 都有正常執行, 按下第 5 個 link (5.link …javascript) 就可以正常切到 drilldown.htm
target=”_top”

  • 當我們按下第 3 個 link (3.link …Top),可以發現也是沒有作用的,而在 console 中會顯示不允許瀏覽到 top-level window,如下,Unsafe JavaScript attempt to initiate navigation for frame with URL ‘http://10.211.55.3/iframesandbox/index.htm' from frame with URL ‘http://10.211.55.3/iframesandbox/childFrameA-ChildFrame.htm'. The frame attempting navigation of the top-level window is sandboxed, but the flag of ‘allow-top-navigation’ or ‘allow-top-navigation-by-user-activation’ is not set.

這時如果我們在 parentFrame.htm 中的 iframe 去設定 sandbox=”allow-top-navigation” ,也是沒有用的哦!
而且會造成原本在 index.htm 中設定的 allow-scripts 往下都失效哦! iframe 的 sandbox 屬性去做 And 操作。

所以按下第 3 個 link (3.link …Top),還是沒有作用的,而在 console 中也是顯示不允許瀏覽到 top-level window。

  • 清掉 parentFrame.htm 中 iframe sandbox 設定,並將 allow-top-navigation 也加到 index.htm 中的 iframe sandbox 屬性之中,就會變成了 sandbox=”allow-scripts allow-top-navigation” ,而第 3 個 link 也可以 work 了。
target=”_blank”

  • 按下第 4 個 link (4.link …Blank popup),可以發現也是沒有作用的,而在 console 中會顯示不允許開啟 window,如下,

Blocked opening ‘http://10.211.55.3/iframesandbox/drilldown.htm' in a new window because the request was made in a sandboxed frame whose ‘allow-popups’ permission is not set.

所以依前面的經驗,將 allow-popups 加到 index.htm 中的 iframe sandbox 屬性之中,就會變成了 sandbox=”allow-scripts allow-top-navigation allow-popups” ,而4 個 link (4.link …Blank popup) 也可以 work 了。

target=”_parent”

這就是本文的重點啦,因為所有的 iframe 都被 sandbox 限制住了,所以無法瀏覽到父視窗。
而錯誤訊息也沒有提示說,可以設定那個 allow 那個權限 …
那 … 怎麼辦呢? 無解嗎?
即然它說了,是因為 sandbox 的原因,那就不要用 sandbox 就可以了呀!

果然將 index.htm 中 iframe 屬性中的 sandbox 拿掉,就沒有問題了。

  • 但有人可能會說,這樣是否會不安全呢? 這取決於這個 iframe src 的內容,如果它的 src 是外部網站,那我會建議使用 sandbox ,如果它是您內部系統,而且您整個系統也不會對外,個人覺得是沒有問題的.
target=”_parent” , postMessage

  • 那如果有 sandbox 又想要瀏覽到 parent (祖先) 要如何做呢? 這時就只好透過 postMessage 的方式來達成了哦!
    新增第 6 個 link (6.postMessage …javascript),並使用 postMessage,所以 childFrameA-ChildFrame.htm 改成以下的內容,

childFrameA-ChildFrame.htm

<html>
	<head>
        <script>console.log(window.location.href);</script>
    </head>
    <body>
        <h2>This is Child Frame  A's iframe page ... </h2>
        <a href="/drilldown.htm" target="_self">1.link ...Self</a>
        <br>
        <a href="/drilldown.htm" target="_parent">2.link ...Parent</a>
        <br>
        <a href="/drilldown.htm" target="_top">3.link ...Top</a>
        <br>
        <a href="/drilldown.htm" target="_blank">4.link ...Blank popup</a>
        <br>
        <a href="javascript:window.location.assign('drilldown.htm')">5.link ...javascript</a>
		<br>
        <a href="javascript:window.parent.postMessage({url:'drilldown.htm'}, 'http://10.211.55.3');">6.postMessage ...javascript</a>
    </body>
</html>

而它父網頁 childFrameA.htm 則改成如下,

<html>
    <head>
        <title>Sandboxed Iframes</title>
        <style>
            #childFrameA-ChildFrame {
              width:400px;
              height: 305px;
              margin: auto;
              border: 2px solid #224477;
            }
        </style>
		<script>
			console.log(window.location.href);
			window.addEventListener('message', function(event) {
				if(event.data.url){
					window.location.assign(event.data.url);
				}
			});
		</script>
    </head>
    <body>
        <h2>This is childFrameA's Page </h2>
        <div>
            <iframe id="childFrameA-ChildFrame" src="/childFrameA-ChildFrame.htm" frameborder="1" ></iframe>
        </div>
    </body>
</html>

這時按下第 6 個 link (6.postMessage …javascript),Parent視窗就會被換成了 drilldown.htm 了哦!

當然,如果無法去改用 postMessage 的方式(可能是代理的產品, 你跟本改不了)。請評估不使用 sandbox 屬性來達到想要的行為!

參考資料

Play safely in sandboxed IFrames
HTML <iframe> sandbox Attribute
Understanding iFrame sandboxes and iFrame security
Cross-window communication

×
Stay Informed

When you subscribe to the blog, we will send you an e-mail when there are new updates on the site so you wouldn't miss them.

Blazor WebAssembly 與 Server 相互轉換
Ansible 初體驗 (安裝 Docker)
Comment for this post has been locked by admin.
 

評論