前言
最近遇到一個 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
1 | <html> |
parentFrame.htm
1 | <html> |
childFrameA.htm
1 | <html> |
childFrameA-ChildFrame.htm
1 | <html> |
drilldown.htm
1 | <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
1 | <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”
- 按下第 2 個 link (2.link …Parent),可以發現也是沒有作用的,而在 console 中會顯示瀏覽到祖先,如下,
Unsafe JavaScript attempt to initiate navigation for frame with URL ‘http://10.211.55.3/iframesandbox/childFrameA.htm‘ from frame with URL ‘http://10.211.55.3/iframesandbox/childFrameA-ChildFrame.htm‘. The frame attempting navigation is sandboxed, and is therefore disallowed from navigating its ancestors.
這就是本文的重點啦,因為所有的 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而它父網頁 childFrameA.htm 則改成如下,1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19<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>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27<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