RSS
 
09. Aug. 2010

How to implement Captchas properly

09 Aug

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.
Mabye 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 often times 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 desaster.
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 tempered 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 build as 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 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.
Thats all there is to it.
That’s why a behaviour in combination with a helper does the trick perfectly.

The code is in my github tools plugin:
captcha behavior
captcha helper
and functionality that both classes use is in captcha lib.

Note: The links are for 1.3 – if you want the 2.0 stuff, you need to switch to this branch.

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 strenghts):

  • 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

Posted by Mark in CakePHP

 

Tags: , ,

Leave a Reply

Tip:
If you need to post a piece of code use {code type=php}...{/code}.
Allowed types are "php", "mysql", "html", "js", "css".

Please do not escape your post (leave all ", <, > and & as they are!). If you have encoded characters and need to reverse ("decode") it, you can do that here!
 

 
  1. Michael Clark

    August 30, 2010 at 17:28

    Sounds like you’re thinking in the direction of a SAPTCHA: http://dmytry.pandromeda.com/texts/captcha_and_saptcha.html

     
  2. Mark

    August 30, 2010 at 17:52

    yeah thanks
    didnt know they are called saptchas ๐Ÿ™‚

    quite similar to my ideas anyway

     
  3. heohni

    October 12, 2011 at 12:41

    What is the CaptchaLib at
    App::import(‘Lib’, ‘Tools.CaptchaLib’); ?

     
  4. Mark

    October 12, 2011 at 12:47

    ops – forgot the link to it.
    is now available!

     
  5. heohni

    October 12, 2011 at 12:56

    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?

     
  6. Mark

    October 12, 2011 at 12:59

    its already done for you by the behavior ๐Ÿ™‚

     
  7. m16u

    January 18, 2012 at 22:59

    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
    ?????

     
  8. Mark

    January 19, 2012 at 02:14

    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?

     
  9. m16u

    January 19, 2012 at 23:54

    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 " ….????

     
  10. Mark

    January 20, 2012 at 00:31

    Oh, thx for the heads up. the translations are still only in the 1.3 branch.
    I will merge them into the 2.0 branch immediately.

    the BR is a part missing (see the bootstrap goodies talked about in the article).
    But I will also provide a fallback.

    All right – done:
    https://github.com/dereuromark/tools/tree/2.0/Locale

     
  11. miguel

    March 28, 2012 at 04:01

    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

     
  12. miguel

    March 28, 2012 at 04:44

    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

     
  13. Mark

    March 28, 2012 at 09:55

    You are right. Those rely on my MyModel invalidate method from https://github.com/dereuromark/tools/blob/2.0/Lib/MyModel.php#L1213

    Sry, I totally forgot to mention this.

     
  14. pedro

    September 25, 2012 at 20:25

    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.

     
  15. Mark

    September 25, 2012 at 22:58

    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).

     
  16. pedro

    September 26, 2012 at 12:49

    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.

     
  17. Mark

    September 27, 2012 at 08:27

    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.

     
  18. Miguel

    November 27, 2012 at 06:33

    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

     
  19. Mark

    November 27, 2012 at 10:30

    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.

     
  20. multiscan

    December 10, 2012 at 11:55

    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.

     
  21. Mark

    December 10, 2012 at 13:36

    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..

     
  22. multiscan

    December 10, 2012 at 14:35

    &gt;&gt;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. ๐Ÿ˜‰

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

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

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

    ๐Ÿ˜‰

     
  23. Racoon

    January 13, 2013 at 13:58

    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.

     
  24. nj

    February 7, 2013 at 11:10

    Thank you big time sir Mark for this one!

    Unusual implementation of captcha yet simple and it actually works.

     
  25. Moltra

    March 26, 2013 at 01:02

    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

     
  26. Moltra

    March 26, 2013 at 01:04

    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.');
    			}
    		}
    	}
     
  27. Mark

    March 26, 2013 at 01:08

    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.

     
  28. Seb

    March 10, 2014 at 16:24

    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?

     
  29. Mark

    March 11, 2014 at 10:20

    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.

     
  30. Siddharth

    June 13, 2018 at 09:30

    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 ..

     
  31. Mark

    June 29, 2018 at 11:40

    Use the 2.x branch there.