Protecting Your Website Forms With Serverless CAPTCHA

Click here if you are not a robot

If you put a form on one of your web pages, it is wide open to being spammed by anyone on the internet, for their own nefarious purposes. To reduce the noise, web developers often employ a CAPTCHA widget, which tries to ensure that the form filler is human.

The contact form at http://glynnbird.com/contact.html

As well as the normal form fields, the user will have to tick a “I am not a robot” tick box. Sometimes, they will be asked to solve a numeric, audio or visual puzzle.

Architecture of a serverless Captcha
  1. The web page’s JavaScript calls the CAPTCHA service to authorise the form submission.
  2. The form is submitted to our server-side script. We are passed the form data and the data the client-side script got from its call to the CAPTCHA API.
  3. The server side script calls the CAPTCHA API with our server-side ID, the client IP address, and the data we were passed. If the data checks out, we are good to accept the form submission.

CAPTCHA on static websites

My personal homepage, which some say is the fastest website in the world, is a static site built with Jekyll and hosted on GitHub pages. If I’m going to have a contact form, protected by CAPTCHA, then I’m going to need some server-side scripting.

For this we’re going to use IBM Cloud Functions, IBM’s serverless platform, but first we’re going to need to sign up for a CAPTCHA service.

Sign up for reCAPTCHA

First, sign up for the ReCAPTCHA service, entering your site’s domain name. (Don’t forget to add “localhost” as well as your production domain name if you’re going to develop locally!) You will be supplied with two keys: one for your client-site HTML and the other for your server-side script.

Build a form

Our form is as simple as can be. Just a plain HTML form with a submit button.

You’ll need to replace RECAPTCHA_KEY with your ReCAPTCHA service's client-side key. We don't know the form's action URL yet. That comes next.

Cloud Functions code

When working with a serverless platform, your code can be nice and simple because the platform handles almost everything for you — you only need to write the code that will execute when each event (in this case a form fill) occurs.

Here’s our complete code:

Its job is to:

  • Collect the caller’s IP address, the g-recaptcha-response field from the submitted form and the ReCAPTCHA secret and send it to the ReCAPTCHA API.
  • If this request succeeds we can trust the data in the form and bounce the user to a static success page.
  • If the request fails, we can ignore the form submission and bounce the user to a static failure page.

Assuming I have the bx wsk installed and configured, then deploying the code is easy:

First we write our configuration into three environment variables, which is bundled into an OpenWhisk “package” called “mysite”. We then upload our JavaScript action into this package and finally ask for the URL it’s being served out on. It should look something like:

This is the URL that goes into the action attribute of your HTML form. That’s it!

Make your serverless script do something

If you’ve been paying attention, you may have noticed that the script, once it’s verified that the CAPTCHA submission is valid, doesn’t actually do anything useful with the form data. That’s easily fixed. You could:

It’s up to you!

Why serverless?

You don’t need to use a serverless platform to handle your form submissions, but it does have several advantages in running your own web service:

  • You don’t have to pay to run a server 24x7 that you have to manage. Just upload your code to the serverless platform, and it will invoke your code when it’s needed.
  • IBM Cloud Functions has a generous free tier. If you’re not expecting many form fills, then you may not have to pay anything.
  • Your code is smaller because you don’t need to code the web server, routing or queuing — only the code that does the work.
  • Scaling is the platform’s responsibility. If a burst of thousands of form fills arrive in a short space of time, the platform will scale up to cope with the demand.

If you want to see this in action, visit my homepage, click on the contact button, and fill in my form. I should get your message in my Slack channel!