Preventing automated sign-ups

The Session goes through periods of getting spammed with automated sign-ups. I���m not sure why. It���s not like they do anything with the accounts. They���re just created and then they sit there (until I delete them).

In the past I���ve dealt with them in an ad-hoc way. If the sign-ups were all coming from the same IP addresses, I could block them. If the sign-ups showed some pattern in the usernames or emails, I could use that to block them.

Recently though, there was a spate of sign-ups that didn���t have any patterns, all coming from different IP addresses.

I decided it was time to knuckle down and figure out a way to prevent automated sign-ups.

I knew what I didn���t want to do. I didn���t want to put any obstacles in the way of genuine sign-ups. There���d be no CAPTCHAs or other ���prove you���re a human��� shite. That���s the airport security model: inconvenience everyone to stop a tiny number of bad actors.

The first step I took was the bare minimum. I added two form fields���called ���wheat��� and ���chaff������that are randomly generated every time the sign-up form is loaded. There���s a connection between those two fields that I can check on the server.

Here���s how I���m generating the fields in PHP:

$saltstring = 'A string known only to me.';$wheat = base64_encode(openssl_random_pseudo_bytes(16));$chaff = password_hash($saltstring.$wheat, PASSWORD_BCRYPT);

See how the fields are generated from a combination of random bytes and a string of characters never revealed on the client? To keep it from goint stale, this string���the salt���includes something related to the current date.

Now when the form is submitted, I can check to see if the relationship holds true:

if (!password_verify($saltstring.$_POST['wheat'], $_POST['chaff'])) { // Spammer!}

That���s just the first line of defence. After thinking about it for a while, I came to conclusion that it wasn���t enough to just generate some random form field values; I needed to generate random form field names.

Previously, the names for the form fields were easily-guessable: ���username���, ���password���, ���email���. What I needed to do was generate unique form field names every time the sign-up page was loaded.

First of all, I create a one-time password:

$otp = base64_encode(openssl_random_pseudo_bytes(16));

Now I generate form field names by hashing that random value with known strings (���username���, ���password���, ���email���) together with a salt string known only to me.

$otp_hashed_for_username = md5($saltstring.'username'.$otp);$otp_hashed_for_password = md5($saltstring.'password'.$otp);$otp_hashed_for_email = md5($saltstring.'email'.$otp);

Those are all used for form field names on the client, like this:

(Remember, the name���or the ID���of the form field makes no difference to semantics or accessibility; the accessible name is derived from the associated label element.)

The one-time password also becomes a form field on the client:

When the form is submitted, I use the value of that form field along with the salt string to recreate the field names:

$otp_hashed_for_username = md5($saltstring.'username'.$_POST['otp']);$otp_hashed_for_password = md5($saltstring.'password'.$_POST['otp']);$otp_hashed_for_email = md5($saltstring.'email'.$_POST['otp']);

If those form fields don���t exist, the sign-up is rejected.

As an added extra, I leave honeypot hidden forms named ���username���, ���password���, and ���email���. If any of those fields are filled out, the sign-up is rejected.

I put that code live and the automated sign-ups stopped straight away.

It���s not entirely foolproof. It would be possible to create an automated sign-up system that grabs the names of the form fields from the sign-up form each time. But this puts enough friction in the way to make automated sign-ups a pain.

You can view source on the sign-up page to see what the form fields are like.

I used the same technique on the contact page to prevent automated spam there too.

 •  0 comments  •  flag
Share on Twitter
Published on September 30, 2024 08:57
No comments have been added yet.


Jeremy Keith's Blog

Jeremy Keith
Jeremy Keith isn't a Goodreads Author (yet), but they do have a blog, so here are some recent posts imported from their feed.
Follow Jeremy Keith's blog with rss.