iframe跨域

来源:https://www.cnblogs.com/xiaohuochai/archive/2017/12/28/8136209.html
-Advertisement-
Play Games

[1]引入 [2]iframe [3]domain屬性 [4]錨點值 [5]XDM ...


前面的話

  script、image、iframe的src都不受同源策略的影響。所以可以藉助這一特點,實現跨域。例如,前面介紹的jsonp是使用script標簽,imgPing是使用image標簽,而本文將介紹使用iframe標簽實現跨域

 

引入

  1995年,同源政策由 Netscape 公司引入瀏覽器。目前,所有瀏覽器都實行這個政策。最初,它的含義是指,A 網頁設置的 Cookie,B 網頁不能打開,除非這兩個網頁“同源”。所謂“同源”指的是”三個相同“:1、協議相同;2、功能變數名稱相同;3、埠相同

  舉例來說,http://www.example.com/dir/page.html這個網址,協議是http://,功能變數名稱是www.example.com,埠是80(預設埠可以省略)。它的同源情況如下

http://www.example.com/dir2/other.html:同源
http://example.com/dir/other.html:不同源(功能變數名稱不同)
http://v2.www.example.com/dir/other.html:不同源(功能變數名稱不同)
http://www.example.com:81/dir/other.html:不同源(埠不同)
https://www.example.com/dir/page.html:不同源(協議不同)

  同源政策的目的,是為了保證用戶信息的安全,防止惡意的網站竊取數據。

  設想這樣一種情況:A 網站是一家銀行,用戶登錄以後,又去瀏覽其他網站。如果其他網站可以讀取 A 網站的 Cookie,會發生什麼?很顯然,如果 Cookie 包含隱私(比如存款總額),這些信息就會泄漏。更可怕的是,Cookie 往往用來保存用戶的登錄狀態,如果用戶沒有退出登錄,其他網站就可以冒充用戶,為所欲為。因為瀏覽器同時還規定,提交表單不受同源政策的限制。

  由此可見,“同源政策”是必需的,否則 Cookie 可以共用,互聯網就毫無安全可言了

  隨著互聯網的發展,“同源政策”越來越嚴格。目前,如果非同源,共有三種行為受到限制

  1、Cookie、LocalStorage 和 IndexedDB 無法讀取

  2、DOM 無法獲得

  3、AJAX 請求無效(可以發送,但瀏覽器會拒絕接受響應)

  雖然這些限制是必要的,但是有時很不方便,合理的用途也受到影響

 

iframe

  iframe元素可以在當前網頁之中,嵌入其他網頁。每個iframe元素形成自己的視窗,即有自己的window對象。iframe視窗之中的腳本,可以獲得父視窗和子視窗。但是,只有在同源的情況下,父視窗和子視窗才能通信;如果跨域,就無法拿到對方的DOM

  [註意]關於iframe的詳細信息移步至此

  比如,父視窗和子視窗的代碼如下所示,都處於localhost域下

<!-- 父視窗test.html-->
<body>
  <iframe id="myIFrame" src="iframe.html"></iframe>
  <script>
    var iframe = document.getElementById("myIFrame");
    iframe.onload = function(){
      var doc = iframe.contentWindow.document;
      console.log(doc.getElementById('test').innerHTML);//'xiaohuochai'
      console.log(document.cookie);//'name=match'
    }
  </script>
</body>
<!-- 子視窗iframe.html-->
<body>
  <div id="test">xiaohuochai</div>
  <script>
  document.cookie = 'name=match';
  </script>
