Lightweight Invisible CAPTCHA Validator Control

Source: http://www.dpchallenge.com/image.php?IMAGE_ID=138743 Not too long ago I wrote about using heuristics to fight comment spam.  A little later I pointed to the NoBot control as an independent implementation of the ideas I mentioned using Atlas.

I think that control is a great start, but it does suffer from a few minor issues that prevent me from using it immediately.

  1. It requires Atlas and Atlas is pretty heavyweight.
  2. Atlas is pre-release right now.
  3. We’re waiting on a bug fix in Atlas to be implemented.
  4. It is not accessible as it doesn’t work if javascript is enabled.

Let me elaborate on the first point.  In order to get the NoBot control working, a developer needs to add a reference to two separate assemblies, Atlas and the Atlas Control Toolkit, as well as make a few changes to Web.config.  Some developers will simply want a control they can simply drop in their project and start using right away.

I wanted a control that meets the following requirements.

  1. Easy to use. Only one assembly to reference.
  2. Is invisible.
  3. Works when javascript is disabled.

The result is the InvisibleCaptcha control which is a validation control (inherits from BaseValidator)so it can be used just like any other validator, only this validator is invisible and should not have the ControlToValidate property set.  The way it works is that it renders some javascript to perform a really simple calculation and write the answer into a hidden text field using javascript.

What!  Javascript?  What about accessibility!? Calm down now, I’ll get to that.

When the user submits the form, we take the submitted value from the hidden form field, combine it with a secret salt value, and then hash the whole thing together.  We then compare this value with the hash of the expected answer, which is stored in a hidden form field base64 encoded.

The whole idea is that most comment bots currently don’t have the ability to evaluate javascript and thus will not be able to submit the form correctly.  Users with javascript enabled browsers have nothing to worry about.

So what happens if javascript is disabled?

If javascript is disabled, then we render out the question as text alongside a visible text field, thus giving users reading your site via non-javascript browsers (think Lynx or those text-to-speech browsers for the blind) a chance to comment.

Accessible version of the Invisible CAPTCHA control

This should be sufficient to block a lot of comment spam.

Quick Aside: As Atwood tells me, the idea that CAPTCHA has to be really strong is a big fallacy.  His blog simply asks you to type in orange every time and it blocks 99.9% of his comment spam.

I agree with Jeff on this point when it comes to websites and blogs with small audiences. Websites and blogs tend to implement different CAPTCHA systems from one to another and beating each one brings diminishing margins of returns.

However, for a site with a huge audience like Yahoo! or Hotmail, I think strong CAPTCHA is absolutely necessary as it is a central place for spammers to target.  (By the way, remind me to write a bot to post comment spam on Jeff’s blog)

If you do not care for accessibility, you can turn off the rendered form so that only javascript enabled browsers can post comments by setting the Accessible property to false.

I developed this control as part of the Subtext.Web.Control.dll assembly which is part of the Subtext project, thus you can grab this assembly from our Subversion repository.

To make things easier, I am also providing a link to a zip file that contains the assembly as well as the source code for the control. You can choose to either reference the assembly in order to get started right away, or choose to add the source code file and the javascript file (make sure to mark it as an embedded resource) to your own project.

Please not that if you add this control to your own assembly, you will need to add the following assembly level WebResource attribute in order to get the web resource handler working.

[assembly: WebResource("YourNameSpace.InvisibleCaptcha.js", 
    "text/javascript")]

You will also need to find the call to Page.ClientScript.GetWebResourceUrl inside InvisibleCaptcha.cs and change it to match the namespace specified in the WebResource attribute.

If you look at the code, you’ll notice I make use of several hidden input fields. I didn’t use ViewState for values the control absolutely needs to work because Subtext disables ViewState.  Likewise, I could have chosen to use ControlState, but that can also be disabled.  I took the most defensive route.

[Download InvisibleCaptcha here].

tags: , , ,

What others have said

