From 2e027b126526077b6a12674c5eed11709add8840 Mon Sep 17 00:00:00 2001 From: Denys Fedoryshchenko Date: Tue, 21 Jul 2026 13:09:47 +0300 Subject: [PATCH] proxy: add JavaScript cookie challenge for dumb bots Production observations show many unsophisticated bots stressing the dashboard with random requests. Add a lightweight JavaScript and cookie hurdle before serving frontend or API requests from Safari, Android, and Chromium-style user agents. Cross-check the claimed browser platform/vendor, reject WebDriver, require the exact verification cookie value, and safely return browsers to the original URI. Preserve local HTTP support while marking the cookie Secure on browser-facing HTTPS connections. Legitimate programmatic API clients using their normal python-requests, Wget, or curl user agents bypass the browser gate. Clients that claim to be browsers must complete the same challenge before reaching /api. This is intentionally a speed bump for dumb bots rather than an authentication boundary; rate limiting remains the appropriate additional protection for determined direct API abuse. Signed-off-by: Denys Fedoryshchenko --- .../etc/nginx/templates/default.conf.template | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/proxy/etc/nginx/templates/default.conf.template b/proxy/etc/nginx/templates/default.conf.template index e9eb4cf3e..2e90a7502 100644 --- a/proxy/etc/nginx/templates/default.conf.template +++ b/proxy/etc/nginx/templates/default.conf.template @@ -1,12 +1,118 @@ +# This is deliberately a lightweight challenge for unsophisticated bots, not +# an authentication mechanism. Browser UAs commonly containing "Safari" +# include Safari itself and Chromium-based browsers; Android browsers are +# included separately because not all of them advertise Safari. +map $http_user_agent $dashboard_browser_ua { + default 0; + ~*(Safari|Android) 1; +} + +map $cookie_kernelci_dashboard_verified $dashboard_cookie_verified { + default 0; + "1" 1; +} + +map "$dashboard_browser_ua:$dashboard_cookie_verified" $dashboard_cookie_gate { + default 0; + "1:0" 1; +} + server { location /api { + if ($dashboard_cookie_gate) { + add_header Cache-Control "no-store" always; + return 302 /__dashboard_cookie_check?return=$request_uri; + } proxy_pass ${PROXY_TARGET}; proxy_connect_timeout 240s; proxy_read_timeout 240s; proxy_send_timeout 240s; send_timeout 240s; } + + # Keep the challenge outside `location /` so it cannot redirect to itself. + # Command-line API clients retain access with their normal user agents; + # clients claiming to be browsers must complete the same challenge. + location = /__dashboard_cookie_check { + default_type text/html; + add_header Cache-Control "no-store" always; + add_header Content-Security-Policy "default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; base-uri 'none'; frame-ancestors 'none'" always; + add_header X-Robots-Tag "noindex, nofollow" always; + return 200 ' + + + + +Redirecting… + + + +

Checking your browser…

+ + + +'; + } + location / { + if ($dashboard_cookie_gate) { + add_header Cache-Control "no-store" always; + return 302 /__dashboard_cookie_check?return=$request_uri; + } root /data/static; try_files $uri /index.html; }