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