Requesting Gravatar... derek@spathi.com (Derek Ekins) Sep 26, 2006 7:11 AM
# Re: Lightweight Invisible CAPTCHA Validator Control
Hey this is really clever but simple.<br />Nice work!
Requesting Gravatar... Sara Sep 26, 2006 10:20 AM
# re: Lightweight Invisible CAPTCHA Validator Control
I just blogged about how i hate captcha today and someone pointed me here. You're the man Phil.

http://www.ilovecode.com/2006/09/26/captcha-can-go-to-hell/
Requesting Gravatar... Craig Sep 26, 2006 10:25 AM
# re: Lightweight Invisible CAPTCHA Validator Control
When the user submits the form, we take the submitted value from the hidden form field, combine it with a secret salt value, and then hash the whole thing together.


How is the salt secret? I assume you have to send it to the client so they can use it as well...
Requesting Gravatar... Haacked Sep 26, 2006 12:14 PM
# re: Lightweight Invisible CAPTCHA Validator Control
No, I keep the salt on the server. I send the math problem to the client via javascript which in pseudo-code is this (using 3 + 4 as example):

document.getElementById(hiddenFieldId).value = 3 + 4;

I also send the answer to the client via another hidden form field, but base 64 encoded.

<input type="hidden" name="someid" value="Nw==" />

To prevent tampering, I also send the answer hashed in yet another hidden field.

When the user submits the form, I take both values (decoding the second) and compare them. I then hash that value and compare it to the expected hash.

I finished this at around 4AM last night, so I accidentally took out that last hidden input field, so I need to put it back in.

So I do give the client the answer base64 encoded, but that's fine since it either needs to add the numbers, or base64 decode the answer. Either way, it takes javascript to do so.
Requesting Gravatar... Haacked Sep 26, 2006 12:24 PM
# re: Lightweight Invisible CAPTCHA Validator Control
I updated the control to add in that extra bit of tamper-proofing.
Requesting Gravatar... Scott Hanselman Sep 26, 2006 8:19 PM
# re: Lightweight Invisible CAPTCHA Validator Control
Would this defend against a WATIR attack? Should I try? ;)
Requesting Gravatar... Haacked Sep 26, 2006 8:27 PM
# re: Lightweight Invisible CAPTCHA Validator Control
Give it a shot! I'd love to know. I'm guessing Watir can handle the javascript.
Requesting Gravatar... Haacked Sep 27, 2006 6:41 PM
# re: Lightweight Invisible CAPTCHA Validator Control
An even better approach might be to use a symmetric encryption library to place the answer in a hidden input in the form.

I should also encrypt the date to prevent a replay attack.
Requesting Gravatar... lb Sep 27, 2006 6:45 PM
# re: Lightweight Invisible CAPTCHA Validator Control
added bonus: blocks people who are bad at math. Like the old saying that "lottery is a tax on people who can't do math".

Mike Pope uses something similar at his site. I don't know how it works under the covers, i just know that i have to put my thinkin hat on before i respond to any of his witty posts.


Requesting Gravatar... Haacked Sep 27, 2006 6:47 PM
# re: Lightweight Invisible CAPTCHA Validator Control
Correction Leon, it blocks blind people (or those who use Lynx or turn off javascript) who are bad at math. ;)
Requesting Gravatar... Targeting Spam Sep 28, 2006 11:13 PM
# Lightweight Invisible CAPTCHA Validator Control
[Source: you've been HAACKED] quoted: Let me elaborate on the first point.&#160; In order to get the NoBot control working, a developer needs to add a reference to two separate assemblies, Atlas and the Atlas Control Toolkit, as well as make a few changes to Web.config.&#160; Some developers will simply want a control they can simply drop in their project and start using right away.
Requesting Gravatar... Quix0r Sep 29, 2006 3:42 AM
# re: Lightweight Invisible CAPTCHA Validator Control
Have you tried out my "Comments Post Rewriter" plugin? It also fights against comment spam by inserting an authorization code into the action-attribute of the comment form. :)
Requesting Gravatar... you've been HAACKED Oct 02, 2006 11:49 PM
# Better CAPTCHA Through Encryption
Better CAPTCHA Through Encryption
Requesting Gravatar... di .NET e di altre Amenit Oct 30, 2006 2:20 AM
# Subtext 1.9.2
Subtext 1.9.2
Requesting Gravatar... limfidus Oct 30, 2006 10:33 AM
# re: Lightweight Invisible CAPTCHA Validator Control
woohoo!
Requesting Gravatar... Sydney Atuatika Jan 25, 2007 9:46 PM
# re: Lightweight Invisible CAPTCHA Validator Control
Very awsome
Requesting Gravatar... Dragan Feb 05, 2007 7:43 AM
# re: Lightweight Invisible CAPTCHA Validator Control
1) Nice try, really!
2) Part with javascript is actually easier to crack than weakest image captcha
3) Part with image is worse that regular captcha because you need not only read and write but do the math.

