Forwarded and X-Forwarded headers can change the request scheme, host and client address seen by the application.
Spring behind a proxy: trust forwarded headers only after the edge strips them
Put trust at the network edge
A service behind a TLS-terminating proxy may see plain HTTP internally while the browser used HTTPS. ForwardedHeaderFilter can reconstruct the external scheme and host for redirects and links. The application cannot tell whether a forwarded header came from its proxy or an arbitrary client. The outermost trusted proxy must remove incoming Forwarded and X-Forwarded variants, then set the values it intends the service to use.
Treat host and prefix as input
If a client can inject X-Forwarded-Host, a password-reset link or absolute redirect may point to an attacker host. If the proxy cannot guarantee stripping, remove headers without using them. Keep an allowlist for externally valid hosts where link generation matters. Security rules and OAuth callbacks must see a consistent external URL.
Test through the actual proxy
Send a spoofed forwarded host from outside and verify the edge replaces it. Then request a legitimate HTTPS redirect and confirm its scheme and host. A local MockMvc test of the filter cannot prove the proxy's stripping behavior; the edge-to-service path is the system under test.
Implementation sketch
@Bean
ForwardedHeaderFilter forwardedHeaders() {
ForwardedHeaderFilter filter = new ForwardedHeaderFilter();
// Enable only behind a proxy that discards client-supplied variants.
return filter;
}Cost and verification
The filter's wrapping cost is small; the security cost of trusting unfiltered host or scheme values is large. Test redirect and cookie behavior after every proxy configuration change.
Common Mistakes
- Do not trust raw Forwarded or X-Forwarded headers from public clients.
- Do not strip only one header family while accepting the other.
- Do not assume a filter unit test proves the reverse proxy is configured safely.
Read next
Spring Security OAuth2 login: callback, identity and browser session, Spring Security login session: rotate the identifier at authentication, Spring MVC CORS: a browser-origin policy is not authentication, Spring Security filter chain: authentication, CSRF and request order.