</body>

  如果iframe視窗不是同源,如處於文件域下(file:///C:/Users/Administrator/Desktop/demo/js/test.html),就會報錯

  <iframe id="myIFrame" src="iframe.html"></iframe>
  <script>
    var iframe = document.getElementById("myIFrame");
    iframe.onload = function(){
    //Uncaught DOMException: Blocked a frame with origin "null" from accessing a cross-origin frame. console.log(iframe.contentWindow.document); } </script>

  上面命令中,父視窗想獲取子視窗的DOM,因為跨域導致報錯。

  反之亦然,子視窗獲取主視窗的DOM也會報錯。

window.parent.document.body
// 報錯

  這種情況不僅適用於iframe視窗,還適用於window.open方法打開的視窗,只要跨域,父視窗與子視窗之間就無法通信

 

domain屬性

  如果兩個視窗一級功能變數名稱相同,只是二級功能變數名稱不同,可以通過設置document.domain來使其通信

  父視窗地址為https://static.xiaohuochai.site/test/test.html

  子視窗地址為https://demo.xiaohuochai.site/test/iframe.html

  代碼如下

<!-- 父視窗test.html-->
<body>
  <iframe id="myIFrame" src="https://demo.xiaohuochai.site/test/iframe.html"></iframe>
  <script>
    var iframe = document.getElementById("myIFrame");
    iframe.onload = function(){
      var doc = iframe.contentWindow.document;
      console.log(doc.getElementById('test').innerHTML);//'xiaohuochai'
      console.log(document.cookie);
    }
  </script>
</body>
<!-- 子視窗iframe.html-->
<body>
  <div id="test">xiaohuochai</div>
  <script>
  document.cookie = 'name=match';
  </script>
</body>

  由結果所示,通過設置document.domain只能獲取DOM,而Cookie、LocalStorage 和 IndexedDB 無法讀取

 

錨點值

  錨點值,又稱為片段標識符(fragment identifier),指的是URL的#號後面的部分,比如http://example.com/x.html#fragment#fragment。如果只是改變片段標識符,頁面不會重新刷新

  父視窗可以把信息,寫入子視窗的錨點值

var src = originURL + '#' + data;
document.getElementById('myIFrame').src = src;

  子視窗通過監聽hashchange事件得到通知

window.onhashchange = checkMessage;

function checkMessage() {
  var message = window.location.hash;
  // ...
}

  同樣的,子視窗也可以改變父視窗的片段標識符

parent.location.href= target + '#' + hash;

  下麵是具體代碼

<!-- 父視窗test.html-->
<body>
  <iframe id="myIFrame" src="iframe.html"></iframe>
  <script>
    var iframe = document.getElementById("myIFrame");
    window.onhashchange = function (e) {
      console.log(/.*#(.*)/g.exec(e.newURL)[1])//'xiaohuochai'  
    } 
  </script>
</body>
<!-- 子視窗iframe.html-->
<body>
  <div id="test">xiaohuochai</div>
  <script>
    parent.location.href = 'test.html' + '#' + test.innerHTML;
  </script>
</body>

 

XDM

  上面兩種方法都屬於破解,HTML5為瞭解決這個問題,引入了一個全新的API:跨文檔通信 API

  [註意]IE8-瀏覽器不支持

  跨文檔消息傳送(cross-document messaging),有時候簡稱為XDM,指的是在來自不同域的頁面間傳遞消息。例如,www.wrox.com域中的頁面與位於一個內嵌框架中的p2p.wrox.com域中的頁面通信。 在XDM機制出現之前,要穩妥地實現這種通信需要花很多工夫。XDM把這種機制規範化,讓我們能既穩妥又簡單地實現跨文檔通信

  XDM的核心是postMessage ()方法。在HTML5規範中,除了 XDM部分之外的其他部分也會提到這個方法名,但都是為了同一個目的:向另一個地方傳遞數據。對於XDM而言,“另一個地方”指的是包含在當前頁面中的<iframe>元素,或者由當前頁面彈出的視窗

  postMessage()方法接收兩個參數:一條消息和一個表示消息接收方來自哪個域的字元串。第二個參數對保障安全通信非常重要,可以防止瀏覽器把消息發送到不安全的地方

  來看下麵的例子。

//註意:所有支持XDM的瀏覽器也支持ifraaie的contentWindow屬性
var iframeWindow = document.getElementById("rayframe").contentWindow,
iframeWindow.postMessage( "A secret', "http://www.wrox.com");

  最後一行代碼嘗試向內嵌框架中發送一條消息,並指定框架中的文檔必須來源於"http://www.wrox.com"域。如果來源匹配,消息會傳遞到內嵌框架中;否則,postMessage()什麼也不做。 這一限制可以避免視窗中的位置在你不知情的情況下發生改變。如果傳給postMessage()的第二個參數是"*",則表示可以把消息發送給來自任何域的文檔,但不推薦這樣做

  接收到XDM消息時,會觸發window對象的message事件。這個事件是以非同步形式觸發的,因此從發送消息到接收消息(觸發接收視窗的message事件)可能要經過一段時間的延遲。觸發message事件後,傳遞給onmessage處理程式的事件對象包含以下三方面的重要信息

data:作為postMessage()第一個參數傳入的字元串數據
origin:發送消息的文檔所在的域,例如"http://www.wrox.com"。 
source:發送消息的文檔的window對象的代理。這個代理對象主要用於在發送上一條消息的視窗中調用postMessage()方法。如果發送消息的視窗來自同一個域,那這個對象就是window

  接收到消息後驗證發送視窗的來源是至關重要的。就像給postMessage()方法指定第二個參數, 以確保瀏覽器不會把消息發送給未知頁面一樣,在onmessage處理程式中檢測消息來源可以確保傳入的消息來自已知的頁面。基本的檢測模式如下

window.onmessage = function(e){
  if(e.origin == 'http://www.wrox.com'){
    //處理接收到的數據
    processMessage(e.data);
    //可選:向來源視窗發送回執
    e.source.postMessage("Received!", "http//p2p.wrox.com");
  }
}

  [註意]event.source大多數情況下只是window對象的代理,並非實際的window對象。換句話說,不能通過這個代理對象訪問window對象的其他任何信息。只通過這個代理調用 postMessage()就好,這個方法永遠存在,永遠可以調用

  XDM還有一些怪異之處

  postMessage()的第一個參數最早是作為“永遠都是字元串”來實現的。但後來這個參數的定義改了,改成允許傳入任何數據結構。可是,並非所有瀏覽器都實現了這一變化。為保險起見,使用postMessage()時,最好還是只傳字元串。如果想傳入結構化的數據,最佳選擇是先在要傳入的數據上調用JSON.stringify(),通過postMessage()傳入得到的字元串,然 後再在onmessage事件處理程式中調用JSON.parse()

  在通過內嵌框架載入其他域的內容時,使用XDM是非常方便的。因此,在混搭(mashup)和社交網路應用中,這種傳遞消息的方法極為常用。有了XDM,包含<iframe>的頁面可以確保自身不受惡意內容的侵擾,因為它只通過XDM與嵌入的框架通信。而XDM也可以在來自相同域的頁面間使用

  下麵是一個實例

  父視窗地址為https://static.xiaohuochai.site/test/test_1.html

  子視窗地址為https://demo.xiaohuochai.site/test/iframe_1.html

  代碼如下

<!-- 父視窗test_1.html-->
<body>
  <iframe id="myIFrame" src="https://demo.xiaohuochai.site/test/iframe_1.html"></iframe>
  <script>
    window.onmessage = function (e) {
      if(e.origin === 'https://demo.xiaohuochai.site'){
        console.log(e.data);//'xiaohuochai'
      }
    }
  </script>
</body>
<!-- 子視窗iframe_1.html-->
<body>
  <script>
  if (window.parent !== window.self) {
    window.parent.postMessage('xiaohuochai', 'https://static.xiaohuochai.site');
  }
  </script>
</body>

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 第一個section上邊多餘間距處理 每個section下邊多餘間距處理 備註:若傳入的 height == 0,則 height 被設置成預設值 若 height 小於屏幕半像素對應的高度,則不會被渲染,所以這裡返回CGFLOAT_MIN,其實返回0.01也是可以的 補充:代碼順序的不同導致第一個 ...
  • 記錄一下用得比較熟練的git命令 git clone: 克隆遠程代碼到本地,使用格式: git clone url (項目所在的遠程倉庫路徑) git clone 只是克隆master上的代碼,要想克隆其他分支的代碼,可以先使用git branch -r來查看遠程分支,再使用 git checkou ...
  • Nicescroll滾動條插件是一個非常強大的基於jQuery的滾動條插件,不需要增加額外的css,幾乎全瀏覽器相容。ie6+,實現只需要一段代碼,侵入性非常小,樣式可完全自定義,支持觸摸事件,可在觸摸屏上使用。 Nicescroll官網地址:http://www.areaaperta.com/ni ...
  • 前言 本文先假設我們使用的是 vue + vuex + vue-router 的情況來展開討論,React 全家桶的情況應該類似。 在日常的前端研發中,我們經常會遇到如題的場景:比如從商品列表進入商品詳情,從訂單列表進入訂單詳情。先看一個 demo~ 看起來是不是還算絲滑流暢,跟客戶端效果較為接近~ ...
  • 微信小程式使用場景延伸:掃碼登錄、掃碼支付 小程式最適合的使用場景有哪些?相比大家能列舉出來很多,但這個場景,大家可能多數沒想到_^ 筆者團隊近期接到了一個PC項目:轉轉游戲租號PC官網,該項目要求在PC端實現整個交易流程,問題來了,我司(轉轉)一直深耕於移動端,在PC端幾乎啥都沒有,甚至都沒有個像 ...
  • /** * JS獲取距當前時間差 * * @param int time 時間戳格式 * */ function get_time_diff(time) { var diff = ''; var time_diff = new Date().getTime() - time; //時間差的毫秒數 /... ...
  • <input type="checkbox" name="qId" onclick="doit();"/><input type="checkbox" name="qId" onclick="doit();"/><input type="checkbox" name="qId" onclick="d ...
  • HTML <a href="javascript:void()" onclick="show()">點擊此處顯示或隱藏</a> <div id="hoary" style="display:none">可以隱身可以顯示。</div> JS <script type="text/javascript" ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...