Filtering out headers from external IP addresses

Closes #48683

Signed-off-by: Pedro Ruivo <1492066+pruivo@users.noreply.github.com>
Signed-off-by: Alexander Schwartz <alexander.schwartz@ibm.com>
Co-authored-by: Pedro Ruivo <1492066+pruivo@users.noreply.github.com>
Co-authored-by: Alexander Schwartz <alexander.schwartz@ibm.com>
This commit is contained in:
Pedro Ruivo 2026-05-19 22:55:50 +01:00 committed by GitHub
parent 2d1a24f501
commit 7635dfbccc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 90 additions and 8 deletions

View file

@ -40,12 +40,24 @@ defaults
frontend https_front
bind *:8443 ssl crt /path/to/haproxy-external-certificate # <1>
mode http # <2>
http-request del-header Forwarded # <3>
http-request del-header x-forwarded-for
http-request del-header x-forwarded-proto
http-request del-header x-forwarded-host
http-request del-header x-forwarded-port
http-request del-header x-forwarded-server
# Prevent external spoofing
http-request del-header Forwarded <3>
http-request del-header x-forwarded-.* -m reg
http-request del-header x-original-.* -m reg
http-request del-header x-real-ip
# Prevent external tracing context injection (W3C Trace Context / Baggage)
http-request del-header traceparent
http-request del-header tracestate
http-request del-header baggage
# Prevent external tracing context injection (Zipkin, Jaeger, OpenTracing)
http-request del-header b3
http-request del-header x-b3-.* -m reg
http-request del-header uber-trace-id
http-request del-header x-ot-span-context
default_backend keycloak_back
backend keycloak_back
@ -66,8 +78,9 @@ The `ssl crt /path/to/haproxy-external-certificate` directive sets the certifica
<2> Enables link:https://docs.haproxy.org/3.2/configuration.html#4-mode[HTTP mode] on the frontend.
This tells HAProxy to operate at Layer 7, decrypting and re-encrypting HTTP traffic.
HAProxy has access to the plaintext HTTP traffic in this mode.
<3> The `http-request del-header <HEADER>` entries remove particular HTTP headers from the incoming requests before passing them on.
The example shows removing of the `Forwarded` and `x-forwarded-` headers in order to prevent a security vulnerability to IP spoofing attacks, where the client is able to impersonate the proxy or other services.
<3> The `http-request del-header` directives remove HTTP headers from incoming requests before forwarding them to {project_name}.
This prevents external clients from spoofing proxy identity headers (such as `Forwarded`, `+X-Forwarded-*+`, and `X-Real-IP`), injecting authentication-related headers (such as `X-Forwarded-Access-Token`), or injecting distributed tracing context (such as W3C Trace Context, Zipkin B3, or Jaeger headers).
For the full list of recommended headers to filter, see the <@links.server id="reverseproxy" anchor="header-filtering-recommendations"/> {section}.
<4> The backend must also use HTTP mode to match the frontend.
<5> Distributes connections across backend servers using link:https://docs.haproxy.org/3.2/configuration.html#4-balance[round-robin] load balancing.
<6> This option adds a `Forwarded` header containing the correct client information.

View file

@ -176,6 +176,75 @@ For example:
<@kc.start parameters="--proxy-headers forwarded --proxy-trusted-addresses=192.168.0.32,127.0.0.0/8"/>
[[header-filtering-recommendations]]
=== Header filtering recommendations
When using TLS re-encrypt, the proxy can inspect and modify HTTP traffic.
Use this capability to prevent external clients from injecting headers that affect identity resolution, access control, or observability.
NOTE: The following assumes that there is only a single proxy layer in front of {project_name}, and that it is not receiving traffic from another trusted proxy layer with trusted headers.
Configure the proxy to apply the following rules to incoming requests before forwarding them to {project_name}:
* *Overwrite* `Forwarded` and `+X-Forwarded-*+` headers with the proxy's own values rather than removing them, because {project_name} relies on these headers when `--proxy-headers` is configured.
* *Strip* all other headers listed below entirely.
[%autowidth]
|===
|Header(s) |Category |Risk if not filtered
|`Forwarded`, `X-Forwarded-For`, `X-Forwarded-Proto`, `X-Forwarded-Host`, `X-Forwarded-Port`, `X-Forwarded-Prefix`
|Proxy identity
|Clients can spoof their IP address, protocol, or host, affecting access control and audit logging.
*Overwrite* these headers rather than stripping them.
|`X-Original-Forwarded-For`
|Proxy identity
|Variant of `X-Forwarded-For` recognized by some proxies.
Can be spoofed to bypass IP-based access controls.
|`X-Real-IP`
|Proxy identity
|Trusted by some applications for rate limiting and audit logging.
Can be spoofed to bypass IP-based restrictions.
|`X-Original-URL`, `X-Original-Method`
|Proxy identity
|Used by authentication sub-request mechanisms in some proxies.
Can be spoofed to manipulate path-based authorization decisions.
|`X-Forwarded-Access-Token`
|Proxy identity
|Injected by some OAuth2 proxies.
Can be spoofed to inject forged access tokens.
|`traceparent`, `tracestate`
|Distributed tracing
|https://www.w3.org/TR/trace-context/[W3C Trace Context] headers.
External injection allows attackers to correlate requests in the tracing backend and map internal service dependencies.
|`baggage`
|Distributed tracing
|https://www.w3.org/TR/baggage/[W3C Baggage] header.
Can inject arbitrary key-value pairs into the trace context propagated to downstream services.
|`b3`, `x-b3-traceid`, `x-b3-spanid`, `x-b3-parentspanid`, `x-b3-sampled`, `x-b3-flags`
|Distributed tracing
|https://github.com/openzipkin/b3-propagation[Zipkin B3] propagation headers.
External injection inflates observability costs and enables cross-service correlation.
|`uber-trace-id`
|Distributed tracing
|https://www.jaegertracing.io/sdk-migration/#propagation-format[Jaeger] propagation header (deprecated in favor of W3C Trace Context).
Same risks as other tracing headers.
|`x-ot-span-context`
|Distributed tracing
|OpenTracing propagation header (deprecated in favor of W3C Trace Context).
Same risks as other tracing headers.
|===
=== Exposed path recommendations
When using a reverse proxy, {project_name} only requires certain paths to be exposed.