How to implement Captchas properly

What is a captcha?

They protect forms on websites from spammers and bots (@see Wikipedia for details). The main idea: Display some kind of code a human can easily read and submit but a computer can not.

How NOT to implement captchas

This part is even more important because there is not only one correct way, but even more wrong ways to go here.

Don’t use sessions unless you really have to.
Pages that use something like $_[‘Captcha’][‘field’] and override this one on every form, really freak me out! It makes working with two or more tabs impossible, because they override each others captcha values all the time, resulting in a ****** mess.
You could use an array-like structure, but your captcha session array can get pretty big in a short amount of time.

More helpful are captchas which use the current form and some hash values based on the fields + current timestamp. It should not be possible to "guess" or "calculate" the hash value. So there is no way to use future "hashs".
You could use older hashs (like from last week), though. But most bots are programmed to just post right away. They would have to save possible valid "scenarios" for later usage.
Maybe we can come up with something fail-prove later on. For now, we want to effectively prevent spam bots to submit their crap without annoying normal users.
The second part is always the hardest. Me – for example – I really hate those image captchas which you can barely read. I oftentimes have to repeat or reload it twice in order to succeed. Annoying comes not even close.

Why do we need captchas

First of all, they make sure that there is no bot (automatic program) posting "spam" or whatever.
But sometimes you just want to add captchas to prevent users from doing some action too often (like friendship requests in a community site etc).

A good example what happens if you dont use captchas, is bakery.cakephp.org.
Some articles have like 36 comments, of which all 36 are SPAM. This is a disaster.
And in this case you even have to be logged in to submit a comment.
The argument that forms for which you need to be logged in don’t need captchas is not contemporary anymore.

Passive Captchas

I already talked about using some hash values based on the fields + current timestamp.
This can be used to generate passive captchas. They are similar to the cake core component "security" which adds some hidden fields to make sure that the fields have not been tampered with.

Both are invisible to the user – they dont even notice the passive captcha. But bots will soon discover that they are facing a wall.
The difference is, that passive captchas should only valid in a specific timeframe. Too fast (less than 2 seconds) is usually a sign for the work of a bot – humans cannot type that fast.
Too late (> x hours?) means you need to revalidate anyway, so we would render the form invalid as well. Well designed forms will keep the posted content, so nothing gets lost.

Another aspect to improve security is to use other user-specific fields for the hash value like browser agent (cannot change during posts, but is less secure because it can be modified), IP address (can only be modified by very skilled hackers and therefore is pretty secure), …

Active Captchas

Those are the most commonly used ones. Users either have to read an image, calculate numbers or
interpret a sentence. The first one is not suitable for handicapped people.

Usually, they are built as an extension on top of passive captchas. We first validate the passive one. If the form is OK, we then validate the user input. If validation passes we render the captcha valid.

I decided to use math captchas. They keep you mentally fit and do what they are supposed to. The only important issue is to make it easy enough. I saw pages using / [division] or numbers above 20 in a multiplication or even above 100 for summation – which is total overhead.
But other ones could be used as well – simply by changing configuration settings.

Captcha Behavior

Ok, to sum it up, we want captchas that

  • don’t annoy users
  • protect as good as absolutely necessary
  • can be used with tabs
  • can be easily implemented and configured

The idea is, that we want to add a single form field as well as attach a single behavior to our model.
That’s all there is to it.
This is why a behavior in combination with a helper does the trick perfectly.

See the bottom links for code reference.

Setup

First include the plugin in APP/Plugin/Tools and make it available using CakePlugin::load('Tools') or CakePlugin::loadAll().

This makes sure the helper is available in your controller:

public $helpers = array('Tools.Captcha');

Helper usage (in the view):

echo $this->Captcha->input(); // or input('Modelname') if model is different from the form model

Behavior usage (in the controller):

    $this->User->Behaviors->attach('Tools.Captcha');
    if ($this->User->save($this->data)) { ... }

Pretty straight forward, isn’t it?

Issues

