How To Implement A Captcha In An Erlang Web Application

In this post, I’ll show you a way to implement a Captcha challenge-response test in an Erlang web application. This method is a simplified version of what we use in our Business Management application

It takes part in an ongoing series of Erlang tutorials that can be found on our Erlang website

captcha

I’ll assume that you have a working Erlang node and a fresh export of the Mochiweb svn (Read our guide to set up Erlang and Mochiweb on Ubuntu if not already done).

So let’s start by installing ImageMagick:

sudo apt-get install imagemagick

Then, we’ll create a brand new app named ‘myapp’ using the new_mochiweb.erl script (Discover our video tutorial to start developing web apps on Erlang if you feel lost).

Here is a quick recap :

~/mochiweb/scripts/./new_mochiweb.erl myapp ~/
cd ~/myapp && make clean && make && ./start-dev.sh

At this point we should be able to browse this url http://127.0.0.1:8000

Now it’s time to write some Erlang code into our myapp_web.erl controller both in the GET and in the POST part of the case statement.

Briefly said, here is the big picture:

Starting with a modified index.html page (see the first step hereunder), we will call our application server at “/captcha” with the GET method.

The server will be in charge of :

  • Generate a random alphanumeric string,
  • Build a new image based on this string by calling Imagemagick through the os:cmd function. The image will be temporarily stored in the /tmp directory and will be deleted as soon as it is read,
  • Encrypt the string content by computing a SHA MAC message code based on a random generated key that we will store in ram
    using Ets

The newly created image along side with a cookie containing the SHA message will be sent back to the browser.

We will use the same “/captcha” url but this time with the POST method in order to submit a form with the code entered at the client.

A check will be performed at the server side using the cookie information, the code and the public key stored in ram.

Let’s go for real:

Step 1 – The HTML

Juste copy paste the following html replacing the content of:

~/myapp/priv/www/index.html

Step 2 – One for the GET, One for the POST

Here, the code speaks for itself, the most interesting part will be explained in the next step.

Two remarks though. First, in the ‘GET’ part, we are returning a response with a “image/png” content-type. Secondly, in the POST part, you will find an example of code for redirecting a request to another location.

We edit this file:

~/myapp/src/myapp_web.erl

and here is the code we should end with.

Step 3 – mycaptcha module

Now, the cool part ;)

We are going to create a new module:

~/myapp/src/mycaptcha.erl

and paste the following lines in it.

First there is the new() function which is used to create our ‘Captcha’. We use the ets module in order to store the tuple containing the randomly generated binary key. This key will be used to check if the string provided by the user and the cookie content match.

This new storage will be set as public, which means that the info will be accessible by subsequent calls.

Secondly, we build a new filename based on the current local time and we generate a random suite of alphanumerical characters. For this purpose, we use the generate_rand(Length) function which is accepting as the only argument the length of the string that we want to generate.

Then, we write the Imagemagick command for building a PNG image with a transparent background and save the result in /tmp/filname.png. We read and store the entire content of the file in a variable and delete the PNG.

Finally, using the crypto module, we build the SHA message based on the public stored key and our 5 characters string. The controller will be in charge of building the cookie and of sending back the binary image to the client.

Note : I’m doing some additional math on the message I want to encrypt in order to make things a little bit more difficult to the potential guessers. Since strings are considered as a list of integer in Erlang, it’s quite easy to sum the total of our characters for instance and insert the result into the message we want to encrypt. When the Captcha will be checked, we will take care of extracting this noisy info before the match.

It’s time to test it all:

cd ~/myapp && make

Browse to http://127.0.0.1:8000 and you should see a nice distorted image with an input field below (cfr top). We can click the image to get a new one, or enter the code and submit the form. If the check is ok, a “Cool!” message will be displayed on the screen.

Enjoy !

Note about Captcha and Spammers: Captcha is not a 100% secure method even if it remains a good way to protect your application from bot users. Spammers have recently succeeded at cracking Windows Live Hotmail and Google, so be sure to add some kind of algorithm to lower the risk.

Comments are closed.