Hi List,

Am 22.06.20 um 21:13 schrieb Tim Düsterhus:
> What kind of (configuration) advice would you give me? Do you have any
> concerns? I consider *anything* a valid answer here and I'd like to hear
> from both experienced admins and "newbies".
> I'll give the "solution" once I get some replies :-)

I've also forwarded the question to the #haproxy channel on Freenode and
I also got some replies in private. The suggestions mostly looked
something like Jonathan's reply:

  acl internal_net src
  acl admin_request path_beg /admin/
  http-request deny if admin_request !internal_net

Indeed that's also something I did myself within my production
configurations. However it's insecure.

One correct solution is the one given by Ilya and hinted by by Jonathan
is: Don't do this in HAProxy, instead do this in the backend which knows
exactly how it's going to interpret stuff.

However that might be painful if authentication is not going to be
performed based on IP address, but e.g. TLS client certificates, because
you would need to ship the DN within a header to the backend.

Another correct solution would be using a strict whitelist using
`http-request allow [...] if [...]` with an unconditional `http-request
deny` at the end.

However that might be painful for the situation I described in the
initial mail ("During upgrades of this off-the-shelf software new files
might be added for new features.").

So what exactly is the issue with the http-request deny rule as given above?

The issue I was concerned about is that HAProxy does not perform
normalization when comparing the path against something within an ACL.
Specifically HAProxy does not perform normalization of non-reserved
percent-encoded characters (RFC 3986#2.3). Nginx does.

So a simple `curl localhost/%61dmin` would circumvent the rule in
HAProxy. But nginx happily interprets this as a request to the /admin/
folder, allowing access to unauthorized users.

While this percent normalization could possibly be done generically,
because these URLs are defined in RFC 3986 to be equivalent, other types
normalization would be harder.

So a request to `curl localhost/public/../admin/` might or might not
cause the backend to interpret the request as a request to /admin/, but
a blanket normalization would be incorrect here, because API backends
might not refer to paths on a file system. This can be fixed with a
`http-request deny if { path_sub ../ }` or something similar.

On Windows a request to `curl localhost/ADMIN` might also access the
admin/ folder, but that is easily fixed with the `-i` flag (unless
unicode characters are used, I guess?).

However the percent-encoding normalization can not be implemented within
the configuration as of right now (to the best of my knowledge). Using
the url_dec converter is incorrect, because it also decodes stuff like
`%2F` to `/` which is disallowed during normalization and can introduce
issues on its own.

The disagreement I had with Willy was that I said that percent
normalization should happen by default (because of the RFC). However
Willy responded that this would take away some visibility, because
you're never going to see these unnormalized URLs in the logs, not
noticing an ongoing attack. Also some bogus clients and backends might
rely on these unnormalized forms.

Willy: Please correct me if I misrepresented your arguments or left out
something important.

- The documentation should be updated to warn administrators that
http-request deny must be used very carefully when combining it with a path.
- HAProxy should gain the ability to correctly normalize URLs (i.e. not
using the url_dec version). How exactly that would look is not yet clear.
  - It could be a `http-request normalize-path percent,dotdot,Y` action.
  - It could be a `normalize(percent)` converter
  - The `path` fetch could be extended to gain an argument, specifying
the normalization requested.
  - An option within the `defaults` section could enable normalization
for everything.

If you have anything to add after reading this mail: Please do!

Best regards
Tim Düsterhus

Reply via email to