HTML5是下一代的Web應用,它具備許多新的特性,是一種新興的技術而且在移動應用中也有着普遍的使用。但也正是由於它的一些新特性的出現以及普遍的應用,使得其安全性很是值得關注。html
在本文中,咱們將針對HTML5 Web消息發送(跨域消息發送)的安全性進行分析和研究。html5
在討論這一問題以前,咱們先來了解下在HTML5中是如何實現跨域的消息發送。windows
在HTML5以前,因爲同源策略的限制致使在兩個窗口之間進行消息傳送必須是使用相同的協議、端口和主機。跨域
HTML5有一種新的方法叫作postMessage()
,經過這一方法,跨域的消息傳送將再也不受到同源策略的限制。安全
如下是postMessage()的語法:dom
otherWindow.postMessage(message, targetOrigin, [transfer]);
當otherWindow.postMessage()執行時,消息將會被髮送到接收窗口。post
發送方使用如下這段代碼後,咱們就能夠接收到這條消息。spa
window.addEventListener("message",receiveMessage, false); function receiveMessage(event){ if (event.origin !== "http://site.com:8383") return; // ... }
經過該段代碼,咱們能夠訪問數據以及這一信息的源。以下所示:3d
出於演示須要,我設立了以下兩個Lab:code
正如你所看到的,上面兩個URL具備不一樣的端口,第一個運行在8383端口,第二個則是在80端口。正是由於其源不一樣,因此才致使端口不一樣。
A是發送窗口,B是接收窗口
如今咱們加載第二個URL(http://localhost/ )做爲第一個URL的iframe:
經過使用postMessage()的方法,我能夠輕鬆的將消息從第一個URL發送到第二個URL.
咱們能夠經過點擊」send message「的按鈕來進行驗證。
儘管加載在第一個URL中的iframe與其並不一樣源,但經過postMessage() 便可進行信息傳遞。
如今咱們來看一些postMessage()使用過程當中可致使應用出現漏洞的例子:
receiver.postMessage('Hi There..!', '*');<
當發送者把targetOrigin規定爲通配符」*「時,將會致使未知的信息被陌生的接收方(窗口)接收到。緣由是從接收窗口傳來的消息任何人均可以再加載一個iframe來進行監聽。所以在進行敏感數據的傳輸時,使用通配符是一個十分錯誤的決定。
針對此問題最好的解決方法就是在發送時添加具體的目標字段,以下所示:
receiver.postMessage('Hi There..!', 'http://localhost');
function receiveMessage(e) { do something..! }
在上面這段代碼中能夠看到,咱們是直接接收發送方的消息對其進行處理,並不檢驗是否來自發送方。
但檢查消息的來源無疑是十分重要的,這樣能夠防止消息來自未經受權的發送者。
所以,咱們只須要在代碼中加入對發送方的驗證,這一問題就可解決了。代碼以下:
function receiveMessage(e) { if (e.origin !== "http://localhost:8383") return; do something..! }
經過檢驗event.origin,來進行驗證。
在這一過程當中,發送方和接收方都應該驗證正在傳送的.消息。若是數據插入到HTML DOM中時並無進行驗證,那麼應用頗有可能遭受到基於DOM的跨站腳本攻擊。
由下面這段代碼能夠看出,當應用程序接收到攻擊者發來的惡意信息,並已經插入到HTML DOM使用innerHTML屬性時,其顯得異常脆弱。
receiver.postMessage("<img src='x' onerror=alert(1);>", 'http://localhost');
function receiveMessage(e) { if (e.origin !== "http://localhost:8383") return; messageEle.innerHTML = "Message from localhost:8383: " + e.data; }
執行上面這段代碼,可致使在接收窗口出現XSS。
解決這一問題最簡單的方法就是在給元素分配數據值時使用 textContent 而不是innerHTML.
以下所示:
function receiveMessage(e) { if (e.origin !== "http://localhost:8383") return; element.textContent = "Message from localhost:8383: " + e.data; }
執行上面這段代碼時咱們能夠看到,文本中顯示frame是做爲數據而不是代碼。
從上圖咱們能夠看到,如今它並不執行代碼,而是顯示爲正常的文本。
[參考來源infosec,譯/Change,轉載自Freebuf黑客與極客(FreeBuf.COM)]