Do we really need CAPTCHA's to prevent robots posting to our web forms? Not if you run ASP.NET 2.0. Whether you use a form for member logins, blog comments or a web shop you want to keep it as secure and tamper proof as possible. Brute force attacks on a login form performed by robots or spammers on the blog comments are scenarios you can avoid by leveraging existing ASP.NET 2.0 features.

Event validation

Event validation makes sure that a postback comes from a control on the page and not a direct POST request sent by an application (read robot).

ASP.NET has event validation turned on by default, but many people turn it off for various reasons. One reason is that their web application registers exceptions caused by the event validation. So does mine, but that is when an unauthorized post request is performed. Don’t turn it off.

ViewstateMAC

When ViewStateMAC is enabled it encrypts the ViewState so it cannot be tampered with by evil doers. ViewStateMAC is not enabled by default, so you have to do it in web.config manually like so:

<pages enableViewStateMac="true" />

When enabling ViewStateMAC you must also add a machine key to the web.config so that all the servers in a webfarm use the same encryption and decryption key. Otherwise you can end up with invalid ViewState. Here is an example on such a machine key.

<machineKey validationKey="D9F7287EFDE8DF4CAFF79011D5308643D8F62AE10CDF30DAB640B7399
BF6C57B0269D60A23FBCCC736FC2487ED695512BA95044DE4C58DC02C2BA0C4A266454C"
      decryptionKey="BDAAF7E00B69BA47B37EEAC328929A06A6647D4C89FED3A7D5C52B12B23680F4"
      validation="SHA1" decryption="AES"
    />

You can take it a step further and add a user key to the ViewState. That locks the ViewState to a single user and makes it even harder to tamper with. Read more on the user key here.

All the rest

These are two build-in technologies that can be used, but you still have to do your custom form field validation etc. No CAPTCHA is needed when using these two techniques. All it requires is that you use a <form runat="server"> and the standard postback feature of ASP.NET to post the form. If you don't believe me, try it out. It does eliminate the use of CAPTCHA's.

Update: It is now possible to write extensions that alters the text of the individual posts by using the Post.Serving event. Also on comments using Post.CommentServing

Last week BlogEngine.NET 1.1 was released, but we are already well on the way to version 1.2, which amongst other things will include a unified extension model.

An extension allows you to write a class that can hook up to all the various events that are exposed in the application in a very simple manor. I’ve written a simple extension that stops other websites from bandwidth leeching by referencing your images directly. You can download the complete source code at the bottom of the post.

Step 1

To transform a class to an extension, all you have to do is to decorate the class definition with an attribute called Extension like so:

[Extension("Stops other websites in displaying your images on their own website")]
public class StopLeechers

The Extension attribute must be fed with a description of the extension you are writing. That’s how we can provide a user interface that lists all extensions nicely with name and description.

Step 2

Secondly, there must be a default constructor – one without parameters. That constructor will be called when the web application starts, so it’s here we will hook into the events of BlogEngine.NET. Here is how it looks in the StopLeechers extension class:

public StopLeechers()
{
  ImageHandler.BeforeServing += new EventHandler<ImageHandler.FileHandlerEventArgs>(StopReferrers);
}

Notice that it makes use of the ImageHandler’s BeforeServing event. The ImageHandler is used to serve images that you’ve uploaded and inserted to your blog posts.

Step 3

Now the event is hooked and we can write the StopReferrers event handler. The event handler will look at the referring URL and determine if it comes from the blog itself or another website. If another website references the image, we will terminate the response and send the HTTP status code 403 Access Denied.

void StopReferrers(object sender, ImageHandler.FileHandlerEventArgs e)
{
  HttpContext context = HttpContext.Current;
  if (context.Request.UrlReferrer != null)
  {
    if (context.Request.UrlReferrer.Host != context.Request.Url.Host)
    {
      context.Response.StatusCode = 403;
      context.Response.End();
    }
  }
}

Step 4

The last thing you need to do is to drop the file into the App_Code folder. From the moment the file is dropped, the extension activates.

Other events

As mentioned, you can hook your extension up to all the events present in BlogEngine.NET, not just the ImageHandler’s. Here is a list of the events you can use.

  • ImageHandler.BeforeServing
  • ImageHandler.ImageServing
  • ImageHandler.BadRequest
  • FileHandler.BeforeServing
  • FileHandler.FileServing
  • FileHandler.BadRequest
  • Post.Saved
  • Post.Rated
  • Post.BeforeAddingComment
  • Post.CommentAdded
  • Post.BeforeRemovingComment
  • Post.CommentRemoved
  • Post.Serving - NEW!
  • Post.CommentServing - NEW!
  • Page.Saved
  • BlogSettings.Changed
  • CategoryDictionary.Saved

We are adding more before the next release. Especially, we will add events that allow you to change the output of a post. That means that you can do string manipulation and other things to the actual post before it get served to the response stream.

If you can’t wait for the 1.2 release, then get the latest source code from CodePlex. Remember that this is not released yet, so it can be subject to change, but I don’t expect it to.

StopLeechers.cs (741,00 bytes)