HTML 5 安全

新標籤的XSS

HTML5 定義了很多新的標籤、事件,這有可能帶來新的XSS攻擊。

一些XSS Filter 如果建立了一個黑名單的話,則可能就不會覆蓋到HTML5新增的標籤和功能,從而避免發生XSS。

筆者曾經在百度空間做過一次測試,使用的是HTML5新增的<video>標籤,這個標籤可以在網頁中遠程加載一段視頻。與<video>標籤類似的還有<audio>標籤,用於遠程加載一段音頻。

<video src="http://tinyvid.tiv/file/29d6d90ad.ogg"
onloadedmetadata="alert(document.cookie);" ondurationchanged="alert(//XSS2/);"
ontimeupdate="alert(/XSS1/);" tabindex="0"></video>

成功地繞過了百度空間的XSS Filter:

HTML 5 中新增的一些標籤和屬性,使得XSS等Web攻擊產生了新的變化,爲了總結這些變化,有安全研究者建立了一個HTML 5 Security Cheatsheet 項目,此項目對研究HTML 5 安全有着重要作用。

 

iframe 的 sandbox

<iframe> 標籤一直以來都爲人所詬病。掛馬、XSS、ClickJacking等攻擊中都能看到它不光彩的身影。瀏覽器廠商也一直在想辦法限制iframe執行腳本的權限,比如跨窗口訪問會有限制,以及IE中的 <iframe> 標籤支持 security 屬性限制腳本的執行,都在向着這一目標努力。

在HTML5中,專門爲iframe 定義了一個新的屬性,叫 sandbox。使用 sandbox 這個屬性後,<iframe> 標籤加載的內容將爲視爲一個獨立的“源”,其中的腳本將被禁止執行,表單被禁止提交,插件被禁止加載,指向其他瀏覽對象的連接也會被禁止。sandbox 屬性可以通過參數來支持更精確的控制。有以下幾個值可以選擇:

  • allow-same-origin:允許同源訪問;
  • allow-top-navigation:允許訪問頂層窗口;
  • allow-form:允許提交表單;
  • allow-script:允許執行腳本。

可有的行爲即便是設置了allow-scripts,也是不允許的,比如“彈出窗口”。

一個iframe的實例如下:

<iframe sandbox="allow-same-origin allow-forms allow-scripts" 
        src="http://maps.example.com/embedded.html"></iframe>

毫無疑問,iframe的sandbox屬性將極大地增強應用使用iframe的安全性。

 

Link Types:noreferrer

在HTML 5 中爲<a>標籤和<area>標籤定義了一個新的Link Types:noreferrer。

標籤指定了 noreferrer 後,瀏覽器在請求該標籤指定的地址時將不再發送Referrer。這個標籤需要開發者手動添加到頁面的標籤中,對於有需要的標籤可以使用noreferrer。

<a href="xxx" rel="noreferrer" >test</a>

這種設計是出於保護敏感信息和隱私的考慮。因爲通過Referrer,可能會泄露一些敏感信息。

 

Cross-Origin Resource Sharing

瀏覽器實現的同源策略(Same Origin Policy)限制了腳本的跨域請求。但是互聯網的發展趨勢是越來越開放的,因此跨域訪問的需求也變得越來越迫切。同源策略給Web開發者帶來了很多困擾,他們不得不設法實現一些“合法”的跨域技術,由此誕生了jsop,iframe跨域等技巧。

W3C委員會決定製定一個新的標準--- CORS 來解決日益迫切的跨域訪問問題。

假設從 http://www.a.com/test.html 發起一個跨域的XMLHttpRequest 請求,請求的地址爲:http://www.b.com/test.php。

<script>
    var client = new XMLHttpRequest();
    client.open("GET", "http://www.b.com/test.php");
    client.onreadystatechange = function(){ }
    client.send(null);
</script>

如果服務器www.b.com返回一個HTTP Header:

Access-Control-Allow-Origin: http://www.a.com

代碼如下:

<?php
header("Access-Control-Allow-Origin: *");
?>
Cross Domain Request Test!

那麼這個來自 http://www.a.com/test.html 的跨域請求就會被通過。

在這個過程中,http://www.a.com/test.html 發起的請求還必須帶上一個 Origin Header:

Origin: http://www.a.com

在Firefox上,可以找包分析這個過程。

Origin Header 用於標記 HTTP 發起的”源“,服務器端通過識別瀏覽器自動帶上的這個Origin Header,來判斷瀏覽器的請求是否來自一個合法的”源“。Origin Header 可以用於防範CSRF,它不像Referer那麼容易被僞造或清空。

在上面的例子中,服務器返回:

Access-Control-Allow-Origin: *

從客戶端的跨域請求通過。在這裏使用了通配符 "*",這是極其危險的,它將允許來自任意域的請求訪問成功。這就好像Flash策略中的 allow-access-from: * 一樣,等於沒有做任何安全限制。

對於這個跨域訪問的標準,還有很多HTTP Header 可以用於進行更精確的控制:

 

