This document describes the CAPTCHA gating feature that has been added to Zoraxy.
The CAPTCHA gating feature allows you to protect your endpoints with CAPTCHA challenges, similar to Cloudflare Turnstile. Users must solve a CAPTCHA before they can access protected endpoints. This feature supports both Cloudflare Turnstile and Google reCAPTCHA (v2 and v3).
- Per-endpoint configuration: Just like rate limiting, CAPTCHA can be enabled/disabled per endpoint
- Multiple provider support:
- Cloudflare Turnstile
- Google reCAPTCHA v2 (checkbox)
- Google reCAPTCHA v3 (invisible with score)
- Session management: Validated users receive a session cookie (configurable duration)
- Exception rules: Exclude specific paths or IP ranges from CAPTCHA challenges
- Modern UI: Responsive CAPTCHA challenge pages with gradient backgrounds
When adding or editing a proxy endpoint, you can configure CAPTCHA with the following parameters:
| Parameter | Type | Description |
|---|---|---|
captcha |
boolean | Enable/disable CAPTCHA for this endpoint |
captchaProvider |
integer | Provider type: 0 = Cloudflare Turnstile, 1 = Google reCAPTCHA |
captchaSiteKey |
string | Site key (public key) from your CAPTCHA provider |
captchaSecretKey |
string | Secret key (private key) from your CAPTCHA provider |
captchaSessionDuration |
integer | Session duration in seconds (default: 3600) |
captchaRecaptchaVersion |
string | For Google: "v2" or "v3" (default: "v2") |
captchaRecaptchaScore |
float | For Google reCAPTCHA v3: minimum score 0.0-1.0 (default: 0.5) |
curl -X POST http://localhost:8000/api/proxy/edit \
-d "rootname=example.com" \
-d "captcha=true" \
-d "captchaProvider=0" \
-d "captchaSiteKey=YOUR_SITE_KEY" \
-d "captchaSecretKey=YOUR_SECRET_KEY" \
-d "captchaSessionDuration=7200"CAPTCHA configuration is stored in the proxy endpoint configuration files (.config files in conf/http_proxy/). The configuration is persisted as part of the ProxyEndpoint struct in JSON format.
- Request arrives at protected endpoint
- Check exceptions: If path or IP matches exception rules → allow
- Check session cookie: If valid session exists → allow
- Serve CAPTCHA challenge: Display CAPTCHA page
- User solves CAPTCHA
- Verification: Submit token to provider API
- Create session: On success, set cookie and allow access
- Redirect: User is redirected to original destination
The CAPTCHA middleware is positioned in the request chain as follows:
- Access Control (blacklist/whitelist)
- Exploit Detection
- Rate Limiting
- CAPTCHA Gating ← Inserted here
- Authentication (Basic Auth / SSO)
- Proxy to upstream
This ensures CAPTCHA verification happens after rate limiting but before authentication.
You can exclude certain paths or IP addresses from CAPTCHA challenges:
-
Path-based exceptions: Match by path prefix
{ "RuleType": 0, "PathPrefix": "/api/v1/" } -
IP-based exceptions: Match by IP or CIDR range
{ "RuleType": 1, "CIDR": "192.168.1.0/24" }
- Exclude API endpoints from CAPTCHA
- Whitelist internal IP ranges
- Skip CAPTCHA for specific paths (e.g.,
/health,/metrics)
The CAPTCHA session store (CaptchaSessionStore) is a global component that:
- Stores session IDs with expiration times
- Uses
sync.Mapfor thread-safe concurrent access - Automatically cleans up expired sessions every 5 minutes
When a user successfully completes a CAPTCHA:
- A random 64-character session ID is generated
- A cookie named
zoraxy_captcha_sessionis set - Cookie attributes:
HttpOnly: Yes (prevents JavaScript access)Secure: Yes if TLS is enabledSameSite: LaxMaxAge: Configurable (default 1 hour)
- Sign up at https://dash.cloudflare.com/
- Navigate to Turnstile section
- Create a new site
- Copy the Site Key and Secret Key
- Configure in Zoraxy with
captchaProvider=0
- Visit https://www.google.com/recaptcha/admin
- Register a new site
- Select reCAPTCHA v2 (checkbox)
- Copy the Site Key and Secret Key
- Configure in Zoraxy with:
captchaProvider=1captchaRecaptchaVersion=v2
- Visit https://www.google.com/recaptcha/admin
- Register a new site
- Select reCAPTCHA v3
- Copy the Site Key and Secret Key
- Configure in Zoraxy with:
captchaProvider=1captchaRecaptchaVersion=v3captchaRecaptchaScore=0.5(adjust as needed)
src/mod/dynamicproxy/captcha.go: Core CAPTCHA verification and session management logic
-
src/mod/dynamicproxy/typedef.go:- Added
CaptchaConfig,CaptchaProvider,CaptchaExceptionRuletypes - Added
RequireCaptchaandCaptchaConfigfields toProxyEndpoint - Added
captchaSessionStorefield toRouter
- Added
-
src/mod/dynamicproxy/dynamicproxy.go:- Initialize
CaptchaSessionStoreinNewDynamicProxy() - Added CAPTCHA middleware to port 80 HTTP handler
- Initialize
-
src/mod/dynamicproxy/Server.go:- Added CAPTCHA middleware to main request chain
-
src/reverseproxy.go:- Added CAPTCHA parameter parsing in
ReverseProxyHandleAddEndpoint() - Added CAPTCHA parameter parsing in
ReverseProxyHandleEditEndpoint() - Added CAPTCHA configuration to endpoint creation
- Added CAPTCHA parameter parsing in
handleCaptchaRouting(): Main middleware functionhandleCaptchaVerification(): Process CAPTCHA token verificationserveCaptchaChallenge(): Render CAPTCHA challenge pageVerifyCloudflareToken(): Verify Cloudflare Turnstile tokenVerifyGoogleRecaptchaToken(): Verify Google reCAPTCHA tokenCheckCaptchaException(): Check if request matches exception rules
-
Secret Key Protection: Store CAPTCHA secret keys securely. They are stored in config files - ensure proper file permissions.
-
Session Security: Session IDs are cryptographically random (32 bytes from
crypto/rand). -
Cookie Security: Cookies use HttpOnly and Secure flags when TLS is enabled.
-
Rate Limiting: CAPTCHA works in conjunction with rate limiting, not as a replacement.
-
Score Thresholds: For reCAPTCHA v3, adjust the score threshold based on your traffic patterns (0.5 is a good starting point).
CAPTCHA-related events are logged with the following identifiers:
captcha-required: User was served a CAPTCHA challenge (403 status)
- Enable CAPTCHA on an endpoint
- Access the endpoint → Should show CAPTCHA challenge
- Complete CAPTCHA → Should create session and allow access
- Access again → Should bypass CAPTCHA (session valid)
- Wait for session expiry → Should show CAPTCHA again
# First request - should return CAPTCHA HTML
curl -i http://your-domain.com/
# After solving CAPTCHA in browser, copy session cookie
# Second request with session cookie - should proxy normally
curl -i -H "Cookie: zoraxy_captcha_session=YOUR_SESSION_ID" http://your-domain.com/The following API endpoints support CAPTCHA configuration:
POST /api/proxy/add: Add new endpoint with CAPTCHAPOST /api/proxy/edit: Edit existing endpoint CAPTCHA settings
Potential improvements for future versions:
- Web UI Integration: Add CAPTCHA settings to the web-based admin panel
- Additional Providers: Support for hCaptcha, FriendlyCaptcha
- Exception Rule Management API: Dedicated endpoints for managing exception rules
- Analytics: Track CAPTCHA solve rates and bot detection statistics
- Custom Challenge Pages: Allow custom HTML templates for CAPTCHA pages
- Distributed Sessions: Support for session sharing across multiple Zoraxy instances
- Check that
RequireCaptchaistruein endpoint configuration - Verify
CaptchaConfigis notnil - Check logs for any errors
- Verify Site Key and Secret Key are correct
- Check network connectivity to CAPTCHA provider APIs
- Ensure client IP detection is working correctly
- Check cookie settings in browser
- Verify session duration configuration
- Ensure cookies are not being blocked by browser settings
Implemented following the existing Zoraxy architecture patterns:
- Rate limiting implementation for reference
- Basic authentication exception rules for exception handling pattern
- Access control for IP filtering patterns
For questions or issues, please file a GitHub issue at https://github.com/tobychui/zoraxy/issues