Skip to content

Commit 7c4f516

Browse files
maxlerebourgdavid-garcia-garciamonisnap-maxmathieuHa
authored
✨ add custom selfhosted captcha (#259)
* ✨ Add wicketkeeper captcha * ✨ Anom config * 🍱 fix readme * 🍱 fix lint * 🍱 fix lint * 🍱 normalize * 🍱 fix lint * 🍱 fix lint * ✨ Add env for RemediationStatusCode (#250) * ✨ Add env for defaultStatusCode * 📝 doc * ✨change name of the parameter * 🔧 Add config check * fix lint * 📈 Report traffic dropped metrics to LAPI (#223) * Initial implementation * fix * fixes * Fixes * xx * progress * xx * xx * xx * fix linter * Progress * Fixes * xx * xx * Remove trace logger * Last fix * fix lint * fix lint * fix lint --------- Co-authored-by: Max Lerebourg <[email protected]> * ✨ Anom config * 🍱 fix readme * 🍱 fix lint * 🍱 normalize * 🍱 fix lint * 📝 Add documentation * 📝 Fix example and makefile and doc for wicketkeeper * 🍱 fix last things * 🍱 add disclaimer to use maxlerebourg docker image * 🍱 Use official wicketpeeker image * 🍱 revert unnecessary code * 🍱 fix --------- Co-authored-by: David <[email protected]> Co-authored-by: max.lerebourg <[email protected]> Co-authored-by: mhx <[email protected]>
1 parent 734975c commit 7c4f516

File tree

13 files changed

+649
-46
lines changed

13 files changed

+649
-46
lines changed

Makefile

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,16 @@ run_tlsauth:
4141
docker compose -f examples/tls-auth/docker-compose.yml up -d --remove-orphans
4242

4343
run_appsec:
44-
docker compose -f examples/appsec-enabled/docker-compose.yml up -d
44+
docker compose -f examples/appsec-enabled/docker-compose.yml up -d --remove-orphans
45+
46+
run_custom_captcha:
47+
docker compose -f examples/custom-captcha/docker-compose.yml up -d --remove-orphans
4548

4649
run_captcha:
47-
docker compose -f examples/captcha/docker-compose.yml up -d
50+
docker compose -f examples/captcha/docker-compose.yml up -d --remove-orphans
4851

4952
run_custom_ban_page:
50-
docker compose -f examples/custom-ban-page/docker-compose.yml up -d
53+
docker compose -f examples/custom-ban-page/docker-compose.yml up -d --remove-orphans
5154

5255
run:
5356
docker compose -f docker-compose.yml up -d --remove-orphans
@@ -96,8 +99,9 @@ clean_all_docker:
9699
docker compose -f examples/redis-cache/docker-compose.yml down --remove-orphans
97100
docker compose -f examples/trusted-ips/docker-compose.yml down --remove-orphans
98101
docker compose -f examples/tls-auth/docker-compose.yml down --remove-orphans
99-
docker compose -f examples/appsec-enabled/docker-compose.yml down --remove-orphans
102+
docker compose -f examples/appsec-enabled/docker-compose.appsec-enabled.yml down --remove-orphans
100103
docker compose -f examples/captcha/docker-compose.yml down --remove-orphans
104+
docker compose -f examples/custom-captcha/docker-compose.yml down --remove-orphans
101105
docker compose -f examples/custom-ban-page/docker-compose.yml down --remove-orphans
102106
docker compose -f docker-compose.local.yml down --remove-orphans
103107
docker compose -f docker-compose.yml down --remove-orphans

README.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ The following captcha providers are supported now:
3939
- [hcaptcha](https://www.hcaptcha.com/)
4040
- [recaptcha](https://www.google.com/recaptcha/about/)
4141
- [turnstile](https://www.cloudflare.com/products/turnstile/)
42+
- [custom/wicketkeeper](https://github.com/a-ve/wicketkeeper)
4243

4344
There are 5 operating modes (CrowdsecMode) for this plugin:
4445

@@ -465,7 +466,19 @@ make run
465466
- Used only in `alone` mode, scenarios for Crowdsec CAPI
466467
- CaptchaProvider
467468
- string
468-
- Provider to validate the captcha, expected values are: `hcaptcha`, `recaptcha`, `turnstile`
469+
- Provider to validate the captcha, expected values are: `hcaptcha`, `recaptcha`, `turnstile` or `custom`
470+
- CaptchaCustomJsURL
471+
- string
472+
- If CaptchaProvider is `custom`, URL used to load the challenge in the HTML (in case of hcaptcha: `https://hcaptcha.com/1/api.js`)
473+
- CaptchaCustomValidateURL
474+
- string
475+
- If CaptchaProvider is `custom`, URL used to validate the challenge (in case of hcaptcha: `https://api.hcaptcha.com/siteverify`)
476+
- CaptchaCustomKey
477+
- string
478+
- If CaptchaProvider is `custom`, used to set class name of the div used by captcha provider (in case of hcaptcha: `h-captcha`)
479+
- CaptchaCustomResponse
480+
- string
481+
- If CaptchaProvider is `custom`, used to set the field in the POST body from the captcha.html to Traefik (in case of hcaptcha: `h-captcha-response`)
469482
- CaptchaSiteKey
470483
- string
471484
- Site key for the captcha provider
@@ -690,6 +703,8 @@ docker exec crowdsec cscli decisions remove --ip 10.0.0.10 -t captcha
690703

691704
#### 10. Using Traefik with Custom Ban HTML Page [examples/custom-ban-page/README.md](https://github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin/blob/main/examples/custom-ban-page/README.md)
692705

706+
#### 11. Using Traefik with Custom Captcha Whiketkeeper[examples/custom-captcha/README.md](https://github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin/blob/main/examples/custom-captcha/README.md)
707+
693708
### Local Mode
694709

695710
Traefik also offers a developer mode that can be used for temporary testing of plugins not hosted on GitHub.

bouncer.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,13 +240,18 @@ func New(_ context.Context, next http.Handler, config *configuration.Config, nam
240240
Timeout: time.Duration(config.HTTPTimeoutSeconds) * time.Second,
241241
},
242242
config.CaptchaProvider,
243+
config.CaptchaCustomJsURL,
244+
config.CaptchaCustomKey,
245+
config.CaptchaCustomResponse,
246+
config.CaptchaCustomValidateURL,
243247
config.CaptchaSiteKey,
244248
config.CaptchaSecretKey,
245249
config.RemediationHeadersCustomName,
246250
config.CaptchaHTMLFilePath,
247251
config.CaptchaGracePeriodSeconds,
248252
)
249253
if err != nil {
254+
log.Error("CaptchaClient not valid " + err.Error())
250255
return nil, err
251256
}
252257

examples/appsec-enabled/docker-compose.appsec-enabled.yml

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
version: "3.8"
2-
31
services:
42
traefik:
53
image: "traefik:v3.0.0"
@@ -36,7 +34,7 @@ services:
3634
# Definition of the router
3735
- "traefik.http.routers.router-foo.rule=PathPrefix(`/foo`)"
3836
- "traefik.http.routers.router-foo.entrypoints=web"
39-
- "traefik.http.routers.router-foo.middlewares=crowdsec@docker"
37+
- "traefik.http.routers.router-foo.middlewares=crowdsec@docker"
4038
# Definition of the service
4139
- "traefik.http.services.service-foo.loadbalancer.server.port=80"
4240
# Definition of the middleware
@@ -48,8 +46,6 @@ services:
4846
# Define AppSec host and port informations
4947
- "traefik.http.middlewares.crowdsec.plugin.bouncer.crowdsecappsechost=crowdsec:7422"
5048

51-
52-
5349
crowdsec:
5450
image: crowdsecurity/crowdsec:v1.6.1-2
5551
container_name: "crowdsec"
@@ -65,7 +61,7 @@ services:
6561
- crowdsec-config-appsec-enabled:/etc/crowdsec/
6662
labels:
6763
- "traefik.enable=false"
68-
64+
6965
volumes:
7066
logs-appsec-enabled:
7167
crowdsec-db-appsec-enabled:

examples/captcha/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ For now 3 captcha providers are supported:
2020
- "traefik.http.middlewares.crowdsec.plugin.bouncer.captchaSiteKey=FIXME"
2121
# Define captcha secret key
2222
- "traefik.http.middlewares.crowdsec.plugin.bouncer.captchaSecretKey=FIXME"
23-
# Define captcha grade period seconds
23+
# Define captcha grace period seconds
2424
- "traefik.http.middlewares.crowdsec.plugin.bouncer.captchaGracePeriodSeconds=1800"
2525
# Define captcha HTML file path
2626
- "traefik.http.middlewares.crowdsec.plugin.bouncer.captchaHTMLFilePath=/captcha.html"

examples/captcha/captcha.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@
293293
</svg>
294294
<h1 class="text-2xl lg:text-3xl xl:text-4xl">CrowdSec Captcha</h1>
295295
</div>
296-
<form action="" method="POST" class="flex flex-col space-y-1" id="captcha-form">
296+
<form action="" method="POST" class="flex flex-col items-center space-y-1" id="captcha-form">
297297
<div id="captcha" class="{{ .FrontendKey }}" data-sitekey="{{ .SiteKey }}" data-callback="captchaCallback">
298298
</div>
299299
</form>

examples/custom-captcha/README.md

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Example
2+
3+
Read the example captcha before this, to better understand what is done here.
4+
5+
### Traefik configuration
6+
7+
The minimal configuration is defined below to implement custom captcha.
8+
This documentation use https://github.com/a-ve/wicketpeeker, a self-hosted captcha provider that have a similar API than big providers.
9+
10+
Minimal API requirement:
11+
12+
- the JS file URL to load the captcha on the served `captcha.html`
13+
- the HTML className to tell to the JS where to display the challenge
14+
- the verify URL endpoint to send the field `response` from the captcha with `content-type: application/x-www-form-urlencoded`
15+
- the name of the field when you POST the resolved captcha to Traefik
16+
17+
- the JS file need to respect the `data-callback` on the div that contains the captcha if you use our template, but you can customize it by your side
18+
19+
```yaml
20+
traefik:
21+
...
22+
labels:
23+
# Choose captcha provider
24+
- "traefik.http.middlewares.crowdsec.plugin.bouncer.captchaProvider=custom"
25+
# Define captcha grace period seconds
26+
- "traefik.http.middlewares.crowdsec.plugin.bouncer.captchaGracePeriodSeconds=1800"
27+
- "traefik.http.middlewares.crowdsec.plugin.bouncer.captchaCustomJsURL=http://captcha.localhost:8000/fast.js"
28+
# Inside Traefik container the plugin must be able to reach wicketkeeper service so we can go through a Traefik localhost
29+
# domain which would resolve traefik itself and the port for the dashboard
30+
- "traefik.http.middlewares.crowdsec.plugin.bouncer.CaptchaCustomValidateURL=http://wicketkeeper:8080/v0/siteverify"
31+
- "traefik.http.middlewares.crowdsec.plugin.bouncer.CaptchaCustomKey=wicketkeeper"
32+
- "traefik.http.middlewares.crowdsec.plugin.bouncer.CaptchaCustomResponse=wicketkeeper_solution"
33+
# Define captcha HTML file path
34+
- "traefik.http.middlewares.crowdsec.plugin.bouncer.captchaHTMLFilePath=/captcha.html"
35+
```
36+
37+
```yaml
38+
wicketkeeper:
39+
image: ghcr.io/a-ve/wicketkeeper:latest
40+
user: root
41+
ports:
42+
- "8080:8080"
43+
environment:
44+
- ROOT_URL=http://localhost:8080
45+
- LISTEN_PORT=8080
46+
- REDIS_ADDR=redis:6379
47+
- DIFFICULTY=4
48+
- ALLOWED_ORIGINS=*
49+
- PRIVATE_KEY_PATH=/data/wicketkeeper.key
50+
volumes:
51+
- ./data:/data
52+
depends_on:
53+
- redis
54+
redis:
55+
image: redis/redis-stack-server:latest
56+
```
57+
58+
## Exemple navigation
59+
60+
We can try to query normally the whoami server:
61+
62+
```bash
63+
curl http://localhost:8000/foo
64+
```
65+
66+
We can try to ban ourself and retry.
67+
68+
```bash
69+
docker exec crowdsec cscli decisions add --ip 10.0.0.20 -d 10m --type captcha
70+
```
71+
72+
To play the demo environment run:
73+
74+
```bash
75+
make run_custom_captcha
76+
```
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
filenames:
2+
- /var/log/traefik/access.log
3+
labels:
4+
type: traefik

0 commit comments

Comments
 (0)