July 30, 2018

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 any more.
  • Transport Layer Security (TLS) as the successor of SSL is the protocol that should be used for HTTPS. Currently TLS 1.2 is the one to use with TLS 1.3 being just around the corner.

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 web server (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 setup 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. In this post all keystores are stored in PKCS12 format which is the default starting with JDK9. If you use JDK 8 then you have to specify the format using the keytool option -storetype.

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 setup 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 new authority in your web browser and sign your server certificate with it.

Certificate for Root CA

Before you start please create the following sub directories 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 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 subdirectory server. Again we use the RSA algorithm with bit length of 3072 and set it valid for 10 years.

Now you will continue with generation of the signing request for your server certificate. This creates the file server.csr in sub directory 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.

Import Root CA Certificate into 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 new authority. Don’t forget to mark the first checkbox as shown on 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 a 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 a “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 corresponding key password

Important: Please do not forget to copy the java key store file server.jks you have created in 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.

Leave a Comment

10 comments

  1. Nice post!

    But to make it work properly I had to make two changes:
    1. set “server.ssl.key-store-type” to “JKS”, since the keystore was not created in PKCS12 format
    2. set “server.ssl.key-alias” to “localhost”, as this was the alias used in the cert generation steps

  2. Thanks for your remarks.
    1. The PKCS12 format is the default setting since JDK 9. As mentioned in the blog post JDK 9 was set as minimum requirement because of HTTP/2 support. If you use JDK 8 or earlier you have to specify the format using the -storetype option
    2. Yes the alias reference was wrong, I updated the blog post for this.

  3. L

    Hello, thank you for this guide !

    I was wondering, is that realy required to import the ca cert to the server keystore ? And why ?

  4. You always need the full chain of trust when using TLS certificates. Therefore the CA certificate must be in the server keystore as well. The same is true if you use for example apache http server with letsencrypt certificates. There you always have to specify paths to root and intermediate certificates as well.

  5. v

    can i once see a video on it ?
    can you tell me in this article you have used ssl or TLS? or
    can i see two diffrent project one on ssl protocol and another one using TLS protocol?

  6. What video do you refer to? There is no video available.
    SSL with all versions (1,2,3) should not be used any more as these are all broken.
    Therefore this blog post only uses TLS.

  7. v

    i’m not able to run project after importing project form git in eclipse ,and
    how can i see this is TLS certificate or SSL certificate

  8. SSL/TLS are cryptographic protocols. For TLS you need a X509 certificate.
    When importing into eclipse please make sure you use JDK 9 and a compatible eclipse version

  9. v

    All are doing same certificate generation staff in x509 authentication also, only difference is they used very small configuration http.x509 for avoiding default spring security login password.
    that’s why i’m looking for two different project one on ssl certificate or another one using TLS, looking both project it will be simple to differentiate b/t ssl and tls

  10. A

    Thanks! All it works for me, but when I change port to 443, I get error “Server closed connection”. Do you know why?

By continuing to use the site, you agree to the use of cookies. more information

The cookie settings on this website are set to "allow cookies" to give you the best browsing experience possible. If you continue to use this website without changing your cookie settings or you click "Accept" below then you are consenting to this.

Close