I just announced the newSpring Security 5 modules (primarily focused on OAuth2) in the course:

>> CHECK OUT LEARN SPRING SECURITY

1. Overview

This tutorial shows how to use HTTPS to protect your application’s login page using Spring’s Channel Security feature.

Using HTTPS for authentication is crucial to protect the integrity of sensitive data when in transport.

The article builds on top of the Spring Security Login tutorial by adding an additional layer of security. We highlight the steps needed to secure the authentication data by serving the login page through the encoded HTTPS channel.

2. Initial Setup Without Channel Security

Let’s start out with the security configuration explained in the aforementioned article.

The web-app allows users to access:

  1. /anonymous.html without authentication,
  2. /login.html, and
  3. other pages (/homepage.html) after a successful login.

The access is controlled by the following configuration:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests() 
      .antMatchers("/anonymous*")
      .anonymous();

    http.authorizeRequests()
      .antMatchers("/login*")
      .permitAll();

    http.authorizeRequests()
      .anyRequest()
      .authenticated();

Or via XML:

<http use-expressions="true">
    <intercept-url pattern="/anonymous*" access="isAnonymous()"/>
    <intercept-url pattern="/login*" access="permitAll"/>
    <intercept-url pattern="/**" access="isAuthenticated()"/>
</http>

At this point, the login page is available at:

http://localhost:8080/spring-security-login/login.html

Users are able to authenticate themselves through HTTP, however this is insecure as passwords will be sent in plain text.

3. HTTPS Server Configuration

To only deliver the login page over HTTPS your web-server must be able to serve HTTPS pages. This requires that SSL/TLS support is enabled.

Note that you can either use a valid certificate or, for testing purposes, you can generate your own.

Let’s say we’re using Tomcat and rolling our own certificate. We’ll first need to create a keystore with a self-signed certificate.

Generating the keystore can be done issuing the following command in the terminal:

keytool -genkey -alias tomcat -keyalg RSA -storepass changeit -keypass changeit -dname 'CN=tomcat'

This will create a private a key and a self-signed certificate in the default keystore for your user profile, in your home folder.

The next step is to edit conf/server.xml to make it look like this:

<Connector port="8080" protocol="HTTP/1.1"
   connectionTimeout="20000"
   redirectPort="8443" />

<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
   maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
   clientAuth="false" sslProtocol="TLS"
   keystoreFile="${user.home}/.keystore" keystorePass="changeit" />

The second SSL/TLS <Connector> tag is usually commented out in the config file so uncommenting and adding keystore information is all that is needed. Further information is available in Tomcat’s related documentation.

With the HTTPS configuration in place, the login page can now be served under the following URL as well:

https://localhost:8443/spring-security-login/login.html

Web-servers other than Tomcat would require different but likely similar configuration.

4. Configuring Channel Security

At this point, we are able to serve the login page both under HTTP and HTTPS. This section explains how to mandate the usage of HTTPS.

To require HTTPS for the login page modify your security configuration by adding the following:

http.requiresChannel()
  .antMatchers("/login*").requiresSecure();

Or add the requires-channel=”https” attribute to your XML config:

<intercept-url pattern="/login*" access="permitAll" requires-channel="https"/>

After this point users could login only via HTTPS. All relative links e.g. a forward to /homepage.html will inherit the protocol of the original request and will be served under HTTPS.

When mixing HTTP and HTTPS request inside a single web app, there are additional aspects to be aware of and that require further configuration.

5. Mixing HTTP and HTTPS

From the security perspective, serving everything over HTTPS is good practice and a solid goal to have.

However, if using HTTPS exclusively is not an option, we can configure Spring to use HTTP by appending the following to the config:

http.requiresChannel()
  .anyRequest().requiresInsecure();

Or add requires-channel=”http” attributes to the XML:

<intercept‐url pattern="/**" access="isAuthenticated()" requires‐channel="http"/>

