最近做了一個免費發簡訊的小網站(http://freesms.cloudapp.net/),但發現最近有人破解了我的驗證碼,以每3秒/條的速度用我的簡訊服務來發他的廣告。更換驗證碼程式和過濾關鍵字只是治標不治本的方法,為了徹底阻止此類事件的發生,我們還是來看一下怎樣通過最佳化程式來實現。
其實同樣的程式除了防止別人濫發請求以外,還對預防拒絕服務(DoS)攻擊同樣適用哦。不妨來看看。
基本目標:限制同一IP訪問網站的頻率。比如,我們限制為每240分鐘來自同一IP的使用者最多隻能夠訪問首頁40次、其他頁面200次。
比如您現在可以開啟http://freesms.cloudapp.net/ 這個網站試一試,重新整理40次,就可以發現您在4小時內無法再次訪問到正確的網站內容了。
基本思想:
- 用HttpContext.Cache記錄訪問次數
- 將IP值與使用者訪問方式作為共同的Key,可以對使用者的不同訪問方式做不同的限制。
- 超出限額時調用Response.End()。
具體代碼:
一、 定義期間
在本例中,我們使用240分鐘作為一次限制的時間。
private const int DURATION = 240
二、定義訪問方式枚舉
針對不同的訪問方式進行不同的限制。在本例中,我們只區分兩種訪問方式:正常訪問與PostBack。在正常應用中,您還可以根據需要增加訪問不同頁面的限制。
public enum ActionTypeEnum { Normal=40, Postback=100 }
三、判斷邏輯
- 在某IP第一次採用某種訪問方式進行訪問時,增加Cache的Key=訪問方式+IP,返回True
- 如果Key已經存在,增加訪問次數,返回True
- 如果超出次數,返回False
public static bool IsValid(ActionTypeEnum actionType) { HttpContext context = HttpContext.Current; if (context.Request.Browser.Crawler) return false; string key = actionType.ToString() + context.Request.UserHostAddress; int hit = (Int32)(context.Cache[key] ?? 0); if (hit > (Int32)actionType) return false; else hit++; if (hit == 1) { context.Cache.Add(key, hit, null, DateTime.Now.AddMinutes(DURATION), System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.Normal, null); } else { context.Cache[key] = hit; } return true; }
四、在頁面中調用
判斷函數需要在頁面的OnInit方法中調用。在這裡需要使用一些自己定義的邏輯,來進行不同訪問方式的判斷。下面的例子是一個最簡單的,只區分正常訪問與Postback。
protected override void OnInit(EventArgs e){ base.OnInit(e); if (!IsPostBack) { if (!ActionValidator.IsValid(ActionValidator.ActionTypeEnum.Normal)) { Response.Write("您發送得太頻繁,被系統判斷為廣告。廣告或其他定製業務請聯絡郵箱admin@cloudera.cn,謝謝。- http://freesms.cloudapp.net"); Response.End(); } } else { if (!ActionValidator.IsValid(ActionValidator.ActionTypeEnum.Postback)) { Response.Write("您發送得太頻繁,被系統判斷為廣告。廣告或其他定製業務請聯絡郵箱admin@cloudera.cn,謝謝。- http://freesms.cloudapp.net"); Response.End(); } }}
PS: 敵人總是狡詐的 ,後來我又發現那個人通過使用代理來變換IP ,繼續通過我的服務發送廣告。這就要繼續最佳化程式了,比如把廣告內容的md5也作為key記錄下來。也許您也一樣,需要面對各種各樣的“敵情”。呵呵,希望本文對您有所協助!