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

jQuery的出現讓AJAX網頁的開發瞬間變簡單了。只要寫支簡單的ASPX,用Request["..."]接入前端用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資料更新的最大問題在於可以用<img src="...">之類的方法閃避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驗明正身,這樣便可以將更嚴格限定只能由該網頁發出相關需求。

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

歡迎推文分享:
Published 16 April 2009 04:13 PM 由 Jeffrey
Filed under: , , ,
Views: 32,552



意見

# weskerjax said on 16 April, 2009 01:10 AM

正所謂 CSRF 漏洞缺失

OWASP 關注的十大缺失之一

www.owasp.org/.../Taiwan

# Tom said on 16 April, 2009 01:16 AM

寫筆記中... 有學到...

# andy said on 16 April, 2009 07:12 AM

請問(在網頁上產生一個Token) 有範例可參考嗎?

# Ark said on 25 April, 2009 11:03 PM

我的做法是比對Request.Url & Request.UrlReferrer

來判別

# 布丁 said on 28 April, 2009 02:09 AM

同事的做法是request method為get時,sql帳號使用Select only權限,request method為post時,則用可修改資料權限的帳號。

# 海角147號 said on 20 October, 2009 08:21 PM

最保險的方法還是最好把每個傳入ASPX的參數做檢查

包含 POST 和 GET 都要檢查..!!

只要其中一個參數不和規則,就自動 Throw new Exception 檔掉

另外,傳入資料庫的 SQL Command

最好是先用字串型態接收參數,然後再 CAST 或是 Convert過

例如:

declare @param1 nvarchar(50)

, @param2 nvarchar(50)

Select @param1 = N'%param1%'

, @param2 = N'%param2%'

Select

*

From [TABLE1]

Where [column1] = CAST(@param As int)

And [column2] = CAST(@param As datetime)

# jocosn said on 08 May, 2011 09:21 PM

「那麼,梗呢? 梗到底在哪裡?」→ 這句好有趣,很好笑。黑大你好幽默耶!

# 小黑 said on 15 June, 2012 02:12 AM

黑大你是我的偶像,甚麼時候我才可以寫出不裸奔的網站呢?

# 0.0 said on 10 March, 2016 03:25 AM

0.0

你的看法呢?

(必要的) 
(必要的) 
(選擇性的)
(必要的) 
(提醒: 因快取機制,您的留言幾分鐘後才會顯示在網站,請耐心稍候)

5 + 3 =

搜尋

Go

<April 2009>
SunMonTueWedThuFriSat
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789
 
RSS
創用 CC 授權條款
【廣告】
twMVC
最新回應

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


Syndication