This instructs Spring to use HTTP for all requests that are not explicitely configured to use HTTPS, but at the same time it breaks the original login mechanism. The following sections explain the underlying cause.

5.1. A Custom Login Processing URL over HTTPS

The security configuration in the original security tutorial contains the following:

<form-login login-processing-url="/perform_login"/>

Without forcing /perform_login to use HTTPS a redirect would happen to the HTTP variant of it, losing the login information sent with the original request.

To overcome this we need to configure Spring to use HTTPS for the processing URL:

http.requiresChannel()
  .antMatchers("/login*", "/perform_login");

Notice the extra argument /perform_login passed to the antMatchers method.

The equivalent in the XML configuration requires adding a new <intercept-url> element to the config:

<intercept-url pattern="/perform_login" requires-channel="https"/>

If your own application is using the default login-processing-url (which is /login) you don’t need to configure this explicitly as the /login* pattern already covers that.

With the configuration in place, users are able to login, but not to access authenticated pages e.g. /homepage.html under the HTTP protocol, because of Spring’s session fixation protection feature.

5.2. Disabling session-fixation-protection

Session fixation is a problem which can’t be avoided when switching between HTTP and HTTPS.

By default Spring creates a new session-id after a successful login. When a user loads the HTTPS login page the user’s session-id cookie will be marked as secure. After logging in, the context will switch to HTTP and the cookie will be lost as HTTP is insecure.

To avoid this setting session-fixation-protection to none is required.

http.sessionManagement()
  .sessionFixation()
  .none();

Or via XML:

<session-management session-fixation-protection="none"/>

Disabling session fixation protection might have security implications, therefore you need to weigh the pros and cons if you’re concerned about session fixation based attacks.

6. Test

After applying all these configuration changes accessing /anonymous.html without logging in (using either http:// or https://) will forward you to the page through HTTP.

Opening other pages directly like /homepage.html should get you forwarded to the login page via HTTPS and after login you will be forwarded back to /homepage.html using HTTP.

7. Conclusion

In this tutorial we’ve taken a look on how to configure a Spring web-application which communicates through HTTP except for the login mechanism. However new modern web-applications should almost always use HTTPS exclusively as their communication protocol. Lowering security levels or turning off security features (like session-fixation-protection) is never a good idea.

This tutorial is based on the codebase available on GitHub. The channel security configuration can be enabled by listing https as an active Spring profile.

I just announced the new Spring Security 5 modules (primarily focused on OAuth2) in the course:

>> CHECK OUT LEARN SPRING SECURITY

newest oldest most voted
Notify of
Scott Stanlick
Guest
Scott Stanlick

How does http.requiresChannel().antMatchers(“/login*”).requiresSecure() operate when running in Spring Boot with POM packaging set to JAR

Eugen Paraschiv
Guest

Hey Scott – sure, the way the application is deployed doesn’t make much of a difference. You can deploy it as a traditional war, or you can run it as a Boot app with a fat jar – both are perfectly fine (as long as the Boot app is configured properly of course).
Cheers,
Eugen.

Gustavo Jungthon
Guest
Gustavo Jungthon

I have the same problem. But I use Spring 3.2. I tried to use your suggestion, but it did not work. The atributtes j_username and j_password remain in plain text in the request header. Can you help me?

Eugen Paraschiv
Guest

Hmm – that’s very interesting. The problem is – your note here isn’t really enough to get to the root of what’s going on. I’ll need an actual failing test or example – feel free to use the codebase of the article (link to Github at the end) and open a PR with a failing test.
I’d be happy to have a look.
Cheers,
Eugen.

Gustavo Jungthon
Guest
Gustavo Jungthon

I’m so sorry. But I got confused. Chrome dev tools was showing these attributes, but it is because it can capture before sending the request. Enabling HTTPS on the application server has resolved the issue.

Eugen Paraschiv
Guest

No worries, I’m glad you were able to work it out.
Cheers,
Eugen.