[InvalidOperationException: 由於該物件目前的狀態,導致作業無效。]
System.Web.HttpValueCollection.ThrowIfMaxHttpCollectionKeysExceeded() +2692482
System.Web.HttpValueCollection.FillFromEncodedBytes(Byte[] bytes, Encoding encoding) +61
System.Web.HttpRequest.FillInFormCollection() +148
[HttpException (0x80004005): URL 編碼型式資料無效。]
System.Web.HttpRequest.FillInFormCollection() +206
System.Web.HttpRequest.get_Form() +68
System.Web.HttpRequest.get_HasForm() +8743911
System.Web.UI.Page.GetCollectionBasedOnMethod(Boolean dontReturnNull) +97
System.Web.UI.Page.DeterminePostBackMode() +63
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +133
出現上面錯誤訊息時,正想要設個中斷點來看看到底哪邊發生錯誤,沒想到,連 Page_Load 事件都還沒進去,且遺言也還沒交待清楚,畫面就已經死掉了。
原來,在 2011 年12月,於德國的 Chaos Communication Congress 會議中,有人展示了透過少量的 Http Request 就可以讓網頁站台變得很忙碌,沒多久就可以讓網站忙到無法再回應新的 Http Reguest 請求而達到阻斷服務攻擊(Denial of Service)的效果。
隨後,在
保哥的文章中找到一篇相關文章,於其技術摘要說明裡指出:
我們在開發 ASP.NET 網站時通常都會使用 Request.Form 物件來取得透過瀏覽器 POST 過來的資料,而此物件型別為 NameValueCollection 類別,該類別儲存 Key 的方式是透過雜湊運算的方式計算出來的 (hash-table data-structures),主要目的就是為了用極快的速度找到該 Key 的對應資料,不過此類別自行實做了有別於 .NET Framework 內建的雜湊演算法,它會將所有傳入的 Key 都先轉換為大寫,並使用名為 DJBX33X (Dan Bernstein's times 33, XOR) 的雜湊演算法進行計算,這將導致此演算法有機會遭到 Meet-in-the-middle 攻擊。
駭客能利用這個弱點實做出輕易可達成的 雜湊碰撞攻擊 (Hash collision attacks),此類攻擊可透過傳入大量的 POST 資料並且夾帶許多特別計算過的 Key 值,讓這些 Key 值在這些 Hash-table 中產生出相同的雜湊值,如此一來在這個 Hash-table 中就會出現許多擁有相同雜湊值的 Key,這便是「雜湊碰撞」的由來。而這類雜湊碰撞的情況正是 DJBX33X 演算法的致命傷,當一個 NameValueCollection 中存在著過多的「雜湊碰撞」就會導致電腦花上許多時間對該 Hash-table 進行運算,所以會讓 ASP.NET 執行緒花上數十分鐘到數小時的時間來操作相對應的 Key 值,如此一來便會耗盡網站伺服器的 CPU 資源,進而達到阻斷服務的目的。
就在 Chaos Communication Congress 會議之後,微軟很迅速的將這弱點進行了補強,也提供了 windows update 的服務,基本上,只要你的電腦有乖乖接受每個微軟的安全更新,理論上都已經可以避免如上所說的攻擊手法了,只是,微軟做了甚麼補強?
微軟開始重訂了一個遊戲規則。要求大家 Post 到後台的物件項目不可以超過 1000 個。包括以下:
1.<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
2.<input type="hidden" id="h_field" runat="server">
3.有已挑選值的 DropDownList (如果下拉清單裡面沒有任何資料,則不算)
4.有已挑選值的RadioButton(如果 RadioButton 裡面沒有任何被選取的資料,則不算)
5.有已挑選值的CheckBox(如果 CheckBox 裡面沒有任何被選取的資料,則不算)
6.有已挑選值的ListBox(如果 ListBox 裡面沒有任何被選取的資料,則不算)
自己詳細檢查了一下出錯的那一頁程式,上面的輸入控制項的確玲郎滿目啊!!
不過,剛開始對於微軟這種補強方法,還真的有點失落,心裡滴咕著,這算甚麼補強嘛,是補弱吧~那真的有需要使用到這麼多欄位需求時,難道得跟客戶說:
事實並非如此的。雖然微軟預設只提供上限 1000 ,但如果有更大的需求時,可以在 web.config 裡的 <appSettings> 加上 :
<add key="aspnet:MaxHttpCollectionKeys" value="2500" />
數值 value 可依實際你所想要允許的最大數量來決定。
Denial of Service 攻擊,的確是一種很難克服的難題。就算你的程式本身沒有問題,還是很有機會被攻擊,更何況被有心人士找到漏洞呢。相信日後這種攻擊手法,會越來越常見。這次微軟非常迅速的發佈更新,讓所有的 .Net 網站可以降低被攻擊的機率,真的值得讚賞。只是,我並沒有因此而得到特別的喜悅。因為我是接到來電說:「
paladin,快來看,你的系統當掉了!」。
參考:
01:
ASP.NET 發現重大資安弱點影響範圍涵蓋 ASP.NET 1.1 ~ 4.0
02:
具有大量表單金鑰、檔案或 JSON 裝載成員的 ASP.NET 請求失敗,並產生例外狀況
03:
ASP.NET Security Update Shipping Thursday, Dec 29th