When you think about javascript solution, don't forget that it actually requires a machine to be identified, and not human...
Requesting Gravatar... Steven Smith Feb 27, 2007 7:52 AM
# Spam Countermeasures
Spam is an increasingly annoying and expensive part of our lives as computer users. In the last week,
Requesting Gravatar... Steven Smith Mar 14, 2007 4:25 PM
# ASP.NET Wish List
I&amp;rsquo;m at the MVP Summit this week in Seattle and one of the things this provides an opportunity for
Requesting Gravatar... Kris - TECH Mar 16, 2007 6:34 AM
# ASP.NET Wish List
I’m at the MVP Summit this week in Seattle and one of the things this provides an opportunity for is
Requesting Gravatar... Chris Crowe's Blog Apr 12, 2007 2:59 AM
# New Blog Engine
New Blog Engine
Requesting Gravatar... Stefan Holmberg May 07, 2007 12:59 AM
# re: Lightweight Invisible CAPTCHA Validator Control
Paul,
you have some great ideas here which might not be too obvious to spot right away : the use of a static SymmetricAlgorithm - and therefore generating a new key and IV at each app restart. I used a hardcoded key which is not so clever:) "No javascript" is not an issue in my particular project so I am using a sort of JQuery driven invisible captcha where I add hidden fields to the form by using javascript. I also stuff a lot of things inside a cookie such as the hidden field name (I generate a new hidden field control name for each request/response) since my app is useless without cookies anyway.
Requesting Gravatar... mcgurk Jun 13, 2007 6:05 AM
# re: Lightweight Invisible CAPTCHA Validator Control
I'm lol. Every time I post on CodingHorror I point out the captcha is still "Orange". Had the feeling that it was something like this. I'm going to have to create a spambot for his website just to pay him back.
Requesting Gravatar... James Shaw Sep 05, 2007 4:57 PM
# re: Lightweight Invisible CAPTCHA Validator Control
It works great, thanks...except that when i refresh the form (by hitting <back> then saying yes, re-submit) i get the error below. Any ideas?


[CryptographicException: Padding is invalid and cannot be removed.]
System.Security.Cryptography.RijndaelManagedTransform.DecryptData(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount, Byte[]& outputBuffer, Int32 outputOffset, PaddingMode paddingMode, Boolean fLast) +1455156
System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount) +179
Classes.InvisibleCaptcha.DecryptString(String encryptedEncodedText) in C:\Documents and Settings\James\My Documents\_Repository\Components\Utils\InvisibleCaptcha.cs:72
Classes.InvisibleCaptcha.EvaluateIsValid() in C:\Documents and Settings\James\My Documents\_Repository\Components\Utils\InvisibleCaptcha.cs:219
System.Web.UI.WebControls.BaseValidator.Validate() +86


Requesting Gravatar... Keyvan Nayyeri Oct 07, 2007 12:34 PM
# Spam Busting in Community Server 2007 - Part 2
In the first post I gave an introduction and outlined eights spam rules to fight against spammers in
Requesting Gravatar... mark Oct 24, 2007 7:42 PM
# re: Lightweight Invisible CAPTCHA Validator Control
Representing not quite the lowest denominator in web developers but someone new to some jargon you use in the installation of this app for securing contact forms - how exactly does this install?

"You can choose to either reference the assembly in order to get started right away, or choose to add the source code file and the javascript file (make sure to mark it as an embedded resource) to your own project."

