This project is not covered by Drupal’s security advisory policy.
Disclaimer: this module was developed with the help of AI 🤖 under the supervision. Reviews of the code are done with humans.
Proof of Work protects selected routes against scrapers and other automated traffic. Visitors without a valid pass are redirected to a challenge page. Once they pass the challenge, a signed cookie lets them through for the pass lifetime of that challenge.
The module is stateless: challenges, tokens and passes are HMAC-signed with the client IP address (IPv6 per /64) and a timestamp. No sessions, database tables or other storage are used.
Features
- Protect any route from the settings page, or from code with the
_proof_of_workroute option. - Pluggable challenges: enable them, order them by weight and configure each one, including its own pass lifetime.
- SHA-256 puzzle: the browser solves a SHA-256 puzzle in a Web Worker. Every extra bit of difficulty doubles the average solving time.
- Waiting time: a fallback without JavaScript that forwards the visitor after a waiting time.
- Protected pages stay cacheable in Drupal's internal page cache; visitors without a pass are still redirected to the challenge.
- Protected pages are sent with
Cache-Control: private, so shared caches (Varnish, CDN) do not store them. - Users with the Bypass proof of work challenge permission are never challenged.
- Theme-friendly: templates without classes and basic CSS with custom properties.
Requirements
- Drupal 11.1 or later.
- PHP 8.3 or later.
- HTTPS for the SHA-256 puzzle: browsers only expose the Web Crypto API on secure origins.
Installation
composer require drupal/proof_of_work drush en proof_of_work
Then go to Administration » Configuration » System » Proof of work to select the routes to protect and configure the challenges.
Good to know
- Passes are bound to the client IP address. Behind a reverse proxy or load balancer, configure
reverse_proxyinsettings.php, otherwise all visitors share the IP address of the proxy and a single pass works for everyone. - Anyone can choose the challenge without JavaScript, so the weakest enabled challenge determines the actual protection.
- Proof of work raises the cost per IP address for cheap scrapers and mass requests. It does not stop a determined attacker: native code solves the puzzle far faster than a browser. Combine it with rate limiting in your reverse proxy or web application firewall.
Writing your own challenge
Challenges are plugins with the #[ProofOfWorkChallenge] attribute. Extend ProofOfWorkChallengeBase and implement build(), verify() and buildVerifyResponse(). See the README for details.
Maintainers
Developed and maintained by SWIS.
Project information
- Project categories: Security
- Created by makertimswis on , updated
This project is not covered by the security advisory policy.
Use at your own risk! It may have publicly disclosed vulnerabilities.
