Require HTTPS with Spring Security for reverse proxy

I have a Spring MVC application protected with Spring Security. Most applications use simple HTTP to save resources, but a small part processes more confidential information and requires an HTTPS channel.

Extract from security-config.xml :

 <sec:http authentication-manager-ref="authenticationManager" ... > ... <sec:intercept-url pattern="/sec/**" requires-channel="https"/> <sec:intercept-url pattern="/**" requires-channel="http"/> </sec:http> 

Everything worked fine until we decided to transfer it to the main server, where application servers work behind reverse proxies. And since HTTPS is now handled by reverse proxies, the application server only sees HTTP requests and denies access to the /sec/** hierarchy.

After some research, I found that proxies add the X-Forwarded-Proto: https header X-Forwarded-Proto: https (*) but in Spring Security HttpServletRequest.isSecure() used to determine the proposed channel security (fetching from the javadoc SecureChannelProcessor ).

How can I tell Spring Security that the X-Forwarded-Proto: https header is enough for a secure request?

I know that I could report about this part about the proxy configuration, but the proxy administrator really does not like this solution, because there are many applications behind the proxy, and the configuration can grow to an unmanaged state.

I am currently using Spring Security 3.2 with XML configuration, but I am ready to accept answers based on Java configuration and / or later.

(*) Of course, proxies remove the header if it was present in the incoming request, so the application can be sure of this.

+11
java spring-security reverse-proxy
source share
3 answers

If your site is HTTPS and you use Apache Tomcat behind another system that handles TLS termination, you can tell Tomcat to "pretend" that it is handling TLS termination.

This makes request.isSecure() return true ;

To do this, you need to add secure="true" to your Connector configuration in server.xml .

https://tomcat.apache.org/tomcat-7.0-doc/config/http.html

See also the scheme attribute.

+5
source

View of the answer to a NeilMcGuigan question that showed that the solution was part of a servlet container.

Tomcat is even better. There is a valve designed to mask the side effects of reverse proxies. Excerpt from the Tomcat documentation for Remote IP Valve :

Another feature of this valve is to replace the visible scheme (http / https), the server port and request.secure with the scheme provided by the proxy server or the load balancer through the request header (for example, "X-Forwarded-Proto")).

Valve configuration example:

 <Valve className="org.apache.catalina.valves.RemoteIpValve" internalProxies="192\.168\.0\.10|192\.168\.0\.11" remoteIpHeader="x-forwarded-for" proxiesHeader="x-forwarded-by" protocolHeader="x-forwarded-proto" /> 

Thus, in the absence of another configuration of the application itself, the call to Request.isSecure() will return true if the request contains the header field X-Forwarded-Proto=https .

I thought of two other possibilities, but would definitely prefer one:

  • use the filter before Spring ChannelProcessingFilter Security to wrap the request using HttpServletRequestWrapper overriding isSecure() to handle the X-Forwarded-Proto header - you need to write and test the filter and wrapper
  • use Spring BeanPostProcessor to search for ChannelProcessingFilter and manually add a ChannelDecisionManager able to view the X-Forwarded-Proto header - really too low
+17
source

Spring Boot makes it very simple (at least with built-in Tomcat).

1. Add the following lines to your application.properties:

 server.use-forward-headers=true server.tomcat.remote-ip-header=x-forwarded-for server.tomcat.protocol-header=x-forwarded-proto 

2. Do the following trick with your HttpSecurity configuration.

 // final HttpSecurity http = ... // Probably it will be in your 'WebSecurityConfigurerAdapter.configure()' http.requiresChannel() .anyRequest().requiresSecure() 

Source - Spring Boot Reference

84.3 Enabling HTTPS when working with a proxy server

+5
source

All Articles