Monday, August 8, 2011

CAPTCHA ("Completely Automated Public Turing test to tell Computers and Humans Apart") are security controls used to prevent automated attacks against a website. You can see them in Gmail account register pages, blog comment forms etc. Sometimes they are used as a CSRF attack countermeasure.

How to do it?

Designing CAPTCHA challenge is hard - you need to fight OCRs (if the CAPTCHA is based on image recognition) and cheap labour (attackers pay $12 for solving 500 CAPTCHA, according to OWASP). On the other hand, it needs to be solvable by your users - so this one, while certainly being a strong challenge, is probably not a good idea ;)

But no matter what the challenge, the whole CAPTCHA architecture must be secure. For example:

it must be protected against replay attacks (CAPTCHA ID generated once cannot be reused)

CAPTCHA given for one session should not be valid in other session. There must be a relation between CAPTCHA and a session, so that the attacker won't solve the CAPTCHA (e.g. manually) in his own session and submit the solved value in the other session.

CAPTCHA solution must not be stored on the client

it must be protected against brute-force attack (e.g.require another CAPTCHA after a few invalid responses)

The amount of possible CAPTCHAs must be A Big Number (bruteforce protection).

MotionCAPTCHA - The fail of the day

What pushed me into writing this blog post is the MotionCAPTCHA project I encountered. It's a HTML5 (yay!) canvas based project where the challenge is to repeat drawing a given shape to prove being a human. I've seen a few broken CAPTCHAs in my life, but this one is just over the top. Just two examples:

You manually disable your form, by emptying the form's action attribute, and placing its value in a hidden <input> with a specific ID. You should also put disabled="disabled" on the submit button, for added points.

You add a few HTML lines to your form to initialise the MotionCAPTCHA canvas, and add the plugin's scripts to your page.

The user draws the shape and, if it checks out, the plugin inserts the form's action into the <form> tag. The user can submit the form, happy days.

and when I solve the challenge, the 'mc-action' will become the form action and the form submits? And the server does not care about the challenge cause it's client side only? How about bot POSTing the form in its entirety to the mc-action URL and bypassing the CAPTCHA completely? #security #fail! Client side CAPTCHA will never be secure, it just can't!

Ouch! Looks like you didn't get around to reading the part where it clearly states:

"In the next major release, the plugin will use progressive enhancement so that the form uses a standard server-side (e.g. PHP) CAPTCHA script, and then on page load, the plugin switches that for the Motion CAPTCHA canvas, only if the browser is grown up enough."

Or the numerous times where I made it clear that this is (in its current state) not intended for production-use. Thanks for the feedback though, I can assure you I've considered your points sir.

Hi! Thanks for your comment, I especially value developers point of view.

I understand that it's version 0.2 and you have a PHP backend in the roadmap, but you have to implement security features from the beginning - For example, your project is already forked a few times and possibly implemented somewhere. From my experience, any library/plugin/code snippet published,even with a big "Please don't use this yet" warning will get implemented in production by some bored programmer who just copy-pastes the googled code without thinking. I've even see my examples of vulnerable code recommended as a implementation.

The problem with PHP captcha and enhancing it client side is that you have a really limited solution-space. 16 shapes, even with a rotation is 64 in total, which is really low number for spam bots. Also, the JS code in client decides if you've drawn a shape correctly, right? So the spam bots will simply bypass it and call the 'shape is ok' function. The verification of whether the challenge is solved correctly (no matter if it's a math equation, image recognition pattern, shape drawing) must be validated by the server.

Don't take this personally, I would be all for having a captcha that is convenient to solve, but I don't think that's possible with the design choices you've taken. I will take a look though on future releases.

it's a proof-of-concept. this means: it shows whats possible! no fail at all.

btw: there is a PHP implementation of the $1-part: https://github.com/matkrzesz/phpDollari connected these two libraries, the last thing i have to do is to randomly generate pointmaps and images. the recognizing-part is all serverside. the only thing which runs clientside is capturing the strokes and send the pointmap to the server.