I recently switched to HAProxy 3.0.11 (-9e587df) on a OpenBSD System, version 7.7. I use HA to switch between hosts but most importantly also to filter out bad traffic. Most of it works fine: Requests that are for sure with bad intent lead to a TCP reject. Among those are also request with query parameters, example “GET /?dns…” but also things like “GET /?@zdi/Powershell”. Problem is that a few of these requests still get through. When I send them with my browser, HA rejects (closes) the connection immediately. I have not understood how these requests still make their way to my servers. I reject if “?” follows “/” (the web root) or “/index.html”
Part of my configuration:
acl defpath path / /index.html
acl qstr query -m found
tcp-request inspect-delay 10s
tcp-request content reject if qstr defpat
Rest is not of importance, just the usual stuff and a few acl to reject if somebody probes for example for Wordpress or “admin” etc.
The configuration snippet you have shown cannot work after 10 seconds after connection establishment, it probably cannot work for subsequent request in a keepalive session, but this depends on the rest of the configuration.
Does haproxy reject the TCP sessions when the second requests hits in a keepalive session, like:
Thank yo very much for the quick response and the advice, appreciated! I put the HAProxy configuration in a file (only modified the domain name, rest unchanged), the result of the curl test (domain name changed and body of html response removed) and an extract of an access log. I share this file as it is more than 300 lines long. The tests show that in the majority of the cases bad requests are rejected (curl, browser and programs). What I will do is keeping the log files of HAProxy, I have sent them to Nirvana as they tend to become quite big. Or start HAProxy with nohup in a terminal session. I did that in the past but as I said, only few bad requests get through
This way I think you should be able to simplify your configuration a lot.
However due to the mixed results you seem to be getting, I think you may have haproxy instances with older configurations running in the background in parallel, that sometimes catch a requests and because they run an older configuration, the request is not rejected.
To make sure: stop haproxy ordinarily and then manually kill all remaining haproxy processes (killall haproxy). Only when no haproxy processes are around anymore, you start haproxy again.
You should not need tcp-request inspect-delay because you are in HTTP mode with full HTTP parsing.
If things still don’t work reliably, try putting http request deny rules after the tcp-content reject rules, to see if haproxy would emit a 403:
http-request deny if qstr defpat
http-request deny if probe !wellkn
My bad! The logs revealed what I simply overlooked. A request with a non-existing path that is followed by queries of course gets routed through, but in the web server log I did not see the original request as it was rewritten (path contained “teorema505” = Qakbot related attack). So there was a path in front of the “?”. The proxy works exactly as configured. I now know how to continue from here. The discussion helped me to look a bit further, thank you again.
I will simplify the configuration as you suggested, makes it much clearer and also easier to spot what I overlooked.