I know you've apparently worked hard to make this an easy app to employ but I am asking for one more step in your explanation that may help others in the shallower end of the programmers pond. What exactly is the elegant, fast way to accomplish this installation? The phrase "reference the assembly" sounds so simple, this is probably a very stupid question...

Your logic in the design and execution sounds very, very good.

/mark



Requesting Gravatar... Haacked Oct 24, 2007 11:28 PM
# re: Lightweight Invisible CAPTCHA Validator Control
Here's an article on adding and removing references with visual studio.
Requesting Gravatar... mark Oct 25, 2007 3:49 PM
# re: Lightweight Invisible CAPTCHA Validator Control
Thanks, I'll need to read up, still quite a reach from the look of it for my xhtml designer background. But I do dig your site.

Cheers -
Requesting Gravatar... qwed Nov 15, 2007 4:46 AM
# re: Lightweight Invisible CAPTCHA Validator Control
dewd
Requesting Gravatar... Tom ¨Pester Dec 04, 2007 4:04 PM
# re: Lightweight Invisible CAPTCHA Validator Control
Hi Phil,

I enyoyed reading your blog post about the "Lightweight Invisible CAPTCHA Validator Control"

I have a question regarding this post and your comment
http://haacked.com/archive/2006/09/26/Lightweight_Invisible_CAPTCHA_Validator_Control.aspx#4597

I fail to see why the second MIMEed hidden field is necessery.
The first and the 3th hashed value can be compared on the server. Isn't that enough?

Maybe your original idea was to do a compare on the clientside but I don't see this implemented if I read the code (I can't execute the code atm sry)

I think the second hidden field is redundant in the current code that you provide for download.

My second question is about why you replaced the hash with a symmetric encryption algorithm.
I fail to see the added security. Please enlighten me cause I am not too comfartable with encryption technology.

I would be very grateful if you could answer these 2 questions cause I am greatly interested in the subject and would like to understand the solutions fully before using them.

Kind Regards, Tom Pester

FYI The contact page has a problem with the mail server after you submit the form
Requesting Gravatar... Josh Stodola Dec 29, 2007 7:50 PM
# re: Lightweight Invisible CAPTCHA Validator Control
Hmmm. I am going to give this a shot, but I am not thinking it is so lightweight, upon considering the ridiclous 20+ KB WebResource.axd javascript file that comes along with the validator. That is no good!

Thoughts?
Requesting Gravatar... Community Blogs Jan 04, 2008 11:18 PM
# Reopen The Comment Door For Your Readers With Subkismet
Six months ago and six days after the birth of my son, Subkismet was also born which I introduced as
Requesting Gravatar... kamal Jan 07, 2008 5:35 AM
# re: Lightweight Invisible CAPTCHA Validator Control
why when i use the CallServer function the CaptchaControl is not working
Requesting Gravatar... Patrick Jan 21, 2008 3:54 AM
# re: Lightweight Invisible CAPTCHA Validator Control
Umm, you gotta be kidding me - this captcha is for real? Regardless of what encryption is used, a simple script in just about any language could pass this captcha pretty easily. Hell, if it only requires a javascript engine to pass it, a bot coder could simply have a application use an embedded Firefox/IE control and just parse the page in that and then grab the final value for submition - they could even submit it using the Firefox/IE control!
Requesting Gravatar... Haacked Jan 21, 2008 9:10 AM
# re: Lightweight Invisible CAPTCHA Validator Control
@Patrick no, I'm not kidding you. Feel free to miss the point and throw out theoretical faults with the system and ignore the fact that it's been working for over a year now.

This won't work for Ticketmaster, Hotmail, etc... It *does* work for Joe Schmoe's blog software. You give the bot writers too much credit.
Requesting Gravatar... Programming Information Jan 21, 2008 8:52 PM
# Features of SubText
Features of SubText
Requesting Gravatar... Robert Jul 13, 2008 9:47 AM
# re: Lightweight Invisible CAPTCHA Validator Control
FYI - The captcha download is not working.
Is there any other place where we can download the source? Thanks.

What do you have to say?

(will show your gravatar)
Please add 7 and 8 and type the answer here: