3
0
Fork
You've already forked geant-captcha
0
No description
  • Python 70.3%
  • Shell 23.9%
  • Dockerfile 5.8%
2026年03月26日 14:48:26 +01:00
.vscode add Redis support for session management 2025年03月13日 20:32:12 +01:00
files refactor: update configuration and environment variable references 2026年03月24日 20:35:19 +01:00
.gitignore refactor: update configuration and environment variable references 2026年03月24日 20:35:19 +01:00
.gitlab-ci.yml feat: refactor CI/CD configuration and update Docker setup 2026年03月24日 19:42:53 +01:00
CHANGELOG.md refactor: update configuration and environment variable references 2026年03月24日 20:35:19 +01:00
cliff.toml feat: refactor CI/CD configuration and update Docker setup 2026年03月24日 19:42:53 +01:00
docker-compose.yml refactor: update configuration and environment variable references 2026年03月24日 20:35:19 +01:00
Dockerfile feat: update Dockerfiles 2026年03月24日 20:05:56 +01:00
Dockerfile-local feat: update Dockerfiles 2026年03月24日 20:05:56 +01:00
README.md docs: add Fail2ban configuration instructions for HAProxy 2026年03月26日 14:48:26 +01:00

GEANT Captcha - Flask

Flask CAPTCHA for HAProxy

  1. Preamble
    1. Google reCaptcha parameters
    2. hCaptcha parameters
    3. HAProxy configuration
  2. Docker instructions
  3. Create a new release

Preamble

This container runs a Flask application to verify a captcha against a supported provider.
Two providers are currently supported: hCaptcha and Google reCaptcha.
Switching from reCAPTCHA to hCaptcha is explained in this page

The parameters are stored here as Consul keys: https://consul.service.ha.geant.net/ui/geant/kv/nomad/test/captcha

Google reCaptcha parameters

  • api_url: https://www.google.com/recaptcha/api.js
  • provider_name: g-recaptcha
---config:verify_url:"https://www.google.com/recaptcha/api/siteverify"provider_name:"g-recaptcha-response"max_age:3600# cookie lifetime in secondsvalkey:host:"redis.service.consul"record_type:"SRV"ssl:falsesites:www.mysite.org:wordpresswiki.geant.org:wiki

hCaptcha parameters

  • api_url: https://js.hcaptcha.com/1/api.js
  • provider_name: h-captcha
---config:verify_url:"https://api.hcaptcha.com/siteverify"provider_name:"h-captcha-response"max_age:3600# cookie lifetime in secondsvalkey:host:"redis.example.org"record_type:"A"ssl:falsesites:www.mysite.org:wordpresswiki.geant.org:wiki

HAProxy configuration

Frontend configuration

frontend http-in
 # Track source IP in the backend's stick-table (per-IP rate limiting)
 http-request track-sc0 src table wiki_backend
 # ACL for rate limiting: more than 10 connections in 10 seconds from the same IP
 acl captcha_rate_limited sc0_conn_rate(wiki_backend) gt 10
 # ACLs for cookie and path checks
 acl is_valid_cookie hdr_sub(cookie) captcha_pass=wordpress # Adjust value as needed
 acl is_captcha_verify path_beg /verify.html
 acl is_captcha_flask path -i /validate
 # Redirect to CAPTCHA if not validated and rate limit exceeded
 http-request redirect location https://%[req.hdr(Host)]/verify.html \
 if !is_valid_cookie !is_captcha_verify !is_captcha_flask captcha_rate_limited
 # Route to Flask CAPTCHA backend for validation requests
 use_backend captcha_verify if { path -i /verify.html }

Backend configuration

backend captcha_flask
 mode http
 option httpchk GET /_healthz
 timeout connect 20s
 timeout server 20s
 http-request set-header Host %[req.hdr(Host)]
 server-template captcha 1-10 _test-captcha._tcp.service.ha.geant.net check inter 30s ssl verify none resolvers consul init-addr none resolve-opts allow-dup-ip resolve-prefer ipv4
backend captcha_verify
 mode http
 http-request cache-use verify_cache
 http-response cache-store verify_cache
 http-request return status 200 content-type "text/html" file "/etc/haproxy/captcha/verify.html" hdr "cache-control" "no-cache"
backend wiki_backend
 stick-table type ip size 100k expire 10m store conn_rate(10s)
 server wiki wiki-backend.example.org:443 maxconn 10 check inter 10s ssl verify none

HAProxy and Fail2ban

💥 This solution has drawbacks 💥 Against distributed attacks the service will be reloaded continuously.

To protect your backend from brute-force login attacks, you can use Fail2ban to monitor HAProxy logs, check for 401 error codes, and store IP addresses that exceed a certain number of failed attempts.
The addresses will be stored in a HAProxy map file /etc/haproxy/banned.lst and HAProxy will be reload systemctl reload haproxy.

The file should contain one IP address per line, for example:

# /etc/haproxy/banned.lst
192.0.2.1
203.0.113.5
198.51.100.7

And haproxy configuration should include the following ACL to block requests from these IPs:

 # ACL to block banned IPs
 acl banned_ip src -f /etc/haproxy/banned.lst
 # Redirect to CAPTCHA if not validated and rate limit exceeded
 http-request redirect location https://%[req.hdr(Host)]/verify.html \
 if !is_valid_cookie !is_captcha_verify !is_captcha_flask banned_ip
 # Route to Flask CAPTCHA backend for validation requests
 use_backend captcha_verify if { path -i /verify.html }

Docker instructions

First you need a secret key for your provider (see Google reCaptcha parameters and hCaptcha documentation).

You can store your secret key in a file called recaptcha_secret.env (the file is declared in .gitignore) with the following content:

secret_key='your_secret_key_here'

Finally can build and run a local image using Docker Compose as follows:

docker compose --profile all up --build

Create a new release

Add this lines to ~/.gitconfig:

[alias]
 pp = !git pull && git push
 pushall = !git remote | xargs -L1 git push --all
 pushall-tags = !git remote | xargs -L1 git push --tags

We assume that we are applying our change to main branch and create a tag starting from main.

If we want to create version 1.2.3, the commands below triggers the CI and and creates version 1.2.3 of the container:

git checkout main # make your changes ...
git commit "my new change"
git push
git tag 1.2.3
git pushall-tags