Simple method to avoid comment spam

by Mads Kristensen 8. November 2006 15:05

We probably all know about the annoying captcha images that a lot of blogs uses for separating humans from machines (spam robots). I use a captcha image to avoid comment spam on this blog because I get a lot, but I really don’t like to use it. I don’t like the fact that it makes is more difficult for my visitors to write comments, which is my only way of measuring the quality of the individual posts.

What I want is an invisible unobtrusive captcha method that automatically makes sure the user is human. So I wrote a simple method that does just that. It works by adding a small JavaScript to the page that adds a hidden form field when the form is submitted. The value of the hidden field must be the same as a server-side variable to validate. There must also be a property that returns a Boolean value that indicates whether or not the user is human.

/// <summary>

/// Initializes the captcha and registers the JavaScript

/// </summary>

private void InititializeCaptcha()

{

  if (ViewState["captchavalue"] == null)

  {

    ViewState["captchavalue"] = Guid.NewGuid().ToString();

  }

 

  System.Text.StringBuilder sb = new System.Text.StringBuilder();

  sb.AppendLine("function SetCaptcha(){");

  sb.AppendLine("var form = document.getElementById('" + Page.Form.ClientID + "');");

  sb.AppendLine("var el = document.createElement('input');");

  sb.AppendLine("el.type = 'hidden';");

  sb.AppendLine("el.name = 'captcha';");

  sb.AppendLine("el.value = '" + ViewState["captchavalue"] + "';");

  sb.AppendLine("form.appendChild(el);}");

 

  Page.ClientScript.RegisterClientScriptBlock(GetType(), "captchascript", sb.ToString(), true);

  Page.ClientScript.RegisterOnSubmitStatement(GetType(), "captchayo", "SetCaptcha()");

}

 

/// <summary>

/// Gets whether or not the user is human

/// </summary>

private bool IsCaptchaValid

{

  get

  {

    if (ViewState["captchavalue"] != null)

    {

      return Request.Form["captcha"] == ViewState["captchavalue"].ToString();

    }

 

    return false;

  }
}

Examples of use

To use the captcha you have to call InitializeCaptcha from the Page_Load handler. Then just check the IsCaptchaValid property before you save the comment.

protected void Page_Load(object sender, EventArgs e)

{

  InititializeCaptcha();

}

 

/// <summary>

/// Handles the submit buttons onclick event

/// </summary>

void btnSave_Click(object sender, EventArgs e)

{

  if (IsCaptchaValid)

  {

    SaveComment();

  }
}

* Only $4.95/month ASP.NET & Windows 2008 + IIS 7 Hosting! FREE SQL Included

Tags:

ASP.NET | Security

Comments

11/8/2006 11:05:45 PM #

 Chris

Wow!

Chris |

11/9/2006 12:30:42 AM #

 Johnny Thawte

The only thing this doesn't prevent is manual comment spam, which I've gotten a lot of. There's a Wordpress plugin that does something similar to what you are doing here, but then you still end up getting manual spam, which can still be pretty nasty.

Any ideas on how to stop that? Obviously CAPTCHA doesn't work for that either.

Johnny Thawte |

11/9/2006 12:32:01 AM #

 Johnny Thawte

Ack. I didn't realize the email address was a public field.

Johnny Thawte |

11/9/2006 12:57:38 AM #

 Martin Knotek

And what with positive bots?

Example of error in Ajax antispa:
gritechnologies.com/.../NoBot.aspx ?

Martin Knotek |

11/9/2006 1:28:45 AM #

 spam blocker

great!


if any want join to the war against spam
please visit this site - http://www.spam-blocker.biz and please tell what are you thinking about this idea.

spam blocker |

11/9/2006 7:41:03 AM #

 Andrew

I suppose it stops all those pesky non-javascript users from contributing too!

What happens if someone writes an app that drives IE to sites, then comments? Wouldn't it have JS enabled and pass your tests?

Andrew |

11/9/2006 8:08:54 AM #

Mads Kristensen

Andrew, I think the tradeoff between non-javascript users and spammers are very simple. Almost anybody has enabled JavaScript and the ones who hasn't are aware of it and know they are excluded from a lot of functionality on many many websites. But that's more of a personal choice. This is my opinion on the non-javascript users subject.

Regarding your question about an app that uses IE to submit comments. That scenario will validate the captcha and allow the spammer to submit comments. Luckily for us, spammers don't use that approach that much. It is very time consuming compared to automated post request hammering different servers. But I guess that only time will tell. They get smarter too.

Mads Kristensen |

11/9/2006 3:43:39 PM #

 Mike

Mads,

If I understand this correctly, this works because the spam bots don't render the page in a browser and so don't run javascript. Is this correct?

Mike |

11/9/2006 6:58:40 PM #

Steve Harman

