最近遇到一個 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 內容額外的限制,限制如下,
所以當 iframe 加入 sanbox 屬性後,就會去針對內容進行一些限制,例如,
所以使用了 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.
那我們如果將該 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 所限制住。
這時如果我們在 parentFrame.htm 中的 iframe 去設定 sandbox=”allow-top-navigation” ,也是沒有用的哦!
而且會造成原本在 index.htm 中設定的 allow-scripts 往下都失效哦! iframe 的 sandbox 屬性去做 And 操作。
所以按下第 3 個 link (3.link …Top),還是沒有作用的,而在 console 中也是顯示不允許瀏覽到 top-level 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 了。
這就是本文的重點啦,因為所有的 iframe 都被 sandbox 限制住了,所以無法瀏覽到父視窗。
而錯誤訊息也沒有提示說,可以設定那個 allow 那個權限 …
那 … 怎麼辦呢? 無解嗎?
即然它說了,是因為 sandbox 的原因,那就不要用 sandbox 就可以了呀!
果然將 index.htm 中 iframe 屬性中的 sandbox 拿掉,就沒有問題了。
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
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.