Quick answer
A proof-of-work challenge asks a client to perform a small computation and return the answer before it is allowed through. A real browser does this automatically in a fraction of a second with nothing to click, while a simple script cannot do it at all because it has no JavaScript engine. The point is not that the work is hard. It is that the cost falls on every new session, which is negligible for one visitor and ruinous for an attacker opening millions of them.
01How it works
The server returns a small page instead of the content, containing a puzzle. In the classic form, the browser must find a value that, hashed together with a seed the server issued, produces a hash starting with a required number of zero bits. There is no shortcut: the only method is to try values until one fits.
The browser runs that loop, submits the answer, and receives a token, usually in a cookie. Later requests present the token and skip the challenge, so the cost is paid once per session rather than per page. Implementations differ in the hash function, the token format and how long a token lasts, but this is the common core.
seed = 'a91f...' // issued by the server
difficulty = N // chosen by the server
let n = 0;
while (!hash(seed + n).startsWith(zeros(difficulty))) n++;
// submit n: the server verifies it with a single hash02Where the idea comes from
Computational puzzles as an anti-abuse tool go back to Cynthia Dwork and Moni Naor's 1992 work on combating junk mail. Adam Back proposed hashcash in 1997 and described it in his 2002 paper "Hashcash - A Denial of Service Counter-Measure": a sender searches for a hash with a set number of leading zero bits, and the recipient checks it with a single hash computation.
The same asymmetry drives today's web challenges. Open-source projects such as Anubis, released under the MIT licence, put browser challenges of this kind in front of websites specifically to slow the flood of automated requests from AI companies' crawlers, a form of web scraping that small sites struggle to absorb.
03Why it changes the economics
The asymmetry is the whole design. Solving costs a browser a brief computation once per session. Verifying costs the server a single hash. An attacker who wants to send a million requests without keeping sessions must solve a million puzzles, which means running a JavaScript engine, or an equivalent solver, a million times.
That turns a cheap attack into an expensive one. HTTP flood tooling is built to send requests as fast as possible with minimal per-request cost; requiring real work per request removes exactly the advantage the attacker was relying on.
| Real visitor | Flood tooling | |
|---|---|---|
| Challenges to solve | One per session | One per request without a valid token |
| Needs a JS engine | Already has one | Must run one, or a solver, every time |
| Practical cost | A brief pause, once | Far more CPU than the attack was worth |
04Difficulty in numbers
Difficulty is the number of leading zero bits the hash must have, and the expected work doubles with every extra bit. That is plain probability, not a property of any product: a random hash has a one in 2 to the power of k chance of starting with k zero bits.
Hashcash used 20 bits as its standard stamp, about a million attempts. In a browser the wall-clock cost of a given difficulty depends heavily on the device, and that spread is the real constraint: optimised native code or a GPU computes hashes far faster than JavaScript on an old phone, so raising difficulty hurts the slowest real visitors long before it hurts a well-equipped attacker.
Memory-hard functions narrow that gap. Argon2, standardised in RFC 9106 for password hashing and proof-of-work applications, is designed to fill memory quickly, which specialised hardware cannot shortcut as easily as it can a plain hash.
| Leading zero bits | Expected attempts | Work relative to 8 bits |
|---|---|---|
| 8 | 256 | 1× |
| 16 | 65,536 | 256× |
| 20 | 1,048,576 | 4,096× |
| 24 | 16,777,216 | 65,536× |
05Compared with a CAPTCHA
A traditional CAPTCHA asks a person to do something: identify images, retype distorted characters, answer a simple sum, click a box. It works, but every legitimate visitor pays with an interaction. The W3C's note on the inaccessibility of CAPTCHA documents how visual and audio puzzles shut out people who are blind, deaf or dyslexic, while better recognition software keeps eroding the security they offer; it cites research that cracked Google's audio reCAPTCHA with a 90% success rate using Google's own speech recognition.
A proof-of-work challenge asks the browser instead of the person. Nothing is clicked and usually nothing is noticed beyond a brief delay. It does not prove humanity, since a headless browser passes, but it does prove that a full browser engine ran, which stops the large class of tooling that never runs one. That is why it sits comfortably inside broader bot management rather than replacing it.
06When a proof-of-work challenge fits
| Situation | Good fit? | Why, or what to use instead |
|---|---|---|
| A flood of requests for HTML pages | Yes | Every request without a valid token costs the sender real work |
| Login and sign-up forms | Yes, before the password check | Automation pays per attempt instead of your database; see credential stuffing |
| JSON APIs used by apps and integrations | No | These clients do not run pages; use keys, tokens and per-client limits |
| Search engine crawlers | No | Verify them by reverse DNS or published ranges, as Google documents for Googlebot; see web crawlers |
| Uptime monitors and webhooks | No | Authenticate them or allow them explicitly |
| Headless-browser bots | Partly | They can solve it; behaviour, rate and reputation have to do the rest |
07What it does not do
- It does not prove a human is present: a headless browser solves it like any other browser
- It does not stop a determined attacker with hardware to spare; it makes every request cost them, which is the realistic goal
- It cannot help clients that never run JavaScript, so APIs and machine clients need their own controls
- A solved token is only as strong as its lifetime and scope: a long-lived token that works anywhere can be shared across many machines
- It costs the slowest real devices the most, which is why difficulty cannot simply be turned up
Questions
Frequently asked questions
Sources
Sources and verification
Expected-attempt figures computed as 2 to the power of the number of leading zero bits.
- 01Hashcash - A Denial of Service Counter-Measure (Adam Back, 2002) · Satoshi Nakamoto Institute
- 02Hashcash · Wikipedia
- 03Inaccessibility of CAPTCHA: Alternatives to Visual Turing Tests on the Web · W3C
- 04Anubis (TecharoHQ/anubis) · Techaro
- 05RFC 9106: Argon2 Memory-Hard Function for Password Hashing and Proof-of-Work Applications · IETF
- 06Verify requests from Google crawlers and fetchers · Google for Developers
Last updated