Interesting... but it does kinda leave out anyone running with Javascript disabled. Check out the InvisibleCaptchaValidator control that we built for Subtext [http://subtextproject.com]. It works both with and without Javascript (tho it's not invisible if you don't have Javascript enabled).

Anyhow, here is Phil's write up on the control:
haacked.com/.../..._CAPTCHA_Validator_Control.aspx

Steve Harman |

3/17/2007 7:23:06 AM #

 John K

Interesting idea. I think your solution is a good one.  As for worrying about people who disable Javascript, well - I understand the concern, but you just can't win every battle. I mean, if you're surfing the web and have your Javascript disabled then you should be prepared to have lots of problems with sites!

John K |

3/17/2007 2:30:01 PM #

 jc

Shouldnt be a problem to add a degrading approach so if javascript is disabled, just default to a regular captcha.

I like the idea of using viewstate to populate the captcha. I think an even cooler approach would be to set a session variable to a GUID, and use AJAX to call into the server to populate the hidden captcha field on mouseclick of the submit.

jc |

6/13/2007 8:58:02 PM #

mcgurk

Am I missing something?  What your page is doing is hidden in plain sight.  Seems like a bot could be made to circumvent this by viewing the page source.

mcgurk United States |

6/13/2007 11:10:48 PM #

Mads Kristensen

mcgurk, you are right that the robots could look for the hidden input field named "captcha". Chances are they don't, but to be sure, you can just give it a random generated name that you store in viewstate. A GUID maybe.

Mads Kristensen Denmark |

6/15/2007 12:52:33 PM #

hartvig

Requirering javascript enabled is indeed a tradeoff when it comes to accessbility where many people need to have javascript disabled and not because they're lynx or security fanatics. I like the idea and think it would be rock solid with the visible (annoying) captcha fall-back solution. In respect of accessbility this adds additional worries, that blind people wouldn't stand a chance which is why more and more captcha solutions offers audible captcah as well.

hartvig Denmark |

8/14/2007 1:31:42 AM #

Rob

Brilliant.

Rob |

8/14/2007 1:35:42 AM #

trackback

Trackback from Driebier.net

To Captcha or not to Captcha..

Driebier.net |

9/29/2007 8:53:17 PM #

Rob van der Veer

I found a little bug in your code.

When you use this code on a page that has validators, and the validation fails once or twice (or whatever many times), the jscript will add more and more hidden fields with the GUID. This is because the SetCaptcha jscript function will be placed in front of the ClientValidate method in the submit body.

When you call IsCaptchaValid on the server side, the Request.Forms property will contain the GUID multiple times (like "<Guid>,<Guid>") and the validation will fail.

I found 2 solutions: 1) Adjust the javascript to not add another hidden field when one already exists, or 2) Patch the IsCaptchaValid() function to detect multiple post attempts (that is, split the Request.Forms value).

Rob van der Veer |

12/3/2007 2:41:12 AM #

Anthony Grace

Hi Mads,

Do you have a solution for the problem Rob found?

Anthony Smile

Anthony Grace United States |

12/31/2007 4:10:12 PM #

Stilgar

well Anthony as Rob suggests just truncate the string in IsCaptchaValid

if(Request.Form["captcha"] == null || Request.Form["captcha"].Length <= Guid.Empty.ToString().Length) //which is 36
{
   return null;
}

return Request.Form["captcha"].Substring(0,36) == ViewState["captchavalue"].ToString();

instead of

return Request.Form["captcha"] == ViewState["captchavalue"].ToString();

Stilgar Bulgaria |

4/17/2008 8:07:34 PM #

kunal

hello sir,
i get following error when i use ur latest updation to the code.
plz update me.
thanks


Compilation Error
Description: An error occurred during the compilation of a resource required to service this request. Please review the following specific error details and modify your source code appropriately.

Compiler Error Message: CS0127: Since 'registeruser.InititializeCaptcha()' returns void, a return keyword must not be followed by an object expression

Source Error:



Line 80:             if (Request.Form["captcha"] == null || Request.Form["captcha"].Length <= Guid.Empty.ToString().Length) //which is 36
Line 81:             {
Line 82:                 return null;
Line 83:             }


kunal India |

4/17/2008 8:54:43 PM #

kunal

plz post full functional code.
what if  someone checks in .cs file whether the username(a fileld in databse column) exists in the database or not(which means server round trips or page post back) in the signup page while using ur capthca code?

with regards,
kunal

kunal India |

6/20/2008 10:52:07 AM #

trackback

Trackback from Dave Burke

Spam and BlogEngine.NET - Nadda, Nope, Nothin

Dave Burke |

7/4/2008 7:20:21 AM #

a

asdasd

a Brazil |

1/30/2009 3:50:54 PM #

trackback

Implementing a naive captcha in BlogEngine.NET

Implementing a naive captcha in BlogEngine.NET

Code Optimism |

2/2/2010 10:56:53 PM #

trackback

Controlling the Influx of SPAM on BlogEngine.NET

Controlling the Influx of SPAM on BlogEngine.NET

Al Bsharah |

Comments are closed

About the slave

Mads Kristensen Mads Kristensen
Web developer at ZYB and founder of BlogEngine.NET. More...

LinkedIn ZYB Facebook Last.fm Twitter View Mads Kristensen's profile on Technorati

The Lounge

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2008