Source code location: ./view_state_spam/viewstatespamstopper.cs
using System; using System.Collections.Specialized; using System.IO; using System.Web; using System.Web.Caching; namespace AspNetResources.Web { public class ViewStateSpamStopper : IHttpModule { private const string banModuleCacheKey = "ViewStateFendOff:IpBanList"; private const string banListFile = "ban_list.txt"; // -------------------------------------------------------------------------- public void Init(HttpApplication application) { application.Error += new EventHandler(this.Error); application.BeginRequest += new EventHandler(BeginRequest); application.EndRequest += new EventHandler(this.EndRequest); } // -------------------------------------------------------------------------- private void BeginRequest(object sender, EventArgs e) { HttpApplication app = ((HttpApplication)sender); HttpContext context = app.Context; string ip = context.Request.UserHostAddress; if (!GetBanList (context).Contains (ip)) return; AbortRequestFromBannedIp (context); } // -------------------------------------------------------------------------- private void Error(object sender, EventArgs e) { HttpApplication app = (HttpApplication) sender; HttpContext context = app.Context; /* There are numerous ways to screw up view state, but it should always be Base64-encoded. Spammers try to plug emails into view state in plain text, and we can look for '@' since it's not allowed in Base64. It's a smoke test, but it should serve its purpose well. We'll try to extract view state from the Form collection and see what we're dealing with. The exception we receive here is too generic to tell. */ string viewState = context.Request.Form ["__VIEWSTATE"]; if (viewState == null || viewState.Length == 0) return; if (HttpUtility.HtmlDecode (viewState).IndexOf ('@') == -1) return; app.Context.Server.ClearError(); /* Blacklist these sons of bitches */ AddIpToBanList (context); AbortRequestFromBannedIp (context); } // -------------------------------------------------------------------------- private void EndRequest(object sender, EventArgs e) { HttpApplication app = (HttpApplication) sender; HttpContext context = app.Context; HttpResponse response = context.Response; if (!context.Items.Contains("BanCurrentRequest")) return; response.ClearContent(); response.SuppressContent = true; response.StatusCode = 403; response.StatusDescription = "Access denied: your IP has been banned. Don't push your luck spamming me."; } // -------------------------------------------------------------------------- private StringCollection GetBanList (HttpContext context) { StringCollection ips = context.Cache [banModuleCacheKey] as StringCollection; if (ips == null) { ips = new StringCollection(); string path = GetBanListPath (context); if (File.Exists(path)) { using (StreamReader sr = File.OpenText (GetBanListPath (context))) { string s = ""; while ((s = sr.ReadLine()) != null) { /* In case someone edits the file by hand and introduces empty strings. */ if (s.Trim().Length > 0) ips.Add(s); } } } CacheDependency cd1 = new CacheDependency (path); context.Cache.Insert (banModuleCacheKey, ips, cd1); } return ips; } // -------------------------------------------------------------------------- private void AddIpToBanList (HttpContext context) { string ip = context.Request.UserHostAddress; if (GetBanList (context).Contains(ip)) return; using (StreamWriter sw = File.AppendText (GetBanListPath (context))) { sw.WriteLine (ip); } } // -------------------------------------------------------------------------- private static void AbortRequestFromBannedIp (HttpContext context) { context.Items ["BanCurrentRequest"] = true; context.ApplicationInstance.CompleteRequest(); } // -------------------------------------------------------------------------- private string GetBanListPath (HttpContext context) { return Path.Combine (context.Server.MapPath (context.Request.ApplicationPath), banListFile); } // -------------------------------------------------------------------------- public void Dispose() {} } }
Copyright © 2004-2006, Milan Negovan. All rights reserved. | License
Back to AspNetResources.com