2014年10月17日 星期五

[AJAX]隱含殺機的GET式AJAX資料更新

網路上看到這篇文章,覺得相當重要,所以做筆記囉 :D

來源:黑暗執行緒

jQuery的出現讓AJAX網頁用jQuery.ajax()傳來的參數,馬上就實現了AJAX式的資料查詢、新增、修改、刪除功能。但是,小心不要寫出如下的程式碼:
protected void Page_Load(object sender, EventArgs e){
    if (Request["mode"] == "del")
    {
        try
        {
            CheckCookieForAuthentication();
            CheckPermission();
            Guid id = new Guid(Request["id"]);
            DataProcessor.DeleteData(id);
            Response.Write("OK");
        }
        catch (Exception ex)
        {
            //...Blah...
        }
        Response.End();
    }
看出問題在哪裡嗎?SQL Injection?new Guid(Request["id"])確保參數id必須是GUID,不致被塞入惡意程式碼。權限管控?CheckCookieForAuthentication()會檢查登入成功才有的Cookie作為身分識別、接著檢查使用者是否有權執行,看來夠嚴格。XSS?除了id外沒有接受其他的輸入參數,因此沒有資料內容驗證的問題。那麼,梗呢?梗到底在哪裡?

由這段程式的寫法來看,我們可以用webform.aspx?mode=del&id=[guid]的方式執行。換句話說,這支程式同時支援GET Request或POST Request呼叫,而這犯了兵家大忌!!!

永遠不要使用GET方式接收指令進行資料更新!

為什麼GET方式的更新很危險?Browser不是都有XmlHttpRequest(XHR)跨網域限制嗎?User必須登入該網站,才能使用XHR對該ASPX進行存取,如果想要在第三方網頁加掛程式碼以XHR進行XSS攻擊,應該會因跨網域被擋下來,不是嗎?

講到重點了,XHR是有跨網域限制,但<script src="…">沒有!
想像一個情境,假設有個芭樂小站部落格平台,用以上的GET寫法執行部落格文章的刪除。小白是芭樂小站站長,登入網站介面執行一些操作後,就跑去網路上打混閒晃。小黑是個駭客,想要刪除某篇看不爽的PO文,先查出該文的Blog GUID,然後寄封信給小白,在信件先嵌入幾張連到網路相簿的照片,例如:殺很大那種
<img src="httq://albumweb/someimage.jpg" />
最後多加個
<img src="httq://blah.com.tw/admin/delPost.aspx?mode=del&id=[guid]" style="display:none;" />
小白的瀏覽器剛做完部落格管理(或者在本機上保存了登入成功的Cookie)再收取WebMail,雖然WebMail會警告該信內嵌外部資源,預設不下載及Show圖,但當然是敵不過想看圖的衝動。按下同意顯示圖片,由albumweb下載照片的同時,也會觸發delBlog.aspx?mode=del&id=[guid],此時瀏覽器會沿用先前登入成功的Cookie,以站長權限執行刪除作業。就這樣,圖也看了、文也刪了,還真的"殺很大"。
是不是有些人現在才發現WebMail或Outlook外連圖片資安警告的用意?它還被用來防止另一種更常見的機車伎倆,例如:廣告信在圖片src加上你的email當成附加參數,開信看圖就等同宣告你的email是有效的,而且心腸很軟,有信都要稍微看一下以示禮貌,以後就會有收不完的廣告信了。XD
GET式AJAX資料更新的最大問題在於可以用之類的方法閃避XHR的跨限制。造成了可以從第三方的網頁盜用使用者Cookie、Session對原站發動的漏洞,因此在嚴謹的設計中,許多Web Service是完全禁止GET式存取的。例如:在ASP.NET AJAX裡,所有WebMethod只接受HTTP POST verb,更進一步還要求檢核Content-Type:application/json標頭,做到雙重保險。

在以上的例子裡,我們可以加上(Request.HttpMethod == "POST")的檢查阻止GET請求,若是用WCF等機制預設都有相關保護,不要隨便亂改設定即可。但這些都只算基本防護,如果要談更進一步的管控,可以在登入完成後,在網頁上產一個Token(不要放入Cookie,降低被盜風險),在執行與這個網頁相關的資料查詢; 更新動作時,一併傳回Token驗明正身,這樣便可以將更嚴格限定只能由網頁發出相關需求。

在網路世界裡,處處埋藏殺機,開發者不可不慎。

沒有留言:

張貼留言