怎麼爲你的springboot應用程序配置TLS和HTTP/2

使用TLS和HTTP/2保護SpringBoot應用程序

現在,通過HTTPS(TLS)使用安全連接和更高效的HTTP/2協議應該是所有web應用程序的理所當然的事情。您可以從Let's Encrypt獲取經過域驗證的證書,而無需設置傳輸層安全性(TLS)。HTTP服務器和web瀏覽器已經廣泛採用HTTP/2。從Java 9和Spring Boot 2/Spring 5開始,您可以輕鬆地讓web應用程序使用安全的HTTPS/TLS連接和HTTP/2協議。

作爲一名開發人員,大部分時間您都在本地環境中工作,不能在這裏使用任何經過正式驗證的TLS證書。相反,開發人員正在使用不安全連接或自簽名證書,從而導致瀏覽器警告。通過設置私有證書頒發機構(CA),您將能夠使用安全連接,而不會出現這些惱人的瀏覽器警告。

在接下來的部分中,您將逐步瞭解如何實現這一點。

HTTP/2協議

根據規範,您可以在兩種變體中使用HTTP/2協議:

明文HTTP上的HTTP/2(h2c)

加密HTTPS上的HTTP/2(h2)

實際上,所有的web瀏覽器都只支持第二種變體HTTP/2而不是HTTPS(h2)。

因此,您必須遵循以下路徑,使用帶有TLS(傳輸層安全性)的HTTPS連接來保護您的web應用程序。

TLS公司

當你讀到HTTPS的時候,你總是會偶然發現SSL或TLS這兩個術語。

這通常是誤解的開始:

HTTP安全(HTTPS)基本上是通過TLS連接的HTTP。

安全套接字層(SSL)是TLS的前身,因此不推薦使用,也不安全。所有SSL版本(1.0、2.0、3.0)都易受攻擊,不應再使用。

傳輸層安全性(TLS)作爲SSL的後繼協議應該用於HTTPS。目前,TLS 1.3是與tls1.2一起使用的,它仍然與兼容性相關。

使用HTTPS連接提供以下保護層:

加密:所有交換的數據都是加密的,因此沒有人可以通過“監聽”連接來獲取您的數據。

數據完整性:交換的數據在傳輸過程中不能被修改或損壞而不被檢測到。

認證:證明您與預期的網站進行了通信。這就是爲什麼除了私鑰/公鑰加密之外還需要證書的原因

我們將按照以下步驟建立有效的TLS連接:

生成強私鑰和公鑰

創建證書籤名請求(CSR)並將其發送到證書頒發機構(CA)

在webserver中安裝CA提供的證書(即在spring boot應用程序的嵌入式tomcat中使用java密鑰存儲)。

在這篇博文中,我將關注當地的發展。因此,在步驟2中,您不會將CSR發送到正式CA。相反,我們將在下一節中設置我們的私有證書頒發機構。

設置私有證書頒發機構(CA)

系統要求

您需要以下軟件來執行此博客文章的所有步驟:

首先,您至少需要一個Java 9 JDK或更新版本(JDK 11是下一個長期的替代方案)

此外,爲了生成證書和執行簽名請求,您需要作爲JDK一部分的keytool。

通常,您使用自簽名證書進行本地開發。但這些證書總是在web瀏覽器中生成警告,並將所有請求標記爲不安全。

目前,web瀏覽器還爲具有驗證警告的TLS證書啓用HTTP/2協議。但是作爲一個安全意識強的開發人員,當你看到這樣的警告時,你應該總是感到害怕。

因此,要消除此警告,您必須創建一個受web瀏覽器信任的證書。爲此,我們必須建立自己的私有證書頒發機構(CA)。使用專用證書頒發機構,以後可以頒發根證書。

最後,可以將此根證書作爲新的頒發機構導入到web瀏覽器中,並用它簽署服務器證書。

根CA的證書

開始之前,請先創建以下子目錄:

 

  • 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)

在第一步中,您需要爲根CA生成私鑰/公鑰和相應的證書。稍後,您將在服務器證書的簽名部分中使用此根證書。

1

keytool -genkeypair -keyalg RSA -keysize 3072 -alias root-ca -dname "CN=My Root CA,OU=Development,O=My Organization,C=DE" -ext BC:c=ca:true -ext KU=keyCertSign -validity 3650 -keystore ./root-ca/ca.jks -storepass secret -keypass secret

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:

 

1

keytool -exportcert -keystore ./root-ca/ca.jks -storepass secret -alias root-ca -rfc -file ./root-ca/ca.pem

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.

 

1

keytool -genkeypair -keyalg RSA -keysize 3072 -alias localhost -dname "CN=localhost,OU=Development,O=My Organization,C=DE" -ext BC:c=ca:false -ext EKU:c=serverAuth -ext "SAN:c=DNS:localhost,IP:127.0.0.1" -validity 3650 -keystore ./server/server.jks -storepass secret -keypass secret

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.

 

1

keytool -certreq -keystore ./server/server.jks -storepass secret -alias localhost -keypass secret -file ./server/server.csr

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

 

1

keytool -gencert -keystore ./root-ca/ca.jks -storepass secret -infile ./server/server.csr -alias root-ca -keypass secret -ext BC:c=ca:false -ext EKU:c=serverAuth -ext "SAN:c=DNS:localhost,IP:127.0.0.1" -validity 3650 -rfc -outfile ./server/server.pem

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.

 

1

2

keytool -importcert -noprompt -keystore ./server/server.jks -storepass secret -alias root-ca -keypass secret -file ./root-ca/ca.pem

keytool -importcert -noprompt -keystore ./server/server.jks -storepass secret -alias localhost -keypass secret -file ./server/server.pem

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.

 

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.

 

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.

 

1

2

3

4

5

6

@RestController

class DemoController {

 

@GetMapping("/")

fun index() = "It works"

}

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.

 

1

2

3

4

5

6

7

server.port=8443

server.ssl.enabled=true

server.ssl.key-store=classpath:server.jks

server.ssl.key-store-type=PKCS12

server.ssl.key-store-password=secret

server.ssl.key-alias=server

server.ssl.key-password=secret

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.

 

1

server.http2.enabled=true

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)

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

@Configuration

class WebSecurityConfiguration : WebSecurityConfigurerAdapter() {

 

override fun configure(http: HttpSecurity) {

http.headers().httpStrictTransportSecurity().disable() // (1)

.and().httpBasic().and().formLogin() // (2)

.and().authorizeRequests().anyRequest().authenticated() // (3)

}

 

@Bean // (4)

fun myUserDetails(): UserDetailsService = InMemoryUserDetailsManager (

User.withUsername("user")

.password("secret")

.passwordEncoder { passwordEncoder().encode(it) }

.roles("USER")

.build()

)

 

@Bean

fun passwordEncoder(): PasswordEncoder

      = PasswordEncoderFactories.createDelegatingPasswordEncoder()

}

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“.

 

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.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章