When your use forms on your website, spammers will very soon be trying to inform your visitors about their "great" products. In this post I will show you how to protect your website by using a simple timestamp.
There are several possibilities to fight against spam:
- Check the referrer to ensure the request comes from the correct origin. This only works in few cases, since spammers often supply cookies and the correct referrer.
- You could use captchas. The disadvantage is, that many captchas are broken by spammers and your users have to decipher them, which is quite difficult sometimes.
But spammers have one problem: Since they want to spam as many websites as possible, they submit a form after only a few milliseconds. Humans however need at least a few seconds to fill a form before they submit it.
Implementation
To check if a request is performed by a human, we use a hidden field containing a timestamp. We use the following extension method of HtmlHelper to generate the timestamp:
public static class SpamProtectionExtensions { public static string SpamProtectionTimeStamp(this HtmlHelper helper) { var builder = new TagBuilder("input"); builder.MergeAttribute("id", "SpamProtectionTimeStamp"); builder.MergeAttribute("name", "SpamProtectionTimeStamp"); builder.MergeAttribute("type", "hidden"); builder.MergeAttribute("value", ((long)(DateTime.Now - new DateTime(1970, 1, 1)).TotalSeconds).ToString()); return builder.ToString(TagRenderMode.SelfClosing); } }
To validate the timestamp we use the following FilterAttribute:
public class SpamProtectionAttribute : FilterAttribute, IAuthorizationFilter { public void OnAuthorization(AuthorizationContext filterContext) { long timestamp = long.MaxValue;if (Int64.TryParse(filterContext.RequestContext.HttpContext.Request.Params["SpamProtectionTimeStamp"], out timestamp)) { long currentTime = (long)(DateTime.Now - new DateTime(1970, 1, 1)).TotalSeconds; if (currentTime <= timestamp + 1) { throw new HttpException("Invalid form submission. At least one seconds have to pass before form submission."); } } else { throw new HttpException("Invalid form submission. Invalid timestamp parameter."); }
} }
Usage
Usage is very similar to the AntiForgeryToken:
<% using (Html.BeginForm()) { %> <%= Html.TextBox("comment")%><%= Html.SpamProtectionTimeStamp() %> <input type="submit" value="Submit" />
<% } %>
Now decorate your controller action handling the postback with the SpamProtectionAttribute:
[SpamProtection()] [AcceptVerbs(HttpVerbs.Post)] public virtual ActionResult Entry(string comment) { // Your form handling }
Downloads
In my blog post 'ASP.NET MVC - Developing a custom blog engine' you'll find a project for download where the SpamProtectionAttribute is used to protect blog comments against spam.