PostMessage 跨窗口傳遞消息

在”跨站腳本攻擊“中,曾經提到利用window.name 來跨窗口、跨域傳遞消息。實際上,window這個對象幾乎是不受同源策略限制的,很多腳本攻擊都巧妙地利用了window對象的這一特點。

在HTML5中,爲了豐富Web開發者的能力,制定了一個新的API:postMessage。postMessage 允許每一個window(包括當前窗口、彈出窗口、iframes等)對象往其他的窗口發送文本消息,從而實現跨窗口的消息傳遞。這個功能不受同源策略限制的。

下面示例是一個postMessage的用法,

發送窗口:

<iframe src="http://dev.jquery.com/~john/message" id="iframe"></iframe>
<form id="form">
    <input type="text" id="msg" value="Message to send"/>
    <input type="submit"/>
</form>
<script>
window.onload = function(){
    var win = document.getElementById("iframe").contentWindow;
    document.getElementById("form").onsubmit = function(e){
        win.postMessage(document.getElementById("msg").value);
        e.preventDefault();
    };
};
</script> 

接收窗口:

<b>This iframe is loacated on dev.jquery.com</b>
<div id="test">Send me a message!</div>
<script>
document.addEventListener("message", function(e){
    document.getElementById("test").textContent = e.domain + " said: " + e.data;
}, false);
</script>

在這個例子中,發送窗口負責發送消息;而在接收窗口中,需要綁定一個message事件,監聽其他窗口發來的消息。這是兩個窗口之間的一個”約定“,如果沒有監聽這個事件,則無法接收到消息。

在使用postMessage()時,有兩個安全問題需要注意。

(1)在必要時,可以在接收窗口驗證Domain,甚至驗證URL,以防來自非法頁面的消息。這實際上是在代碼中實現一次同源策略的驗證過程。

(2)在本例中,接收消息寫入textContent,但實際應用中,如果將消息寫入innerHTML,甚至直接寫入script中,則可能會導致DOM based XSS的產生。根據”Secure By Default“原則,在接收窗口不應該信任接收到的消息,而需要對消息進行安全檢查。

使用postMessage,也會使XSS payload變得更加的靈活。Gareth Heyes 曾經實現過一個JavaScript運行環境的sandbox,其原理是創建一個iframe,將JavaScript限制於其中執行。但筆者進過研究發現,利用postMessage()給父窗口發送消息,可以突破此sandbox。

 

Web Storage

過去在瀏覽器裏能夠存儲信息的方法有以下幾種:

  • Cookie
  • Flash Shared Object
  • IE UserData

其中,Cookie主要用於保存登錄憑證和少量信息,其最大長度的限制決定了不可能在Cookie中存儲太多信息。而Flash Shared Object和IE UserData 則是Adobe與微軟自己的功能,並未成爲一個通用化的標準。因此W3C委員會希望能在客戶端有一個較爲強大和方便的本地存儲功能,這就是Web Storage。

Web Storage 分爲 Session Storage 和 Local Storage。Session Storage 關閉瀏覽器就會失效,而Local Storage則會一直存在。Web Storage就像一個非關係型數據庫,有Key-Value對組成,可以通過JavaScript對其進行操作。使用方法如下:

  • 設置一個值:window.sessionStorage.setItem(key, value);
  • 讀取一個值:window.sessionStorage.getItem(key);

下面這個示例展示了 Web Storage 的使用。

<div id="sessionStorage_show">
    sessionStorage Value:
</div>
<br>
<div id="localStorage_show">
    localStorage Value:
</div>

<input id="set" type="button" value="check" onclick="set();">

<script>
function set(){
    window.sessionStorage.setItem("test", "this is sessionStorage");
    if (window.globalStorage){
        window.globalStorage.namedItem("a.com").setItem("test", "this is LocalStorage");
    }else{
        window.localStorage.setItem("test", "this is LocalStorage");
    }

    document.getElementById("sessionStorage_show").innerHTML += window.sessionStorage.getItem("test");
    if(window.globalStorage){
        document.getElementById("localStorage_show").innerHTML += window.glabolStorage.namedItem("a.com").getItem("test");
    }else{
        document.getElementById("localStorage_show").innerHTML += window.localStorage.getItem("test");
    }
}
set();
</script>

運行結果如下:

Web Storage 也受到同源策略的約束,每個域所擁有的信息只會保存在自己的域下,如下例:

<body>
<script>
if (document.domain == "www.a.com"){
    window.localStorage.setItem("test",123);
}
alert(window.localStorage.getItem("test"));
</script>
</body>

運行結果如下:

當域變化時,結果如下:

Web Storage讓Web開發更加的靈活多變,它的強大功能也爲XSS Payload大開方便之門。攻擊者可能將惡意代碼保存在Web Storage中,從而實現跨頁面攻擊。當Web Storage中保存有敏感信息時,也可能成爲攻擊的目標,而XSS攻擊可以完成這一過程。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章