The Bot Barrier plugin for Caddy enforces a browser-based computational challenge before granting access to HTTP resources. It helps mitigate bot traffic while imposing minimal delays on legitimate users.
This plugin introduces a middleware that:
- Mitigates Bot Traffic: Requires clients to solve a computational challenge before proceeding.
- Stateless Design: Operates without server-side session storage.
- Customizable Complexity: Adjust the difficulty of the challenge to balance security and user experience.
- Custom Templates: Use your own HTML templates for the challenge page.
- Automatic Verification: The challenge is solved automatically by the browser using JavaScript.
- Time-Limited Challenges: Challenges expire after a configurable duration to prevent replay attacks.
- Cookie-Based Validation: Uses cryptographically signed cookies to verify challenge solutions.
-
Initial Request (No Cookies) Client sends an HTTP request → Middleware detects missing or invalid challenge cookies.
-
Challenge Page Server returns an HTML page containing embedded JavaScript and a cryptographically signed challenge (seed + HMAC).
-
Client Solves Challenge JavaScript computes a nonce so that:
SHA512(seed || nonce)
has at leastN
leading zero bits (complexity
). -
Cookies Set by Client Once solved, the client sets:
__challenge_seed
: The original challenge (hex-encoded).__challenge_solution
: The found nonce (hex-encoded).__challenge_mac
: HMAC(seed, secret) to authenticate seed origin.
-
Page Reloads Automatically Browser reloads → Middleware now verifies all three cookies.
-
Access Granted If the solution is valid and timely, the request proceeds to the next handler.
-
secret
: The secret key used to generate and validate HMACs for the challenge seed.- Default: A random secret is generated during provisioning if not explicitly provided.
- Usage Tip: Use a long, random string for better security.
- Caddy Placeholder Support: Placeholders like
{file./path/to/secret.txt}
are supported, but only during initialization. The resolved value is used for the lifetime of the module.
-
complexity
: Defines the number of leading zero bits required in the hash (SHA512(seed || nonce)
) for the challenge to be considered solved.- Default:
16
. - Higher values increase the difficulty of the challenge, making it harder for bots to solve quickly.
- Caddy Placeholder Support: You can use placeholders like
{vars.bot_barrier_complexity}
to dynamically set the complexity for each HTTP request.
- Default:
-
valid_for
: Specifies the duration for which a challenge seed is valid.- Default:
10m
(10 minutes). - After this duration, the client must solve a new challenge.
- Default:
-
seed_cookie_name
: The name of the cookie that stores the challenge seed.- Default:
__challenge_seed
.
- Default:
-
solution_cookie_name
: The name of the cookie that stores the solution (nonce) found by the client.- Default:
__challenge_solution
.
- Default:
-
mac_cookie_name
: The name of the cookie that stores the HMAC of the challenge seed.- Default:
__challenge_mac
.
- Default:
-
template
: Path to a custom HTML template for the challenge page.- Default: A built-in embedded template is used if no custom template is specified.
:443 {
handle {
@private {
remote_ip private_ranges
}
vars bot_barrier_complexity 18
vars @private bot_barrier_complexity 14
bot_barrier {
secret "{file./path/to/secret.txt}"
complexity {vars.bot_barrier_complexity}
valid_for 15m
template /path/to/custom_template.html
}
respond "Welcome!"
}
}
The complexity
parameter defines the number of leading zero bits required in the hash (SHA512(seed || nonce)
) for the challenge to be considered solved. This directly controls the difficulty of the computational challenge.
Complexity | Approx. Attempts | Est. Time (Desktop) |
---|---|---|
12 | ~4,000 | <50 ms |
14 | ~16,000 | 100–200 ms |
16 | ~65,000 | 300–500 ms |
17 | ~130,000 | 600–800 ms |
18 | ~260,000 | 1–2 seconds |
20 | ~1 million | 5–10 seconds |
22 | ~4 million | 20–40 seconds |
The valid_for
configuration determines how long a seed is considered valid.
Example:
bot_barrier {
secret "mysecret"
complexity 18
valid_for 30m
}
You can provide a custom HTML template for the challenge page using the template
option. If not specified, a default embedded template is used.
bot_barrier {
template /path/to/custom_template.html
}
The template must include a placeholder for the embedded JavaScript:
<script>{{ .Script }}</script>
:8080 {
bot_barrier
respond "Hello, human!"
}
:8080 {
@private {
remote_ip private_ranges
}
vars bot_barrier_complexity 18
vars @private bot_barrier_complexity 0
bot_barrier {
complexity {vars.bot_barrier_complexity}
valid_for 60m
template ./custom_challenge_template.html
}
respond "Access granted!"
}
This project is licensed under the Apache License 2.0. See the LICENSE file for details.
- Caddy for providing a powerful and extensible web server.