詳解ASP.NET中Membership表和阻止DOS攻擊
無需關閉站點的情況下如何查詢ASP.NET 2.0 Membership表
這種查詢會爽快的運行在你的開發環境中:
|
或者在無需任何問題的情況下獲得一些用戶的 profile :
|
甚至你可以像這樣在aspnet_membership表中輕松的更新用戶的郵件地址:
|
但是當在你的產品服務器上有一個巨大的數據庫時,運行這些腳本都會搞垮你的服務器。理由就是,雖然這些查詢看起來明顯是你經常使用的語句,但是這些語句沒有任何索引。因此,上面所有在"Table Scan"中的結果(很糟糕的查詢方式)都會響應數百萬行記錄。
這里的現象對我們而言意味著什么。我們使用了這些字段諸如UserName, Email, UserID, IsAnonymous等。關于Pageflakes的很多市場報表。這些報表中的一些僅僅市場部可以使用,其他人都不可以使用它。現在,站點運行得很好,但是市場部一天當中會使用它很多次而且用戶常常打電話告訴我們網站太慢了,”用戶報告網站性能十分地慢!”,一些頁面甚至還發生超時等現象。
常常,當他們打電話個給我們的時候,我們就會告訴他們“稍等,馬上檢查”,然后我們開始對整個網站進行檢查。我們使用SQL profiler工具來查看到底那里出錯了。但是我們不能找到任何問題。Profiler顯示了查詢運行的摁件。CPU負載位于適當的參數范圍內。站點運行得很好,很流暢。我們打電話給他們,“我們不能查到任何問題,到底怎么了?”。
因此,當我們試圖調查這個問題并且在我們沒有調查時,發現站點真的變得很慢的時候,為什么我們不能看到它變慢的任何問題?
市場部有時候每天需要很多次運行一些分析報表來查詢數據。無論什么時候他們執行這些查詢,當這些字段都是不是索引時,它會使得服務器的IO吞吐量更高以及CPU的使用率增高:
我們使用了15000 RPM的SCSI驅動器,雖然很貴,但是運行速度很快。CPU是雙核Dual Xeon 64位的。盡管有這些強大的硬件支持,但是由于這個巨大的數據庫在執行查詢時仍然把我們壓倒了。
但是當市場部給我們打電話時,這些問題從來沒發生過,并且我們沒有掛斷電話并試圖找出問題所在。因為當他們打電話給我們時,會跟我們交談,他們沒有運行使服務器垮掉的任何報表。讓他們停留在了站點上的其它地方,幾乎做了和用戶一樣的事情.
咱們看看如下索引:
表: aspnet_users
◆簇索引 = ApplicationID, LoweredUserName
◆非簇索引 = ApplicationID, LastActivityDate
◆主鍵 = UserID
表: aspnet_membership
◆簇索引 = ApplicationID, LoweredEmail
◆非簇索引= UserID
表: aspnet_Profile
◆簇索引 = UserID
大部分索引都有ApplicationID在其中。除非你放置ApplicationID='…'在WHERE從句中,此時它就不會使用任何索引。結果,所有的查詢會進行全表掃描。僅僅是把ApplicationID放在where從句中(從aspnet_Application表中找到你的ApplicationID)所有的查詢就會變得非常快。
不要在WHERE從句中使用Email或者UserName。他們不是索引的一部分,從而取代LoweredUserName和LoweredEmail字段。所有的查詢必須在WHERE從句中有ApplicationID。
我們的管理站點上包涵了很多這種報表并且每個報表都包涵了很多這種在表aspnet_users、 aspnet_membership 和aspnet_Profile上的查詢。結果,當市場部試圖產生報表時,它們會占用所有CPU、HDD的資源,最終導致站點變得非常慢甚至毫無響應。
確保你總是檢查了所有的WHERE和JOIN從句。否則當你的網站上線時會出現大問題。
阻止決絕服務(DOS)攻擊
對黑客而言,Web服務是最容被襲擊的目標,因為甚至一個入門級的黑客都可以通過重復調用一個代價昂貴的Web服務來使服務器死掉。像Pageflakes這樣以Ajax技術構建的頁面并將其作為起始頁的站點將是DOS攻擊的最大目標,因為如果你僅僅是在無需保存cookie的情況下重復地訪問主頁,這樣每次點擊都會產生一個新的用戶、新的頁面配置、新的widgets等。第一次訪問是花費代價最昂貴的一次。
可是這也是最容易暴露并搞垮站點的一次機會。你可以自己試試這種方式,僅僅需要如下一段簡單的代碼即可:
|
令你感到吃驚的是,你會注意到,在進行兩次調用之后,你不會得到一個有效的響應。這并不是說你已經成功地將服務器搞垮了。而是因為你的請求被決絕了。你可能會樂意你不再獲得任何服務了,因此你達到了決絕服務(你自己)的目的。我們很高興決絕了你的服務(DYOS)。
我提出的這種簡便技巧就是記住從某個特殊IP地址發來的請求。當請求的數量超過閥門值時,便決絕后續發來的請求。這個辦法是在ASP.NET緩存中記住調用者的IP并為每個IP維護一個計數的請求。當該計數值超過了預定義的限定值時,決絕一段時期后的發來的請求,比如10分鐘。10分鐘后,再次允許來自那個IP的請求。
我有一個名為ActionValidator的類,該類包涵了一些具體的活動諸如首次訪問、再次訪問、異步回傳、添加新的widget、添加新的頁面等等。檢查這種指定活動的計數值是否指向了一個IP閥門值。
|
該枚舉包涵了活動的類型以便用來在某個持續的時間――10分鐘檢查它們的閥門值。
使用 一個名為IsValid的static方法用來進行檢查。如果請求限制沒有通過,則返回true。如果請求需要被決絕,則返回false。一旦你獲得false,你就可以調用Request.End ()方法并阻止ASP.NET進行未來的處理。你可以切換顯示了“Congratulations! You have succeeded in Denial of Service Attack.”的頁面。
|
內置的緩存鍵將活動類型和客戶端IP地址進行了合并。首先它檢查是否有針對活動的任何入口和存儲于緩存中的客戶端IP。如果沒有,開始計數并記住指定持續時間內緩存中的IP。緩存項中的絕對期滿日期確保緩存項在持續一段時間后能夠被清除并重新計算。當在緩存中已經存在一個入口時,獲得最后的點擊數,并檢查是否超越了該限制。如果沒有超過,則增加計數器。
不需要通過Cache[url]=hit的方式存儲更新后的值到緩存中;因為點擊對象是一個引用對象,改變它意味著在緩存中它也要改變。事實上,如果你再次將它放入緩存中,緩存期滿計數器將重新開始并在指定持續時期后導致失敗邏輯重新計算。
用法十分簡單, default.Aspx頁面上的代碼如下:
protected override void OnInit(EventArgs e)
{
base.OnInit(e);// Check if revisit is valid or not
if( !base.IsPostBack )
{
// Block cookie less visit attempts
if( Profile.IsFirstVisit )
{
if( !ActionValidator.IsValid(ActionValidator.ActionTypeEnum.FirstVisit))
Response.End();
}
else
{
if( !ActionValidator.IsValid(ActionValidator.ActionTypeEnum.ReVisit) )
Response.End();
}
}
else
{
// Limit number of postbacks
if( !ActionValidator.IsValid(ActionValidator.ActionTypeEnum.Postback) )
Response.End();
}
}
這里我對具體的場景如訪問、再次訪問、回發等進行檢查。
當然你可以通過放置一些Cisco的防火墻來阻止DOS攻擊。這樣你就可以避免主機提供商的整個網絡不會因為受到DOS或者DDOS攻擊的影響。這些所能保證的只是網絡級別的攻擊,諸如TCP SYN攻擊、奇怪的數據報文分組等。在沒有cookie或者試圖加載太多widgets的情況下, 他們沒有辦法能夠分析這些報文并找出一個特殊的IP來試圖多次加載站點。這些都被稱為應用程序級別的DOS攻擊,硬件不能對其進行阻止。這些必須在你自己的代碼中進行實現處理。
現在幾乎很少有站點采用這種預防措施來防止遭受這種應用程序級別的DOS攻擊。因此可以非常容易地編寫一些簡單的代碼從寬帶連接中通過持續點擊站點上這些耗費昂貴的頁面或者進行Web服務調用來使得服務器崩潰。我希望這對你來說只是一個小問題,并可以采用這種有效的方式幫助你阻止自己Web應用程序遭受DOS攻擊。
小結
你已經學到了很多技巧來應付在具有相同硬件配置的機器上使得ASP.NET的性能發揮到極致。你也學到了如何使用一些AJAX技術來使得你的站點加載更快更流暢。最后,你學到了如何防御站點因高點擊量所帶來的風險以及擴展靜態內容跨過內容傳輸網絡來抵御站點高峰期引起的阻塞。所有這些技術都可以使你的站點加載速度更快,運行得更流暢,以及以更低的成本獲得更高的負載量。
【編輯推薦】