Preventing Spam With An ASP.NET CAPTCHA Control
The source and dll for the project can be downloaded here: CaptchaControl.zip About A CAPTCHA image displays text that is readable to humans, but not to computers. The concept is useful because it provides a means to filter out automated programs while allowing real users to pass through. Bots for example, which spam comments on weblogs and other dynamic websites, are a fairly pervasive problem and even a regularly new and low traffic blog like this was getting dozens of spam comments every day. CAPTCHA is a means to stop them while still allowing real users to post.CaptchaControl is an ASP.NET server control that is designed to start working by just being dropping onto the page, without any modification. This version is based off Michael Trefry’s implementation, which is in turn based off Dan Burke’s. My update fixes a couple of issues around storing the code in a browser cookie and adds features like client validation. CatchaControl OverviewThe CaptchaControl class is a composite control and encapsulates the CAPTCHA image, a textbox for capturing the result and a validator for verifying the correct code was entered. It handles hooking all the controls together, pointing the image src towards the image handler and maintaining the state of the code, which is stored encrypted in a hidden form field and then decrypted on postback.
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
RegenerateCode();
Page.ClientScript.RegisterHiddenField(ClientID + "__hidden", _encryptedCode);
Page.RegisterRequiresPostBack(this);
SetChildProperties();
}
bool IPostBackDataHandler.LoadPostData(string postDataKey, NameValueCollection postCollection)
{
_encryptedCode = postCollection[ClientID + "__hidden"];
_code = Encryptor.Decrypt(_encryptedCode, GetKey(), GetIV());
return true;
}
CaptchaControl has a number of properties for modifying its behavior such as the text of the error message, whether to display for authenticated users and whether the code should be validated on the client with JavaScript (note that the unencrypted code will be included with the page if this is enabled). It also an optional LayoutTemplate property of ITemplate that allows the encapsulated controls layout to be customized.Generating the CAPTCHA ImageThe CAPTCHA image is generated by CaptchaHandler, a HttpModule. Parameters in the querystring, including the encrypted code data, are passed to a class than handles generating the image, which is then rendered to the response.
void IHttpHandler.ProcessRequest(HttpContext context)
{
HttpRequest request = context.Request;
HttpResponse response = context.Response;
string encryptedCode = request.QueryString["code"];
string code = Encryptor.Decrypt(encryptedCode, CaptchaControl.GetKey(), CaptchaControl.GetIV());
int width = Convert.ToInt32(request.QueryString["width"]);
int height = Convert.ToInt32(request.QueryString["height"]);
CaptchaImageGenerator captchaImage = new CaptchaImageGenerator(code, width, height);
response.Clear();
response.ContentType = "img/jpeg";
response.Cache.SetCacheability(HttpCacheability.NoCache);
captchaImage.RenderImage(response.OutputStream);
}
UsageRegister the CaptchaHandler by adding the following to your web.config’s httpModule element.
<addverb="*"path="captchahandler.axd"type="Newtonsoft.CaptchaControl.CaptchaHandler, Newtonsoft.CaptchaControl"/>
To add the CaptchaControl to a page simply place it where you want it to be displayed:
<%@ Register TagPrefix="ncc" Namespace="Newtonsoft.CaptchaControl" Assembly="Newtonsoft.CaptchaControl" %>
<ncc:CaptchaControl runat="server" ID="CaptchaControl" />
The IsValid property on the page will automatically be set when the page’s validators, including CaptchaControl, are evaluated on postback.
private void btnSubmit_Click(object sender, EventArgs e)
{
if (IsValid)
{
// logic
}
}
The important question: Does it work? Since adding CAPTCHA validation to this blog comment spam has dropped from dozens each day to zero.The source and dll for the project can be downloaded here: CaptchaControl.zip