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_work route 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_proxy in settings.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.

Supporting organizations: 

Project information

  • Project categories: Security
  • Created by makertimswis on , updated
  • shield alertThis project is not covered by the security advisory policy.
    Use at your own risk! It may have publicly disclosed vulnerabilities.

Releases