Current weaknesses (apart from its strengths):

  • possible "hash extraction" with unlimited use of those valid hashs (session or db to prevent?)

Final notes

Right now it is mainly used for math captchas (active captchas) and just passive captchas.
Feel free to update the missing parts like providing more captcha types (image, sentence, …) or processing types (session, cookie, …).

Since 2.0 the Security component has improved quite a bit. You can combine this captcha behavior with it to get maximum security.
The security component will actually store the form fields as a hash in the DB and therefore invalidate any foul-play right away.

UPDATE 2011-10-13
The i18n translations are now commited, as well: /locale

UPDATE 2012-04-30
For CakePHP 2.x you need to use $this->request->data instead.

UPDATE 2017/2018
For CakePHP 3.x this has been moved into its own plugin @ dereuromark/cakephp-captcha GitHub repository.

3.75 avg. rating (77% score) - 4 votes

31 Comments

  1. yeah thanks
    didnt know they are called saptchas 🙂

    quite similar to my ideas anyway

  2. OK great!
    I’ve got it running, but how can I validate it?
    I need to setup a rule in my model to return a error message on failure, how can I do this?

  3. hi im working un cake 2,but i have this erros

    Warning (4096): Argument 1 passed to Helper::__construct() must be an instance of View, none given, called in D:\xampp\htdocs\blogcake2\app\View\Helper\CaptchaHelper.php on line 28 and defined [CORE\Cake\View\Helper.php, line 144]
    Notice (8): Undefined variable: View [CORE\Cake\View\Helper.php, line 145]
    Notice (8): Undefined variable: View [CORE\Cake\View\Helper.php, line 146]
    Notice (8): Trying to get property of non-object [CORE\Cake\View\Helper.php, line 146]

    any help
    ?????

  4. Did you use the correct files? 2.0 branch for a 2.0 project.
    Then everything should work fine.
    PS: how did you include your helper?

  5. Hi thanks for reply, the captcha sometimes works..i have this errors,

    Notice (8): Use of undefined constant BR – assumed ‘BR’ [APP\Plugin\Tools\View\Helper\CaptchaHelper.php, line 124]

    CaptchaBRcaptchaExplained
    nine calcMinus zero =

    I think it should be "nine -zero " ….????

  6. hi sorry for my bad english, I speak spanish and i wanna to localizate into spanish this captcha, i have the .po file in spanish but.
    How, I can use this po file by default?

    thank you

  7. ok I edited the captcha_de.po file and translated into spanish the numbers labels work fine but these messages cant translate

    msgid "captchaResultIncorrect"
    msgstr "El resultado es incorrecto"

    msgid "captchaResultTooFast"
    msgstr "El resultado se escribo demasiado rápido"

    msgid "captchaIllegalContent"
    msgstr "Contenido ilegal"

    again thak you

  8. Hi Mark,

    I’m trying to use your CAPTCHA. I’m getting the following.

    Error: The application is trying to load a file from the Tools plugin

    I’m working in Cake v2.
    a) I copied the Helper: CaptchaHelper.php in the /View/Helper/CaptchaHelper.hp
    b) I’ve copied the lib at /Lib/CaptchaLib.php
    c) I’ve include the helper in the Controller as
    public $helpers = array(‘Captcha’);

    I appreciate your help.
    Thank you very much.

  9. without some cake experience it is easier to leave the plugin intact and copy it alltogether using it as above.
    Copying the files requires some minor changes in the include statements in the files (App::uses() needs to be changed).

  10. Thanks Mark,
    I did it and it’s working now.

    I’m testing and this is happening

    1. Randomly the captcha element show the math sign and other time it show the label such as calcPlus

    2. Even when I’ve enter the right result. It return the error: captchaResultTooFast.

    I’ve started to play with your CaptchaBehavior to test it better and I did:
    a) Modified the _validateCaptchaMinTime and _validateCaptchaMaxTime method, always returning true.
    And even when the entered value is right, it return an error captchaResultIncorrect

    b) The captchaResultIncorrect is returned because the _validateCaptcha method in the line

    if ($data['captcha_hash'] == $hash){ return true}

    The $data[‘captcha_hash’] is equal to $hash

    So far, what other kind of configuration should I have in my cakephp to work with your code?

    Thank you very much! This is exactly the Captcha component I need in my site. I appreciate your help to work with this.

  11. seems like you forgot to include the translations form the po file in your app po file (default.po). then "calcPlus" would be "plus" etc.

    for the other points. I don’t see why there should be any modifications necessary. So far they work for me just fine. I will have to look into that in detail.

  12. hi, firt sorry for my bad english, well i was using this behaivor in some projects but now i dont know i have this messge "captchaIllegalContent", and i dont know why … doy you know What is causing this error? last week worked fine

  13. you should translate that via PO file to sth like "Are you a bot? It seems this way" – The illegal content flag is raised if you submit sth in the "homepage" field for example – it is a dummy field bots will most likely run into.

  14. Thank you very much! I just use this code for a project of mine and I appreciate it very much.

    If I can, I would like to suggest you to create a step by step guide. I’m quite new to cake php and it took me a bit to understand where I have to place captcha behavior captcha helper and captcha lib inside my project
    (at first try i put CaptchaBehavior in /app/model/behavior instead of /app/plugin/tools/model/behavior and i place also others file with the same logic).

    Anyway I like very much this kind of bot avoidance and this implementation really works fine.

    PS: I apologize for any grammar error but I’m not a native speaker of English.

  15. It would be wiser to put the whole tools plugin in your APP/Plugin/ folder. This way you safe a lot of time and trouble.

    Please note that you need to respect the casing (Model/Behavior instead of model/behavior).

    Yeah, I should add a beginners guide at the top of the articles. I used to expect too much of beginners in the past..

  16. >>It would be wiser to put the whole tools plugin in your APP/Plugin/ folder. This way you safe a lot of time and trouble.

    yes I understand it after some struggle. 😉

    >>Please note that you need to respect the casing (Model/Behavior instead of model/behavior).

    Yes, of course. I just mistyped in the comment.

    >>Yeah, I should add a beginners guide at the top of the articles. I used to expect too much of beginners in the past..

    😉

  17. So great, I implemented this in two minutes.

    I love you and I want to have your children. When I get paid I will send you money.

  18. Thank you big time sir Mark for this one!

    Unusual implementation of captcha yet simple and it actually works.

  19. I am new to Cakephp and I am not sure how to integrate this in my UsersController.php

     else {
                    $this->Session->setFlash('The user could not be saved. Please, try again.');
                }
            }
        }

    .

    I think I need to add the behavior usage

     $this->User->Behaviors->attach('Tools.Captcha');
        if ($this->User->save($this->data)) { ... }

    in the above, I am just not sure how. Any and all help / advice is apprciated

  20. for some reason the function did not add right in my prior post.

     public function add() {
            if ($this->request->is('post')) {
                if ($this->User->save($this->request->data)) {
                    $this->Session->setFlash('The user has been saved');
                    $this->redirect(array('action' => 'index'));
                } else {
                    $this->Session->setFlash('The user could not be saved. Please, try again.');
                }
            }
        }
  21. Well, you are on the right track. Anywhere prior to the save() call would do.
    Also bear in mind that yo need to properly load the plugin as outlined in the cakephp documentation.

  22. Hey,

    thanks for this tutorial. I’d love to use the captcha plugin but it seems that it isn’T available on github anymore.
    The links above don’t work.
    Is there any way you could provide it?

  23. Please see the note in the text:
    "Note: The links are for 1.3 – if you want the 2.0 stuff, you need to switch to this branch."
    So simply use the cake v2 (current master) branch.

  24. Hi , I would like to use this . But the file links are not working .
    I am using cakephp 2.3.4 .
    Can you please send me the links ? please ?
    And the tutorial also ?
    Thanks in advance ..

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.