Spring Boot HTTPS
最后修改于 2023 年 7 月 24 日
在本文中,我们将展示如何在 Spring Boot 应用程序中使用 HTTPS 设置安全通信。
Spring 是一个流行的 Java 应用程序框架,而 Spring Boot 是 Spring 的一个演进,它有助于轻松创建独立的、生产级的基于 Spring 的应用程序。
HTTPS
超文本传输安全协议 (HTTPS) 是一种用于互联网通信的安全通信协议。它确保数据完整性和数据保密性。它是 HTTP 协议的扩展。在 HTTPS 中,通信协议使用传输层安全协议 (TLS) 或(过去)安全套接字层 (SSL) 进行加密。该协议通常被称为 HTTP over TLS 或 HTTP over SSL。
SSL(安全套接字层)是一种行业标准协议,通过保护在系统之间发送的所有敏感数据来确保互联网连接的安全。它防止入侵者读取和修改任何传输的信息。TLS(传输层安全)是 SSL 的一个更近期的安全版本。如今,由证书颁发机构提供的证书仅基于 TLS。这两个术语通常可以互换使用。
在 Java 中,truststore 通常用于存储受信任实体的证书。它维护一个由其信任的所有受信任方的证书组成的存储库。Keystore 用于存储服务器密钥(公钥和私钥)以及签名证书。
创建 TLS 证书
我们可以从认证机构 (CA) 获取 TLS 证书,例如 Verison、Symantec 或 Digicert。这需要时间和金钱。(有一个流行的免费自动化认证机构称为 Let's Encrypt。)另一种选择,非常适合开发目的,是创建自签名证书。
在本文中,我们使用自签名证书。
创建自签名证书
首先,我们创建一个自签名证书。证书可以使用以下两种证书格式之一:PKCS12
或 JKS
。
公钥加密标准 (PKCS12) 是一种受密码保护的格式,可以包含多个证书和密钥;它是一种被广泛使用的行业格式。Java KeyStore (JKS) 是一种类似于 PKCS12 的专有格式。它仅限于 Java 环境。
我们可以使用 keytool
或 OpenSSL 工具从命令行生成证书。Keytool 随 Java 运行时环境一起提供,OpenSSL 可以从 https://www.openssl.org 下载。
Keytool
Java keytool
管理一个密钥库(数据库),其中包含加密密钥、X.509 证书链和受信任证书。
$ keytool -genkeypair -alias mycert -keyalg RSA -keysize 2048 \ -storetype PKCS12 -keystore zetcode.p12 -validity 365
使用 keytool
,我们生成一组加密密钥并将它们存储在一个新的密钥库中。可以在同一个密钥库中存储多个密钥对,每个密钥对都由一个唯一的别名标识。
如果我们没有像在这种情况下那样显式指定密码,则该工具将为密钥库和一些其他选项请求一个密码。
-genkeypair
选项生成一个密钥对(一个公钥和相关的私钥)。它将公钥包装成一个 X.509 v3 自签名证书,该证书存储为一个单元素证书链。此证书链和私钥存储在由别名标识的新密钥库条目中。-alias
选项为新的密钥对指定一个名称。-keyalg
选项指定用于生成密钥对的算法,并且 keysize
值指定要生成的每个密钥的大小。
-storetype
指定存储类型,可以是 JKS 或 PKCS12。-keystore
为新存储指定一个名称。-validity
选项指定证书的有效天数。
Spring Boot HTTPS 示例
以下应用程序演示了如何使用先前创建的自签名证书设置 HTTPS。此外,我们将 HTTP 流量重定向到 HTTPS。
build.gradle ... src ├───main │ ├───java │ │ └───com │ │ └───zetcode │ │ │ Application.java │ │ ├───config │ │ │ WebConfig.java │ │ └───controller │ │ MyController.java │ └───resources │ application.properties │ zetcode.p12 └───test └───java
这是项目结构。我们将密钥库数据库移动到 src/main/resources
目录。
plugins { id 'org.springframework.boot' version '3.1.1' id 'io.spring.dependency-management' version '1.1.0' id 'java' } group = 'com.example' version = '0.0.1-SNAPSHOT' sourceCompatibility = '17' repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' }
这是 Gradle 构建文件。这是一个非常简单的 Web 应用程序,因此我们只需要 spring-boot-starter-web
启动器。
server.port=8443 server.ssl.key-alias=mycert server.ssl.key-store-password=s$cret server.ssl.key-store=classpath:zetcode.p12 server.ssl.key-store-provider=SUN server.ssl.key-store-type=PKCS12
在 application.properties
中,我们配置应用程序。我们指定端口、密钥对别名、密钥库密码、密钥库位置、提供程序和类型。
package com.zetcode.config; import org.apache.catalina.Context; import org.apache.catalina.connector.Connector; import org.apache.tomcat.util.descriptor.web.SecurityCollection; import org.apache.tomcat.util.descriptor.web.SecurityConstraint; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.servlet.server.ServletWebServerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class WebConfig { @Bean public ServletWebServerFactory servletContainer() { var tomcat = new TomcatServletWebServerFactory() { @Override protected void postProcessContext(Context context) { var securityConstraint = new SecurityConstraint(); securityConstraint.setUserConstraint("CONFIDENTIAL"); var collection = new SecurityCollection(); collection.addPattern("/*"); securityConstraint.addCollection(collection); context.addConstraint(securityConstraint); } }; tomcat.addAdditionalTomcatConnectors(redirectConnector()); return tomcat; } private Connector redirectConnector() { var connector = new Connector("org.apache.coyote.http11.Http11NioProtocol"); connector.setScheme("http"); connector.setPort(8080); connector.setSecure(false); connector.setRedirectPort(8443); return connector; } }
在 WebConfig
中,我们配置 Tomcat(默认的 Spring Boot 嵌入式服务器)以将 HTTP 流量自动重定向到 HTTPS。
package com.zetcode.controller; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class MyController { @GetMapping(value = "/hello", produces = MediaType.TEXT_PLAIN_VALUE) public String hello(){ return "hello there"; } }
在我们的控制器中,我们有一个简单的页面,它返回一条文本消息。
package com.zetcode; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
Application
是设置 Spring Boot 应用程序的入口点。
我们使用 ./gradlew -q bootRun
运行应用程序,并导航到 https://:8443/hello
。请注意,当应用程序第一次启动时,浏览器会显示一个巨大的错误消息,提示网站证书不受信任。我们需要为我们的应用程序添加一个安全例外才能使其工作。
在本文中,我们已经展示了如何创建自签名证书,并使用此证书为 HTTPS 设置 Spring Boot 应用程序。