user-icon Andreas Falk
30. July 2018
timer-icon 7 min

Secure Spring Boot Applications with TLS and HTTP/2

These days, using secure connections via HTTPS (TLS) and the much more efficient HTTP/2 protocol should be a matter of course for all web applications. You can get a domain validated certificate from Let's Encrypt at no cost to setup transport layer security (TLS). Also HTTP servers and web browsers widely adopted HTTP/2 already. Starting with Java 9 and Spring Boot 2 / Spring 5 you can easily enable web applications to use secure HTTPS/TLS connections and the HTTP/2 protocol.

As a developer most of the time you work in your local environment and cannot use any of the officially validated TLS certificates here. Instead, developers are using unsecured connections or self-signed certificates resulting in browser warnings. By setting up a private certificate authority (CA) you will be able to use secured connections without these annoying browser warnings.

In the next sections, you will see step by step how to achieve this.

HTTP/2

According to the specification you can use the HTTP/2 protocol in two variants:

  1. HTTP/2 over plaintext HTTP (h2c)
  2. HTTP/2 over encrypted HTTPS (h2)

In practice, all web browsers only support the second variant HTTP/2 over HTTPS (h2).
Therefore you have to follow the path to secure your web application using HTTPS connections with TLS (transport layer security).

TLS

When you read about HTTPS you always stumble upon the terms SSL or TLS.
This is where usually the misconception begins:

  • HTTP Secure (HTTPS) is basically HTTP over a TLS connection.
  • Secure Sockets Layer (SSL) is the predecessor of TLS and as such is deprecated and insecure. All SSL versions (1.0, 2.0, 3.0) are vulnerable and should not be used anymore.
  • Transport Layer Security (TLS) as the successor of SSL is the protocol that should be used for HTTPS. Currently, TLS 1.3 is the one to use with TLS 1.2 still being relevant for compatibility.

Using HTTPS connections provides the following layers of protection:

  1. Encryption: All exchanged data is encrypted, so nobody can grab your data just by “listening” to the connection.
  2. Data integrity: Exchanged data cannot be modified or corrupted during transfer without being detected.
  3. Authentication: Proves that you communicate with the intended website. This is why you need a certificate in addition to the private/public key encryption

We will follow the path to establish valid TLS connections in these steps:

  1. Generate a strong private and public key
  2. Create a Certificate Signing Request (CSR) and send it to a Certificate Authority (CA)
  3. Install the CA-provided certificate in webserver (i.e. using a java key store in embedded tomcat of spring boot application).

In this blog post, I will focus on local development. Therefore in step 2, you will not send the CSR to an official CA. Instead, we will set up our private Certificate Authority in the next section.

Setting up a private Certificate Authority (CA)

System Requirements

You need the following software to perform all steps of this blog post:

  • First of all, you need at least a Java 9 JDK or newer (with JDK 11 being the next long term alternative)
  • Furthermore for generating certificates and performing sign requests, you need the keytool which is part of the JDK.

Usually, you use self-signed certificates for local development. But these certificates always generate warnings in web browsers and mark all requests as insecure.

unsecure https ssl tls browser warning

Currently, web browsers also enable the HTTP/2 protocol for TLS certificates having validation warnings. But you as a security-aware developer should always be scared when you see such warnings.
Consequently to get rid of this warning you have to create a certificate that is trusted by your web browser. To achieve this we have to set up our own private certificate authority (CA). Using the private certificate authority you can later issue a root certificate.
Finally, you can import this root certificate as a new authority in your web browser and sign your server certificate with it.

Certificate for Root CA

Before you start please create the following subdirectories first:

  • root-ca  (You will store all artifacts required for setting up a certificate authority here)
  • server (You will store all artifacts required for your signed server certificate here)

In the first step you need to generate private/public keys and the corresponding certificate for the root CA. Later you will use this root certificate in the section for signing your server certificate.

This command creates a new java keystore ca.jks in folder root-ca containing the private and public keys. The certificate uses the RSA algorithm with a bit length of 3072 and is valid for 10 years. This includes also the distinguished name CN=My CA,OU=Development,O=My Organization,C=DE.

Now you export the certificate to file ca.pem in the subdirectory root-ca using this command:

Signed Server Certificate

In the next step you create another new java key store file containing the private/public keys for the server certificate.
The private key is required to generate the certificate signing request. The CA uses the public key for validating the certificate signing request.


You can find the new java key store server.jks in the subdirectory server. Again we use the RSA algorithm with a bit length of 3072 and set it valid for 10 years.

Now you will continue with the generation of the signing request for your server certificate. This creates the file server.csr in the subdirectory server.


With the next command, you will now sign and export your server certificate using the file server.csr from the previous step.


To achieve the required valid chain of trust between the root ca and the signed server certificate you have to perform the following last step.


This imports the certificate for the root ca and updates the existing (unsigned) server certificate with the signed one.
Finally, we have a java key store containing the full chain of certificates ready to be used in our spring boot application.

Using the Keytool to manually perform all steps for creating the certificates is good for learning. But if you want to automate these things for subsequent usages then mkcert is a great tool for that.

Import Root CA Certificate into a web browser

Let’s continue with enabling trust in your web browser for our private certificate authority.
We will use the chrome browser here to demonstrate this. Just open the settings in chrome, expand the “Advanced” section and then go to “Manage certificates“.
Here you import the root ca certificate from file ./root-ca/ca.pem into the browser as a new authority. Don’t forget to mark the first checkbox as shown in the following picture.

import certificate into chrome

Create Spring Boot Application

In an earlier blog post, I have described how easy you can create a new web application with basic security in just 5 minutes.
You follow the same steps by using start.spring.io, but this time we will use Kotlin instead of Java.

Create a spring boot application

To get simple feedback when testing our simple application just add the following rest controller class DemoController to our new spring boot application.
This just prints out an “It works” in the browser when navigating to localhost:8080.


But still, we are using unsecured HTTP connections here. It is time for you to change this just now!

Configure TLS

To enable TLS put the following entries into your application.properties file.


With these property entries you will change the following behavior:

  • The application is started on port 8443 instead of port 8080 (by convention this is the usual port for HTTPS connections).
  • Use our new java key store server.jks which is of type PKCS12 and is opened with given store password
  • Define the alias of public/private key to use for the server certificate with the corresponding key password

Important: Please do not forget to copy the java key store file server.jks you have created in the previous section into the src/main/resource folder of the new spring boot application.

Configure HTTP/2

You can now switch on HTTP/2 by adding the following entry to application.properties.

Configure Security

Before we can start our application we need to tweak the security configuration a bit.
The reasons for manually configuring this are:

  1. We want to switch off HTTP Strict Transport Security (HSTS) for local development. If we leave this enabled (the default setting for HTTPS connections in spring security) all our applications running on localhost will be forced to use HTTPS by the web browser. This may not be the desired behavior – especially for other local applications that are not configured for HTTPS connections.
  2. You can authenticate yourself to our application by using either basic authentication or form based login
  3. All requests are secured by default (i.e. require authentication first)
  4. We want to have our own user with encrypted password instead of default one (using clear text password)

Let’s try it

Now start the spring boot application and after successful start direct your browser to URL https://localhost:8443.
Here you will notice the secure HTTPS connection shown as valid by the browser.

After providing the user credentials “user” and “secret” you will get the message “it works“.

it works with TLS and HTTP2

That’s it for this tutorial on Spring Boot Apps with HTTP/2 and TLS.

You can grab the complete accompanying project code from my GitHub repository at https://github.com/andifalk/ssl-demo.

Comment article