CAPTCHA Alternative? Try this Invisible Human Check for Web Form Validation

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.

In this tutorial, I describe a technique that uses Javascript to recognise human activity based on screen events, which works very well for us.

In a discussion on Scratch Forums on the merits of CAPTCHA, one of our members suggested a possible alternative that detected JavaScript events (mouse events, keystrokes) to show that it’s a human completing the form.

I took on the challenge of creating a simple JS-based alternative to CAPTCHA, which I’ll explain below.

High-level Requirements

  1. The form should record certain events to prove human involvement.
  2. If JavaScript is not enabled, there needs to be a fallback solution.
  3. The tests should be invisible to the user where possible.
  4. 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

We want to set the value of “imahuman” (or your own name, please) when certain events take place, which we’ll detect using Javascript.

Following best practice, the function that sets up the event detection should be called by an event handler, and that event handler should be attached using an external Javascript file, not written into your HTML code. Like this…

// Set up
addEvent(window, "load", setUpHumanTest, false);
function setUpHumanTest() {
var myforms = document.getElementsByTagName("form") ;
for (var i=0; i&lt;myforms.length; i++) {
addEvent(myforms[i], "focus", markAsHuman, false);
addEvent(myforms[i], "click", markAsHuman, false);
}
}

// Identify a human
function markAsHuman() {
document.getElementById("imahuman").value = "1";
}

// Generic cross-browser code for attaching events to elements
// You should really have this in a separate common JS file
var addEvent;
if (document.addEventListener) {
addEvent = function(element, type, handler) {
element.addEventListener(type, handler, null);
if (element.href) element.href="javascript:void('');" ;
}
}
else if (document.attachEvent) {
addEvent = function(element, type, handler) {
element.attachEvent("on" + type, handler);
if (element.href) element.href="javascript:void('');" ;
}
}
else {
addEvent = new Function; // not supported
}

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.
  • function setUpHumanTest() actually runs through every form on the page (why not?) and attaches 2 javascript event handlers to the form:
    • 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.

What About When JavaScript is Off?

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.

Become a True Web Pro!

