1

Hello information security stack exchange!

I made a captcha application in PHP. It's certainly not a great idea to do so, but I was bored and I wanted to learn about Bézier curves and Bresenham line algorithms. Therefore let's disregard that my application is not really secure against serious cracking attempts that try to crack it with OCR methods.

To my question: My app basically writes every two hours 10 new captcha images in a directory (with a cronjob). If there are more than 1000 images in the directory, it replaces the oldest 10 images with the newly generated ones. So there is always a pool of 1000 captchas that slowly but steadily refreshes. All the captcha images have a 18 char long random filename and I have a associative array in my database that maps the filenames as keys to the captchas value.The array looks something like this:

Array
(
    [captchas/6aab1bfa796ff02b48] => knfbb
    [captchas/3f53d6eefb535233f0] => HnHnQ
    [captchas/436e3567bdbb987b45] => HaEQS
    [captchas/916ac5d684f17f1677] => aQnWE
    [captchas/fb6267bfb72ff37fdb] => fHWya
    [captchas/3fb748ba654b98088e] => WkSEG
    [captchas/71ea9d1d88a245c1e3] => HkQXy
    .
    .
    .
);

Whenever my captcha application hooks into a comment form or login form in order to inject a captcha image, it choses a random captcha from the pool and let's the user try to solve it.

Now you might already see the security drawback: How can I make sure that a user doesn't download all captchas and maps them manually (Decipher the captcha manually and map it to the md5-sum of the png-image) to it's corresponding string value and then spams my site with a script?

The attacker would just need to download around 20 percent of all images and then he had a average success rate of, errhh, yeah 20%, in succeeding to spam my site (The script would just refresh the form as long as it serves a captcha that it knows).

How would you defend against such attacks? (Under the condition that my app architecture doesn't change: I can't generate captchas on demand, it would be too slow).

I thought of blacklisting IP addresses (parsing apache2 access_log IP addresses) from my site that visit my site more than 100 times per 5 minutes, but this could easily be circumvented by proxies.

6
  • How long does it take you to generate a single captcha? Oct 30, 2013 at 21:47
  • use pragmatic approach: google.com/recaptcha
    – valentinas
    Oct 30, 2013 at 22:53
  • It takes me around 0.3 seconds to generate one captcha. But it's certainly too long. When 50 users would be on the page the site would crumble... Oct 30, 2013 at 22:56
  • @valentinas: No. Oct 30, 2013 at 22:57
  • @NikolaiTschacher, you can't put up a loading gif while the CAPTCHA generates? Oct 30, 2013 at 23:03

4 Answers 4

3

The issue seems to be exposing the url of the image and there by alerting the user to the possible repeated captcha.

Have you considered using a php script to serve the image? Perhaps using the session to identify which captcha image to serve. Although a bit slower than the client getting the image directly, it does provide a means for obscuring which file the user is loading.

1
  • Another good way to obscure the source for an image is to return it in the HTML as a data URL.
    – Owen
    Nov 6, 2013 at 12:28
2

Instead of all that storage mess. Why not to use PHP GDI?

http://stackoverflow.com/questions/13267846/how-to-add-text-to-an-image-with-php-gd-library

Pictures can be a good idea. you can leave them as they are..just combine text and image, and that could increase the difficulty in guessing the right captcha.

If you want more security, ask a question..lets say.

What day was it 4 days from now? or How do you spell this word backwards "stackexchange"?

2
  • Good idea. But I am afraid that I will repel users with too many hindrances from posting comments. Oct 31, 2013 at 12:00
  • I would personally find a human answerable question a little easier than a captcha, and it also avoids problems with screen readers for blind users.
    – Owen
    Nov 6, 2013 at 12:25
2

Firstly, kudos on making this just for the sake of it, not enough people just tinker around nowadays. ;)

I'd say the best approach is to generate on the fly - unless traffic to your site is very heavy, or your server is particularly overloaded already. It eliminates all issue of the hashing of the value, and downloading the image and such, and in most cases, won't put too much load on your server really.

Generating on the fly does provide an extra challenge though, it provides the user with an address they can load which adds extra load to the server, in excess of just reloading an average page, so implementing limits on how much an IP can load these images might be a good idea, again depending on traffic to your site.

Of course the real best answer is to use one of the captcha generation and serving systems, but that's a little out of the experimental spirit you seem to have adopted.

2

A better approach is 'test it'. CAPTCHAs are all about a race, as in "who can make a puzzle that's AI-resistant yet simple enough to not annoy the legitimate users?" But no matter what your technology, a dedicated attacker can eventually defeat it, if they have enough motivation or reward for doing so. Therefore, no CAPTCHA is ever going to be perfect and stay perfect. If you can accept that, then you can aim for "good enough".

So in your case, you've established a two-hour sliding window. If someone steals a dozen filenames from you right now, that still won't benefit them two hours from now. I'd seriously consider that "good enough to deploy". Of course, you don't deploy it in a vacuum. You still need to monitor it for abuse, so monitor it. If a spammer gets through, do a bit more research to determine if he was a human or a bot.

Start deriving value from it today, and learn some real world lessons from it. That's better than leaving it on a shelf and asking stackexchange "is it any good?"

2
  • The two hours is misnomer - it is something like 200 hours before file names are cycled out. He is generating 10 captchas every 2 hours, that take out the 10 oldest from a block of 1000. So to cycle out a file name would take 100 regeneration cycles - ie, 200 hours.
    – Kami
    Nov 7, 2013 at 10:11
  • @Kami, that doesn't invalidate the general approach of "test it". As a matter of fact, it's a good lever for him to push on. He's obviously concerned about performance, so he can start with a lengthy regen period, and shorten it only if it proves to be a problem. Nov 7, 2013 at 13:42

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .