What’s the ideal check to protect your web forms from spambots?
No one really likes having to copy squiggly letters from a CAPTCHA image, but is there a better alternative?
The ideal check would be one that most people don’t ever notice, but which effectively keeps out all spambots.
I took on the challenge of creating a simple JS-based alternative to CAPTCHA, which I’ll explain below.
- The form should record certain events to prove human involvement.
- The tests should be invisible to the user where possible.
- It should not be possible for a bot to discover the test and to spoof the results.
Am I Human?
First of all, our form will need some way of sending the answer to “am I human” through to the back-end script.
For this, I’ll just use a hidden field. Note, following requirement 4 above, this field could be named anything. If bots learn the likely name for this field, they could send the correct value through and bypass the system.
I’ll put the hidden field before the closing form tag (but you could put it anywhere in the form).
<input type=”hidden” name=”imahuman” id=”imahuman” value=”0â€³ /> </form>
The value of this field is zero by default, which means “no – not a human”.
Switch it For Humans
What’s happening here (working from bottom upwards):
- The addEvent stuff at the bottom means you can simply call a single addEvent(what element, what event, function you want to run, escalation) command in almost any browser.
- The function markAsHuman will be called when we think we have a human. It simply changes the value of the hidden field from zero to 1.
- Note, it might be sensible to change these values to something less obvious.
- If the form receives the focus, we fire the markAsHuman() function;
- Same if the form receives a click.
- Both these events only happen in the browser window, so a code/spambot wouldn’t be able to reproduce them.
- Finally, at the very top, the addEvent() call tells the browser to run the setUpHumanTest() function when the page has loaded.
Testing Results with Script
Your form will submit to a middleware script (PHP, ASP etc.) You’ll simply need to tell this script to reject any submissions that still have “imahuman” (or equivalent) set to zero (or whatever you use).
Personally, I like to pretend that the script has worked, and forward the bot to the success page, but not do whatever is supposed to happen with a valid input. I figure that there’s no reason to tell a bot that you’ve twigged its game and draw attention to your site.
Clearly, we need to handle the (approximately 10%) minority that don’t use JS. This now includes some mobile browsers and text-to-speech readers, not just people exercising their choice for a diminshed browsing experience.
It’s very easy to show extra special HTML when JS is not working: you just use the <noscript></noscript> tag.
Here’s what I do:
<noscript> <dt>What is three plus four?</dt> <dd><input type=”text” maxlength=”1â€³ name=”althuman” /></dd> </noscript>
This is really simple, but you could replace it with a CAPTCHA test if you prefer.
(Note, we usually use definition lists for form layout these days. Not the strictest semantic application of the tag type, but I think it’s OK, in the broader application of name/value pairs.)
The field only allows a one-character response, so you have to type “7”. This is also easy to change.
The back-end script would then need to test first whether “imahuman” is set “on”, OR if the alternative human check is correct. If either is OK, we’re OK.
I hope you find this technique easy to implement and useful on your own sites. If you have any comments, please let me know below.
Here’s a great post with 10 ways to help prevent spam on WordPress sites.