Creating a Slider Captcha to Eliminate Spam
For quite a while, I have been getting very annoying spam emails via the contact form on my website. It only required solving a simple math equation to submit a contact request, which didn't prove very effective. The spammers didn't even bother to visit the page with the contact form. Instead, they figured out which POST request was required and I assume they just tried random numbers until they guessed the correct solution.
So, after months of deleting multiple spam emails per day, I decided to do something against it and created a slider captcha to reduce the spam.
You can find many different types of captchas. First of all, there are the captchas with distorted words or characters, which may or may not stop bots, but they are also quite difficult to solve for most humans. Then there are ones with "click on all images with a motorcycle in it" and the ones where you only have to click a checkbox and "the algorithm" figures out whether you are a human or not. Both of these would have required using a third-party solution and I try to minimize my usage of third-party tools whenever possible.
The type of captcha that seemed the easiest to create was a slider captcha where you have to slide a puzzle piece in an image to the correct position.
Creating a Slider Captcha
For the image and the sliding puzzle piece, I am using a canvas element because it can be redrawn efficiently and I love canvases. While there are default HTML sliders they look terrible, so I created a custom slider element, which is just a div within another div. The inner div, i.e. the slider knob, needs three event listeners for mousedown, mousemove, and mouseup. The most interesting one is mousemove where we need to figure out the distance the mouse has moved since it was clicked and use that offset to move the slider and the puzzle piece. When the mouse button is released (mouseup), we have to check whether the puzzle piece is at the correct location and if it is, trigger the onsuccess callback of the slider captcha class and onfail otherwise.
Here is the full code of the slider captcha class:
The slider captcha in action:
Using the Captcha to Prevent Spam
As mentioned before, one of the biggest problems with my old contact form was that the spammers could create spam messages by sending POST requests without visiting the page. This is something I wanted to avoid with the new captcha-based solution. To do this, two random position values are created on the server using PHP and stored in the session. These positions are then used to initialize the slider captcha. When it is solved correctly, the values are added to the form and it is submitted.
On the server, we have no way to verify the correctness of the captcha. All we see is a POST request that may have been sent by solving the captcha or just as likely from a spammer's script. However, we can check whether the contact page was visited by checking whether the session variables exist and whether the POST values match them. This makes guessing the correct values for the POST request very unlikely. With the 0.0001 error margin on both values, there are 1,000,000 possibilities.
How Effective Is It?
Unfortunately, captchas aren't perfect. Most solutions on the market can be solved automatically, and even if one of them is unsolvable right now, it won't be in a few months. The first results that come up when you google slider captcha, are ways to automatically solve them. This means that my simple homemade solution can also be circumvented with a script. However, my custom solution has an advantage compared to using a popular third-party captcha. The scripts that spammers use can likely solve the captchas from the market leaders. But it's unlikely that the same script that can solve a popular slider captcha can also solve mine. Mine is almost certainly easier to break, but it would require at least a little bit of work to do it. Objectively, it's not worth it because I am literally the only one who uses it. However, there was no reason to reverse engineer my old solution either, so it's probably only a matter of time.
by Christian - 06.06.2022 - 16:02