57 Comments Leave a comment

  1. James says:

    A nice idea, but still easy for spammers to bypass the check by simply passing the number field with ’7′. A captcha alternative is the only reasonable conclusion.

    Additionally, a spammer (with a brain) could still quite easily pass the imahuman field as ‘true’ if they took some time to inspect the elements.

  2. Ben says:

    James, you’d change the name of the variable, and also the details of the sum, to whatever you want. I think that gives a good enough level of protection for many purposes.

  3. Blink Web Design says:

    problem , I use a form filler to fill in forms , fills them all in

  4. Fruity says:

    This is perfectly fine to use – as well as a dozen other methods – as long as your site isn’t specifically targeted.

    Lets say I’m the bad guy – and my bad guy boss wants spambot on your site – in a few moments of examination(no more than 20 minutes,) you’re toast.

    If you are targeted, a good captcha is the only recourse.

    Chances are, no one will waste their time like that, however, so use whatever you want :)

    • R2D2 says:

      There is no such thing as “good captcha”. Captcha is always pain in the ass for real user, but it does not stop spammers.

      And you should never use external captcha services. Those are spam magnets. For example, one of my favorite forums was running years without any spam. Then they updated the forum and started to use capthca. Instantly, the site was flood with spam.

  5. Justin says:

    It’s interesting that you tell the bot that it’s succeeded. The problem here, as I see it, is that there are bot/human pairs, where the human only jumps on when the bot has reached a certain level of success. Typically the bot has reached a point that it needs help to go further. Or, the bot got some information that a human can use.

    Telling a bot that it did its job may be the same as telling it to put it in a report that a human will look at, and then come to your site to do –whatever–. They say “why isn’t this working???” and only then start poking around. If this happens, it would have been better just to tell the bots to blow off.

    I think it really depends on your site. As a previous commenter mentioned, the difference is if you’re targeted specifically. Sadly, if you’re targeted specifically, not even a captcha will work. (there are plenty of ways around captchas).

    I think most sites go too far. Just do anything unique, and you’re ok until you’re a target. “What’s 4+4?” or even bluntly asking “Are you human?” and looking for “no” as a response. Using these methods I’ve never dev’d for a site that has actually become a target – it’s the out of the box stuff that gets hit by random bots.

  6. ejes says:

    WARNING: this will NOT WORK, it is trivial to bypass.

    NEVER use client side controls for verification.
    This is SECURITY 101 people… go look at the OWASP site to find out about REAL security.

    WARNING: this will NOT WORK, it is trivial to bypass.

    • Clemens says:

      Dear Ejes,
      would you kindly link to specific OWASP-project(s) which target “Captcha alternatives” (bot-form-submission)?
      Thx

  7. fajas colombianas says:

    you’d change the name of the variable, and also the details of the sum, to whatever you want

  8. ahaghh says:

    haha.. you will never beat xrumer ;)

  9. NickR says:

    It’s nice to see people looking for alternatives to the captcha that’s so prevalent at the moment. Unfortunately, as a previous commenter mentioned, I also use a robot to pre-fill forms for me so wouldn’t be considered human. With a tick box that the robot didn’t identify to ask whether I was human I would have to manually intervene but with this technique in it’s current form I probably wouldn’t notice and would be none the wiser as the success page would still show.

    In my opinion it’s back to the drawing board time but I think with some refinement you could get this to work.

  10. Logan says:

    Would it be possible to add something that tracked your time on the page? If greater than 10sec then human=1?

    A captcha method is definitely the way to go for anything important, however I’m sure this method would suit most contact forms and blogs well.

    I’d agree that it’s not perfect, but it could dramatically cut down the spam. The slight inconvenience of receiving a few spam messages a week is, IMO, is worth improving the user experience for typical visitors.

  11. Karsten says:

    Interesting idea, although the spammers will probably find a way, they always do. Also, some bots are welcome, the Google-bot, for example. The anti-bot feature must be implemented in a way, that it does not prevent Google from spidering your content. This would be ok for submission forms, as mostly there is no need for search engine to spider the result pages. But you would have to take care, if you use these anti-bot features in other website elements.

    All in all: Nice idea! :)

  12. Mark Christian says:

    I get a lot of spam through my form – usually about the same stuff. It’s as though there’s a robot that finds unsecure forms on websites and hits them constantly.

    As I get a lot of this I figured it might be a good way to test if this stops the spam or not. I’ll come back and tell you all if it works.

  13. Cambridge Bonner says:

    I’m sorry to admit that I have tried various levels of protection using JavaScript methods but all have failed because spammers are clever enough to evaluate the JavaScript and come up with a solution that bypasses any checks.

    Captcha checking is better but again these are being cracked. I find AI with AI training works best as matching a series of patterns against what has been submitted works best and then any spam-like messages are put aside for checking once all non-spam messages have been.

    This is the solution I deploy to all of my customers who report very low levels of spam and in most cases what they report isn’t spam but more an unwanted newsletter they signed up for.

  14. Jeru says:

    The number of people who have JavaScript off is way less than that – it’s like 1 or 2% these days.

  15. Pingback: In Search Of The Perfect CAPTCHA - Smashing Magazine

  16. Pingback: In Search Of The Perfect CAPTCHA | Ruturaj Pradeep Kohok | Your Web Advisor

  17. Pingback: In Search Of The Perfect CAPTCHA | Remake Wordpress Theme

  18. Daniel says:

    form.focus();
    And you’re dead.

  19. Greg says:

    wait… Logan’s idea is very interesting. What about the time variable idea? Page load, set a time variable and save to db with php, on submit cross reference with stored variable, if 10 seconds has passed allow the form. Wouldn’t this stop robots, or at least bring them to a crawl?

    • deatos2k says:

      The problem with this, is by design you would be sending an integer from the browser to the server, or adding it to the query string, nothing is stopping a spambot from just using a fuzzy average here.

  20. deatos2k says:

    anything done with javascript can be defeated by spammers, some spambots use the browsercontrol itself and send actual clicks to the form elements, thus passing this test, bots that are socket based only need to create a dom out of the document, and then execute javascript against the dom element to get the required values. All of this can be done in just a few lines of code. A better solution would be to use something that is not so easy such as drawing a line on a swf object which is not so easy for spammers to work around.

    • Paul says:

      “some spambots use the browsercontrol itself and send actual clicks to the form elements, thus passing this test”

      Yeah exactly. This is useless against them.

  21. deatos2k says:

    spambots generaly use regex for pattern matching
    so if you know a bot is looking for this

    chances are they are matching it with this:
    input.*?name=\”formauth”.*?value=\”(.*?)\”

    so change it to this

    with a browser you can expect to see this data
    formauth=
    dsfasdfasdfs=imaspambot

    with a spambot, you would see
    formauth=imaspambot
    dsfasdfasdfs=imaspambot

    • deatos2k says:

      my html was stripped off :/ so that example didnt go so well

  22. Eric says:

    But this would be so easy to bot. Change all numbers to their integer forms and replace operators with their single character form and then eval. For example if you have the words five plus four it would first do 5 plus 4 and then 5 + 4 and then eval it. Far too easy to crack with a bot.

    • Ben Hunt says:

      If you can be bothered to write custom bot code for every small website. This is a simple version, it could be obfuscated pretty easily I think.

      • benny says:

        You can use foreign words, not English. Or English with some variants, e.g. Whatisonepluseight? Writethewordhuman. etc.

  23. Jenni says:

    I recommend you using the GASP wordpress plugin to prevent spamming comment, it’s so much better than Akismet.

    • Aaron says:

      I agree, Jenni. It’s been a great addition to my client sites. Went from dozens of spam comments a day to none.

  24. Kyle Hobson says:

    How can I test it to see if it works, right?

  25. Calin says:

    I don’t like captcha, but let’s admit that with today’s spammers, it’s a strong solution.

  26. Herrin says:

    And what about all the human spam going on at the moment? Is captcha or this solution going to stop them?

    • R2D2 says:

      Yes, the problem with both captcha and this Javascript solution is that they only try to stop robots. However, most of the spam these days comes from humans.

      There are lots of companies for example in India where thousands of people are working just to resolve captchas. They may be paid like one cent for each capthca, but they have so much practice they can easily submit hundreds of captchas per hour.

  27. Helen Neely says:

    Nice example, but I think another method to protect your form would be to check on the server side that the values are indeed coming from your form. I’ve seen people post data from a different form trying to brake the application.

    Nice article BTW.

  28. Chris Ivey says:

    I agree with the need for a better human interactive proof – but it has to be something that’s easy to incorporate into any existing architecture with a minimum of coding. My company just released a new technology with a different approach, called VouchSafe, and I’d be interested in your comments, (http://www.vouchsafe.com). Is it intuitive enough? Does making the user experience better add enough value to make it worthwhile for websites to switch?

  29. Anthony says:

    Many spambots will still get stopped by this method all the same.

  30. Behnam hassanpour says:

    All spambots looking for an exact field name if we send random elemens name maybe we could stop them.
    For example a bot is sensitive to email field name if we send a randum name instead of “mail” to user browser we can stop bots .Ofcours our script must be genus to detect submited forms.

  31. Pingback: In Search Of The Perfect CAPTCHA « Tips

  32. Dale says:

    I’m interested in using this on my forms and I understand where to place the no script tag but I’m not sure what to name the external java script file or how to activate from my form. A little clarity for the noobs would be greatly appreciated.

    • Ben Hunt says:

      Does anyone have a live example of this script they can share with Dale?

  33. Mike says:

    Use ajax to send the mouse clicks and the server stores them in cookie sessions or database or file with a timeout and then if they didn’t send these ajax signals then they were not using js.

  34. Xandor Schiefer says:

    I just add a second email field to my forms, but hide it from visitors using CSS.

    If it’s filled in it was a robot, simple. Works like a charm.

    http://www.webmasterworld.com/webmaster/3218242.htm

    • Michael says:

      Another approach is to layer another element over the input field so it appears hidden.

  35. Pingback: In Search Of The Perfect CAPTCHA | Smashing Coding

  36. Pingback: Oh God CAPTCHAs | Stephen Bussey

  37. Pingback: Oh God CAPTCHAs - Stephen Bussey

  38. Anon says:

    Clearly you’ve never made a bot before because this does absolutely nothing

    • Xandor Schiefer says:

      @Anon I fail to see how this does absolutely nothing. Please explain a bit further. What I described is known as the ‘Honeypot method’. It’s a bona fide anti-spam technique.

      • Paul says:

        He was probably talking about the article Xandor, not your post. Note that he wasn’t replying to your post. I’m pretty sure your method works much better than the author’s, although a sufficiently sophisticated script could read the css to see that the field is hidden to the user, and decide for that reason not to touch it.

  39. tim says:

    I get a js error:

    Error: TypeError: addEvent is not a function

    how to overcome this?

    • Ben Hunt says:

      Hi Tim.. I’m sorry, but I can’t support this code now. It is quite old, and JS errors will depend on many factors, not least the browsers you use.

  40. Paul says:

    I scoured this article for an explanation of how adding some javsacript could possibly fool a computer.
    All I could find was this:
    “Both these events only happen in the browser window, so a code/spambot wouldn’t be able to reproduce them.”

    What the heck? Am I missing something? What makes you think a malicious program does not have access to a browser, and the ability to trigger the exact same events your human can trigger?

  41. Michael says:

    I really like the idea, but don’t have the necessary know-how to implement it. Do you have a sample script to install what is necessary? And would this work in a setting where one would use something like Captcha to access some information, like an e-mal address?

    By the way, your form at your Contact link is a blank area of the screen.

    Thanks.

    • Ben Hunt says:

      Hi Michael. I’m sorry but I don’t have a nicely packaged version of this. It’s really shared for the benefit of fairly experienced developers.

  42. Pingback: In Search Of The Perfect CAPTCHA