Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Require HTTPS with Spring Security behind a reverse proxy

I have a Spring MVC application secured with Spring Security. The majority of the application uses simple HTTP to save resources, but a small part processes more confidential information and requires an HTTPS channel.

Extract from the 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>

All worked fine until we decided to migrate it to the main server, where the application servers run behind reverse proxies. And as now HTTPS is processed by the reverse proxies the application server only sees HTTP requests, and disallows access to the /sec/** hierarchy.

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

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

I know I could report that part on proxies configuration, but the proxies administrator really does not like that solution, because there are many application behind the proxies and the configuration could grow to a non manageable state.

I an currently using Spring Security 3.2 with XML config, but I'm ready to accept answers based on Java config and/or more recent version.

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

like image 789
Serge Ballesta Avatar asked May 06 '15 12:05

Serge Ballesta


People also ask

How do I restrict URL in Spring Security?

Securing the URLs The most common methods are: authenticated(): This is the URL you want to protect, and requires the user to login. permitAll(): This is used for URL's with no security applied for example css, javascript. hasRole(String role): Restrict to single role.

What is the need for @EnableWebSecurity?

The @EnableWebSecurity is a marker annotation. It allows Spring to find (it's a @Configuration and, therefore, @Component ) and automatically apply the class to the global WebSecurity . If I don't annotate any of my class with @EnableWebSecurity still the application prompting for username and password.

Is WebSecurityConfigurerAdapter deprecated?

The type WebSecurityConfigurerAdapter is deprecated Well, it's because the developers of Spring framework encourage users to move towards a component-based security configuration.


1 Answers

Kind of a followup to NeilMcGuigan's answer that showed that the solution was servlet container side.

Tomcat is even better. There is a valve dedicated to masking the side effects of a reverse proxy. Extract from Tomcat documentation for Remote IP Valve:

Another feature of this valve is to replace the apparent scheme (http/https), server port and request.secure with the scheme presented by a proxy or a load balancer via a request header (e.g. "X-Forwarded-Proto").

Example of the valve configuration :

<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" />

That way with no other configuration of the application itself, the call to Request.isSecure() will return true if the request contains a header field of X-Forwarded-Proto=https.

I had thought of two other possibilities, but definitively prefere that one :

  • use a filter active before Spring Security ChannelProcessingFilter to wrap the request with a HttpServletRequestWrapper overriding isSecure() to process a X-Forwarded-Proto header - need writing and testing the filter and the wrapper
  • use a Spring BeanPostProcessor to look for a ChannelProcessingFilter and manually inject a ChannelDecisionManager able to consider the X-Forwarded-Proto header - really too low level
like image 124
Serge Ballesta Avatar answered Sep 27 '22 20:09

Serge Ballesta