| src | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| example-config.yaml | ||
| LICENSE | ||
| README.md | ||
| rustfmt.toml | ||
Mesozoa
Mesozoa is a small animal living between a reverse-proxy and a server, protecting the server from crawlers by forcing the browser to run proof of work.
Why?
Why not Anubis? Because it provides no build instructions and only supports Docker.
Why not using Realm completely? Because the hook system is useless and only allows filtering.
And because it looked like a fun little project.
Install
Install rustup and a nightly Rust toolchain.
cargo build --release
Must be used behind a reverse proxy providing X-Forwarded-For.
./target/release/mesozoa -c example-config.yaml
Challenge protocol
Challenge generation
Sent by the server as a cookie.
secret: chosen randomly at startupsalt: chosen randomly each timetimestamp: UNIX time in seconds, 64 bits, big endianua:User-Agentfrom request headerip:X-Forwarded-Forfrom request header (client's IP)
set-cookie: mesozoa-challenge=BASE64(salt || timestamp || SHA3-256(secret || salt || timestamp || ip || "/" || ua))
Where BASE64 is URL-safe unpadded.
Challenge verification
Request must contain both cookies mesozoa-challenge and mesozoa-proof.
Server checks challenge is correct and timestamp not too old.
cookie: mesozoa-proof=nonce
hash = SHA2-256(nonce || challenge)
Client must find a nonce matching /[0-9a-zA-Z_-]{8}/ such that hash starts with at least some number of zeros (in binary representation, MSB-first).
Security
Network handling and HTTP parsing
This implementation uses cheap tricks and regexes, is probably not fully compliant to HTTP specs, etc. You should probably not expose it directly to an open network. Please use it behind a safer reverse proxy like Apache or Nginx.
Length-extension attack
SHA3 (used as a MAC in the challenge cookie) is not vulnerable. Values in the hash are either fixed-length, safe, or delimited.
SHA2 (used for PoW) is vulnerable but nonce is at the beginning so this is not a problem.
PoW
I would like a better PoW: memory-bound and ideally non-parallel. Cuckoo seems a good candidate.
Contribution
Patches and forks are welcome. Send an e-mail to tuxmain ât zettascript ðøt org.
If people are interested, I may switch to a public forge like Codeberg.
The "A" in GNU AGPL means that if you host a publicly available instance of a modified version, then you should also make the modified source code available to users. For example, this can take the form of a link to a repository in the challenge page or in the protected website. As the challenge page's source code is directly distributed by the server, you can modify it independently. (unless adding a compiled object, like WASM. Then you have to publish its source.) Configuration file can be modified and kept secret, of course.
License
GNU AGPL v3, CopyLeft 2025 Pascal Engélibert (why copyleft?)
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, version 3 of the License.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along with this program. If not, see https://www.gnu.org/licenses/.