Hey, howdy, hallo,
For the service I’ve been building for the past 8+ months, I needed some way to protect the login and registration page from automated attacks. I couldn’t use a third party (like Cloudflare) as I’m going for a privacy first, self-hosted (on Hetzner VPS’s) approach.
One of the most common options for protecting a login page is a third-party CAPTCHA service. The annoying 9 photos that you need to click and select the correct object or whatever it asks for. Besides wasting human life, these are extremely annoying and can make a site less accessible for users. Instead, I opted for a Proof Of Work challenge. I found it pretty interesting after figuring out exactly how it worked, so I thought I would share.
Let me start off by saying this is an overview, so I’m sure some specifics will be missing, but it should help you with a general understanding.
Proof Of Work, or PoW for short, requires that the user accessing the resource (you accessing the site) preforms some sort of work before you can continue. Typically, a malicious actor looking to spam your login or registration page doesn’t want to waste their compute resources having to do meaningless work. While it will take seconds for your singular computer, their botnet will waste numerous resources.
That’s not to say it’s foolproof either, it’s just about not being the easiest site to abuse. A motivated attacker could still bypass it and continue on with their attack.
One major concept you need to understand before the explanation is hashes. A hash is a function that takes an input, and outputs a digest.
There’s a tool called CyberChef that makes this easy to visualize. If you go to this site, I input the string dog and got the value cd6357efdd966de8c0cb2f876cc89ec74ce35f0968e11743987084bd42fb8944. Mess around changing the input to see how the output changes.
No matter how many times you hash dog using the same algorithm, it will always come out to the same value. Hashes are a one-way function, which makes them a good way to store passwords in a database, it’s also useful for verified file integrity. If you ever downloaded an APK from a site (such as the Signal apk), you might have seen a fingerprint (hash) associated with it.
The challenge starts with the server generating a unique prefix (random string) to challenge the session. Let’s use "sideofburritos" as the example prefix.
The server stores this prefix and sends it to the client.
The client executes the client-side JavaScript provided by the site. The JavaScript contains instructions that tell the client how to solve the challenge
Take the prefix (sideofburritos), append some number to it, so that the resulting hash starts with 4 zeros.
89abcdef12345678 (Does not meet the condition)fedcba9876543210 (Does not meet the condition)00001234abcd5678 (Meets the condition)What happened was your client needed to hash 531 strings to arrive at the answer that would solve the challenge.
The client sends the answer back to the server, in this case 531.
The server validates the answer by computing the hash ("sideofburritos"+"531") and if it’s correct, allows the client to proceed. If it’s not correct, the client will receive a new challenge to solve.
There’s always compromises that need to be made for publicly accessible sites. It’s an interesting landscape because the first thing you need to do is treat every user as if they’re hostile. Compared to other businesses, like a restaurant, where that usually isn’t the case.
This is only one sort of challenge that other companies implement. A company like Cloudflare will perform various operations to check different aspects of the browsing session when you see the challenge page + a PoW challenge.
Hopefully, the next time you see one of those pages show up when you visit a site, you can have a bit of a better of an understanding of what’s going on.
-Josh
This site is an interesting collection of stuff.
"Eat the Frog"
(my new favorite way to remember to get the most difficult task done first)
Reply with one sentence on a topic you find intriguing and are curious about.