當咱們要在域名A.com下使用一個域名B.com提供的頁面服務,直覺想到的實現方式就是使用iframe。可是iframe直接的交互存在**跨域問題**,目前看來解決方式有兩種。一是使用nginx代理轉發,在域名A的nginx上配置指定的轉發規則,直接指向域名B,直接幹掉了跨域;另外一種方式是使用postMessage方法。此處針對第二種方式,看下使用方式和可能的問題。
此處引用MDN關於postMessage的詳細說明。簡而言之就是:postMessage是掛載在window下的一個方法,用於不一樣域名下的兩個頁面的信息交互,父子頁面經過postMessage()發送消息,再經過監聽message事件接收信息。javascript
假設有一個父頁面indexPage.html, 子頁面iframePage.htmlphp
// 父頁面index.html //獲取iframe元素 iFrame = document.getElementById('iframe') //iframe加載完畢後再發送消息,不然子頁面接收不到message iFrame.onload = function(){ //iframe加載完當即發送一條消息 iFrame.contentWindow.postMessage({msg: 'MessageFromIndexPage'},'\*'); }
iFrame.contentWindow.postMessage('MessageFromIndexPage','b.com')html
方法的第一個參數是發送的消息,無格式要求;第二個參數是域名限制,當不限制域名時填寫* ,第三個可選參數transfer通常不填,這個參數有嚴重的瀏覽器兼容問題。java
// 子頁面iframePage.html //監聽message事件 window.addEventListener("message", function(event){ console.log( '這裏是接收到來自父頁面的消息,消息內容在event.data屬性中', event ) }, false)
window.parent.postMessage({name: '張三'}, '\*');
方法的第一個參數是發送的消息,目前可無格式要求, 在 Gecko 6.0 (Firefox 6.0 / Thunderbird 6.0 / SeaMonkey 2.3)以前, 參數 message 必須是一個字符串;第二個參數是域名限制,當不限制域名時填寫’*‘nginx
//監聽message事件 window.addEventListener("message", function receiveMessageFromIframePage (event) { console.log('這裏是子頁面發送來的消息,消息內容在event.data屬性中', event) }, false);
使用postMessage交互,默認就是容許跨域行爲,一旦容許跨域,就會有一些安全問題,針對postMessage主要有兩種攻擊方式。一是僞造數據發送方(父頁面),易形成數據接收方(子頁面)受到XSS攻擊或其餘安全問題;二是僞造數據接收方,相似jsonp劫持。json
攻擊方式:僞造一個父頁面,引導使用者觸發功能,發送消息給子頁面,若是子頁面將父頁面發送的消息直接插入當前文檔流,就是引起XSS攻擊,或者子頁面使用父頁面傳遞的消息進行其餘操做,例如寫入數據,形成安全問題。跨域
防範方式:子頁面iframe對接收到的message信息作域名限制瀏覽器
// 子頁面iframePage.html //監聽message事件 window.addEventListener("message", function(event){ origin = event.origin || event.originalEvent.origin if(origin == 'https://A.com'){ console.log( '這裏是接收到來自父頁面的消息,消息內容在event.data屬性中', event ) } }, false)
攻擊方式:僞造一個子頁面,在父頁面中引入子頁面,在僞造的頁面中接收父頁面發送的消息,此時能夠獲取用戶的敏感消息。安全
防範方式:父頁面對發送消息的頁面作域名限制post
// 父頁面index.html //獲取iframe元素 iFrame = document.getElementById('iframe') //iframe加載完畢後再發送消息,不然子頁面接收不到message iFrame.onload = function(){ //iframe加載完當即發送一條消息 iFrame.contentWindow.postMessage('MessageFromIndexPage','https://B.com'); }
參考: