昨天收了一則考題:

如上圖,serverA上有個ParentPage.htm用IFrame內嵌了來自另一台Server(serverB)的網頁ChildPage.htm,ChildPage的網頁高度(Height)會因內容多寡而改變,大部分時候都會產生垂直軸捲。需求是 -- 希望ParentPage能依ChildPage的高度自動放大IFrame高度,避免產生捲軸。

這本來是個簡單的小需求,在ChildPage用$("body").height()取得網頁高度,將它當成參數傳給ParentPage以Javascript修改Iframe的Height就可大功告成。但本案的關鍵在於ChildPage與ParentPage分屬不同網站,依據瀏覽器的Same-Origin Policy,ChildPage不允許直接與ParentPage溝通,形成了"世上最遙遠的距離不是生與死,而是只隔了一個Pixel,卻不能傳參數過去"的難題。

解決Cross Domain Scripting限制的做法蠻多的,例如: 指定相同document.domain、JSONP... 等等。而這次決定嘗試用IFrame Proxy解決:

我們在ChildPage.htm再內嵌一個來自於serverA的IFrameProxy.htm,便形成有趣的互動關連: ChildPage存取parent會發生存取被拒、IFrameProxy存取parent(即ChildPage)也會發生存取被拒,但存取parent.parent(ParentPage)則因屬於同一document.domain可被放行。因此,便能在指向IFrameProxy.htm的URL多加上Query String帶入要傳給ParentPage的參數,IFrameProxy.htm由location.href取出參數後,就能透過parent.parent將參數送交給ParentPage。

程式範例如下:

ParentPage.htm

排版顯示純文字
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <script type="text/javascript">
        function setIframeSize(size) {
            var p = size.split('x');
            if (p.length != 2) return;
            var w = parseInt(p[0]), h = parseInt(p[1]);
            var frm = document.getElementById("frmX");
            frm.style.width = w + "px";
            frm.style.height = h + "px";
            setTimeout(function () {
                alert("Resize IFrame to " + w + "x" + h + "!");
            }, 100);
        }
    </script>
</head>
<body style="background-color: Green; color: White;">
serverA/ParentPage.htm<br />
<iframe id="frmX" src="http://serverB/ChildPage.htm" 
    width="400" height="100"></iframe>
</body>
</html>

ChildPage.htm

排版顯示純文字
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <script src="http://ajax.microsoft.com/ajax/jquery/jquery-1.4.2.min.js?WT.mc_id=DOP-MVP-37580" 
        type="text/javascript"></script> 
    <script type="text/javascript">
        $(function () {
            //將網頁高度帶入Query String參數
            $("#frmProxy").attr("src",
            "http://serverA/IframeProxy.htm?400x" 
            + ($("body").height() + 20));
        });
    </script>
    <style type="text/css">
        body  
        {
            background-color: Gray; color: White; 
            height: 300px;
        }
    </style>
</head>
<body>
serverB/ChildPage.htm <br />
<iframe id="frmProxy" style="display: none;"></iframe>
</body>
</html>

IFrameProxy.htm

排版顯示純文字
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <script type="text/javascript">
    var i = location.href.indexOf("?");
    var qs = i > 0 ? location.href.substring(i + 1, location.href.length) : "";
    var func = parent.parent.setIframeSize;
    if (func) func(qs);
    </script>
</head>
<body style="background-color: Green; color: White;">
serverA/IFrameProxy.htm
</body>
</html>

【重要提醒】在打破Cross Site Scripting限制的同時,也等於開啟了網頁接受來自其他網域網頁(包含惡意網頁)傳入參數的大門,在利用這些參數執行程式邏輯前,務必要檢核參數是否合於規定,避免惡意人士在其中夾帶程式碼,形成XSS資安漏洞。尤其是將收到的參數直接透過document.write()、window.eval()、指派給location.href... 等等方式輸出或執行,都是等同於裸奔的高風險行為,可能讓你顏面盡失,撰寫類似程式時千萬要謹慎為之。


Comments

# by dor0705

謝謝分享,學到不少好東西~~

# by Cheung

A very clear example, thank you !

# by Laing

前几天就为跨域的权限问题困扰半天,这是一个不错的思路。

# by Alexyont

謝謝大大的分享, 另外想請問Same origin policy, ServerA/ParentPage.htm要去call ServerB/ChildPage.htm上的javascript function是否也是違反Same origin policy? 若是的話, 是否也能在ParentPage.htm放置IframeProxy的方式來解決? 謝謝指教.

# by Jeffrey

to Alexyont, ServerA的網頁去存取ServerB網頁上的DOM元表或JavaScript物件/函數的確也違反SOP,構成Cross-Site Scripting。你提的解法我認為可行,跟文中的案子剛好反過來做(IFrameProxy由ServerB提供給ParentPage內嵌)就OK了。

# by shrdi

serverA.ParentPage.htm 和 serverB.ChildPage.htm 網頁內容都是自己寫成的才能這樣做... 如果serverB不是自己的呢? 應該就拿不到ChildPage.htm的資訊了吧?

# by Jeffrey

to shrdi, 如果無法要求ServerB配合,這招就行不通了。(行得通反而恐怖,等同於打破了XSS的安全機制)

# by gaku

所以假如我想嵌入的iframe是外部網頁, 如pchome ,yahoo.... 這篇的做法就不行了嗎?

# by Jeffrey

to gaku, 是的,被嵌入端不配合就行不通,這是瀏覽器基於安全必須維持的底線。

# by Guyher

I propose another way to achieve it and hope it helpful. It is easy to implement - No need to modify the web page at other server to be used in your . - Only need to add some javascript to your web page The key points of the proposed method are: -Obtain the HTML code of the web page to be used in your via Yahoo’s YQL - Create an with attribute src of empty Modify the obtained HTML code by adding ‘base’ tag and adding any javascript you want, e.g. for adjusting ’s - Set the ’s content to be the modified HTML code. Typically, this will have the same content/appearance as the web page at the other server. And more importantly, this is not a - one, so your script can access anything within the . For the details, on-line demo, and sample code, please refer to here: http://www.share888.info/published/PublishedDoc.asp?id=2

# by Jeffrey

to Guyher, 原理上類似透過Server端取回外部網站內容後再佯裝為自家內容,也算一種解法,謝謝分享。

Post a comment