淺析 postMessage 方法介紹、如何接收數據(監聽message事件及其屬性介紹)、使用postMessage的安全注意事項、具體使用方式(父子頁面如何互發消息、接收消息)


  postMessage 是 html5 引入的API,postMessage()方法允許來自不同源的腳本采用異步方式進行有效的通信,可以實現跨文本文檔、多窗口、跨域消息傳遞,多用於窗口間數據通信,這也使它成為跨域通信的一種有效的解決方案

一、Window postMessage() 方法介紹

  postMessage() 方法用於安全地實現跨源通信。(只有同源腳本才能相互通信,window.postMessage() 方法提供了一種受控機制來規避此限制,只要正確的使用,這種方法就很安全。)

1、語法:otherWindow.postMessage(message, targetOrigin, [transfer]);

(1)otherWindow:其他窗口的一個引用,比如iframe的contentWindow屬性、執行window.open返回的窗口對象、或者是命名過或數值索引的window.frames。

(2)message:將要發送到其他 window的數據。它將會被結構化克隆算法序列化。這意味着你可以不受什么限制的將數據對象安全的傳送給目標窗口而無需自己序列化。

(3)targetOrigin:通過窗口的origin屬性來指定哪些窗口能接收到消息事件,其值可以是字符串"*"(表示無限制)或者一個URI。

  在發送消息的時候,如果目標窗口的協議、主機地址或端口這三者的任意一項不匹配targetOrigin提供的值,那么消息就不會被發送;

  只有三者完全匹配,消息才會被發送。

  這個機制用來控制消息可以發送到哪些窗口;例如,當用postMessage傳送密碼時,這個參數就顯得尤為重要,必須保證它的值與這條包含密碼的信息的預期接受者的origin屬性完全一致,來防止密碼被惡意的第三方截獲。

  如果你明確的知道消息應該發送到哪個窗口,那么請始終提供一個有確切值的targetOrigin,而不是*。不提供確切的目標將導致數據泄露到任何對數據感興趣的惡意站點。

(4)transfer可選:是一串和message 同時傳遞的 Transferable 對象,這些對象的所有權將被轉移給消息的接收方,而發送一方將不再保有所有權。

 2、接收數據:監聽message事件的發生

// 執行如下代碼, 其他window可以監聽分發的message:
window.addEventListener("message", receiveMessage, false); function receiveMessage(event) { var origin = event.origin if (origin !== "http://example.org:8080") return; // ...
}

  message 的屬性有:

(1)data:從其他 window 中傳遞過來的對象。

(2)origin:調用 postMessage  時消息發送方窗口的 origin。

  這個字符串由 協議、“://“、域名、“ : 端口號”拼接而成。例如 “https://example.org (隱含端口 443)”、“http://example.net (隱含端口 80)”、“http://example.com:8080”。

  請注意,這個origin不能保證是該窗口的當前或未來origin,因為postMessage被調用后可能被導航到不同的位置。

(3)source:對發送消息的窗口對象的引用,您可以使用此來在具有不同origin的兩個窗口之間建立雙向通信。

(4)type: 指的是發送消息的類型;

  event 對象的打印結果截圖如下:

3、安全問題

  如果您不希望從其他網站接收message,請不要為message事件添加任何事件偵聽器。 這是一個完全萬無一失的方式來避免安全問題。

  如果您確實希望從其他網站接收message,請始終使用origin和source屬性驗證發件人的身份。 任何窗口(包括例如http://evil.example.com)都可以向任何其他窗口發送消息,並且您不能保證未知發件人不會發送惡意消息。 但是,驗證身份后,您仍然應該始終驗證接收到的消息的語法。 否則,您信任只發送受信任郵件的網站中的安全漏洞可能會在您的網站中打開跨網站腳本漏洞。

  當您使用postMessage將數據發送到其他窗口時,始終指定精確的目標origin,而不是*。 惡意網站可以在您不知情的情況下更改窗口的位置,因此它可以攔截使用postMessage發送的數據。

二、postMessage 使用方法

  HTML5 提出了一個新的用來跨域傳值的方法,即postMessage,IE8也開始支持了。我們假設有兩個網站,1.com 與 2.com,我在 1.com 的頁面上通過 iframe 或 window.open 或超鏈接打開了一個 2.com 的網頁,此時我要在 2.com 上做操作的時候,給 1.com 傳值,讓 1.com 有所變化。這個過程就是個跨域的過程。

  比如,你的父頁面有個函數叫 callback,然后你子頁面本可以這樣調用:window.opener.callback(),同域時能成功,跨域時就沒有權限了。但是,此時你調用window.opener.postMessage(),卻可以成功。

  我們看一下如何具體使用:

// 1、父頁面向子頁面發送消息
let data = {type: 'answerResult', data: jsonData.data}; this.$refs.iframe.contentWindow.postMessage(data, '*'); // 2、子頁面向父頁面發送消息
let parentData = {type: 'passDataBack', data: passData}; window.parent.postMessage(parentData, '*'); // 3、接收消息方法
window.addEventListener('message', function (e) {})

  方法封裝之后在頁面中的具體使用:

// 父頁面
mounted(){ window.addEventListener("message", this.handleMessage) }, methods:{ // 向iframe傳值的方法 @param {Object} data sendMessage(data){ const iframe = this.$refs.iframePage.contentWindow; iframe.postMessage(data, '*'); }, // 監聽子頁面傳過來的值的方法 @param {Object} event handleMessage (event) { // dosomething
 } } // 子頁面
mounted(){ window.addEventListener("message", this.handleMessage) }, methods:{ // 向父頁面傳值的方法 @param {Object} data sendMessage(data){ window.parent.postMessage(data, '*'); } // 監聽父頁面傳過來的值的方法 @param {Object} event handleMessage (event) { // dosomething
 } }

  這里需要注意一點的就是:postMessage語法 - window.postMessage(msg,targetOrigin),postMessage要通過 window 對象調用!因為這里的window不只是當前window,大部分使用postMessage的時候,都不是本頁面的window,而是其他網頁的window!如:

(1)iframe的contentWindow

(2)通過window.open方法打開的新窗口的window

(3)window.opener

(4)如果你使用postMessage時沒有帶window,那么當然,你就是用的本頁面的window來調用了它。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM