HTTPS login with Spring Security redirects to HTTP

39,290

Solution 1

Your spring configuration should be agnostic to the used protocol. If you use something like "requires-channel", you'll run into problems sooner or later, especially if you want to deploy the same application to a development environment without https.

Instead, consider to configure your tomcat properly. You can do this with RemoteIpValve. Depending on which headers the loadbalancer sends, your server.xml configuration needs to contain something like this:

<Valve
   className="org.apache.catalina.valves.RemoteIpValve"
   internalProxies=".*"
   protocolHeader="X-Forwarded-Proto"
   httpsServerPort="443"
   />

Spring will determine the absolute redirect address based on the ServletRequest, so change the httpsServerPort if you are using something else than 443:

The httpsServerPort is the port returned by ServletRequest.getServerPort() when the protocolHeader indicates https protocol

Solution 2

If it is a Spring Boot application (I use currently the 2.0.0 release), the following configuration within the application.properties file should be enough:

server.tomcat.protocol-header=x-forwarded-proto

This worked for me on AWS with an load balancer at the front.

For Spring Boot < 2.0.0 it should also work (not tested)

Solution 3

I had the same problem with Spring Boot behind Google Kubernetes. Adding these two lines to application.properties did it for me

server.tomcat.remote-ip-header=x-forwarded-for
server.tomcat.protocol-header=x-forwarded-proto

Source: https://docs.spring.io/spring-boot/docs/current/reference/html/howto-security.html#howto-enable-https

Solution 4

Solution was two fold

(1) application.yml

server:
  use-forward-headers: true

(2) in servers /etc/apache2/sites-enabled/oow.com-le-ssl.conf

RequestHeader set X-Forwarded-Proto https
RequestHeader set X-Forwarded-Port 443

(2.1) and enabled the apache module with

sudo a2enmod headers

Put it together with the help of this and this

Solution 5

One way I got this working is by adding the following config

<http auto-config="true" use-expressions="true" entry-point-ref="authenticationEntryPoint" >
    <form-login login-page="/login.jsf" authentication-failure-url="/login.jsf?login_error=t" always-use-default-target="true" default-target-url="xxxxx" />
    <logout logout-url="/logout" logout-success-url="/logoutSuccess.jsf" />
    ...
</http>

Had to add always-use-default-target="true" and default-target-url="https://....". Not the ideal way as you need to hard code the url in the config.

Share:
39,290
Thody
Author by

Thody

Updated on June 28, 2021

Comments

  • Thody
    Thody almost 3 years

    I have a Spring web app, secured with Spring Security, running on EC2. In front of the EC2 instance is an Elastic Load Balancer with an SSL cert (https terminates at the load balancer ie. port 443 -> port 80), so from Tomcat's perspective, inbound requests are HTTP.

    My login form submits to https, however the subsequent redirect goes to http (success or fail). The authentication was successful, and I can go back to https and I'm logged in.

    My login configuration looks like so:

    <security:form-login
        default-target-url="/home"
        login-page="/"
        login-processing-url="/processlogin"
        authentication-failure-url="/?login_error=1"/>
    

    What do I need to change to make default-target-url and authentication-failure-url go to https?

    • Tomcat 6
    • Spring Security 3.0.x
  • marcelj
    marcelj over 10 years
    After login, Spring will still send a Location header with a http address. The user won't notice, because your apache will instantly redirect him to https again, but it is still a serious security problem, because the browser will send the session cookies over an unsecure channel.
  • Andrew Westberg - BCSH
    Andrew Westberg - BCSH over 10 years
    @marcelj - I just ran it through firebug and you're correct. I'll try to figure out a better solution and revise my answer if I do.
  • Nathan Ward
    Nathan Ward over 9 years
    @marcelj, Could you explain why this is a serious security risk or provide a reference that describes the risk?
  • Paŭlo Ebermann
    Paŭlo Ebermann over 9 years
    @NathanWard If an attacker intercepts the HTTP request, she can serve a HTTP login form and retrieve the credentials.
  • John A
    John A over 5 years
    This issue had been driving me crazy. This suggestion worked perfectly. Thanks!
  • Jeff Sheets
    Jeff Sheets over 5 years
    Thanks! I also had to add server.use-forward-headers=true docs.spring.io/spring-boot/docs/current/reference/html/…
  • Imtiaz Shakil Siddique
    Imtiaz Shakil Siddique over 4 years
    The actual code which loads http scheme from servlet request can be found from: docs.spring.io/spring-security/site/docs/current/api/org/… From there one can find out that, Spring actually collects http scheme from servlet request. So @marcelj solution is the perfect answer for this!
  • jumping_monkey
    jumping_monkey about 4 years
    server.use-forward-headers=true is deprecated. Instead, use server.forward-headers-strategy=native, and DO NOT set it to framework unless you trust your reverse-proxy ;-).
  • vilvic
    vilvic over 3 years
    We were faced with the error "The information you're about to submit is not secure" on chrome. To solve the problem we added server.forward-headers-strategy: native to application.yml and added the following line to traefik in our docker compose "traefik.frontend.headers.customResponseHeaders=X-Forwarded-‌​Proto:https||X-Forwa‌​rded-Port:443"