运行在内嵌Tomcat、Jetty或Undertow中的Spring Boot应用,默认启动后监听的是HTTP端口,请求报文以明文方式在链路上传输。只要网络路径中出现不可信节点,账号、会话标识、接口返回数据都可能被截获或篡改。启用HTTPS并不是修改业务代码,而是把TLS证书和私钥配置到Web容器上,让TLS握手在TCP连接建立后、业务数据发送前完成。这个过程包含证书生成、密钥库格式转换、配置项加载、端口重定向以及客户端证书校验等环节。

本文以Spring Boot内嵌Tomcat为例,给出从证书准备到生产验证的完整配置。其他内嵌容器的配置思路类似,核心属性都集中在server.ssl命名空间下,只是HTTP跳转部分稍有差异。
一、准备证书并生成PKCS12密钥库
Java生态通常使用KeyStore保存证书和私钥,Spring Boot默认支持PKCS12格式。对于本地开发或内网测试,可以用JDK自带的keytool命令直接生成自签名证书。以下命令会创建一个名为keystore.p12的文件,密钥别名为springboot,有效期为3650天,算法采用RSA。
keytool -genkeypair -alias springboot -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore keystore.p12 -validity 3650
执行后需要输入密钥库密码和证书主体信息,例如姓名、组织、城市等。这里的姓名通常填写域名或服务器标识,本地测试可写localhost。自签名证书可以满足开发调试,但浏览器会提示证书不受信任,因为签发者不在系统信任链中。如果服务要面向公网,建议向权威CA申请证书,或者在企业内部搭建私有CA并分发根证书。
很多团队已经持有CA签发的PEM格式证书和私钥,例如cert.pem和key.pem。Spring Boot虽然也能加载PEM,但早期版本对PEM直接配置支持不统一,PKCS12是更稳妥的中间格式。可以用openssl命令转换:
openssl pkcs12 -export -in cert.pem -inkey key.pem -out keystore.p12 -name springboot -certfile ca-chain.pem
这里-certfile参数用于附带中间证书,把服务证书和中间CA链写入同一个密钥库。缺少中间证书时,某些客户端可以自动下载,但移动端或严格校验的服务端会握手失败。转换完成后,将keystore.p12放到Spring Boot工程的src/main/resources目录下,并确保打包时不会被过滤。
二、在Spring Boot中启用HTTPS
Spring Boot的HTTPS配置集中在application.yml或application.properties中。下面配置说明使用YAML格式,将服务监听端口切到8443,并加载上一步生成的密钥库。
server:
port: 8443
ssl:
enabled: true
key-store: classpath:keystore.p12
key-store-password: changeit
key-store-type: PKCS12
key-alias: springboot
server.port从默认的8080改为8443,这样应用启动后不再直接暴露HTTP端口。server.ssl.enabled显式开启TLS,key-store指向classpath下的密钥库文件。key-store-password是生成密钥库时设置的密码,key-store-type必须与文件格式一致,如果文件扩展名是.p12但类型写成JKS,启动时会抛出类型不匹配错误。key-alias指定要使用的证书条目,如果密钥库中只包含一个条目,该项可以省略,但显式写出来能避免多条目时的歧义。
如果使用properties文件,等价配置为:
server.port=8443 server.ssl.enabled=true server.ssl.key-store=classpath:keystore.p12 server.ssl.key-store-password=changeit server.ssl.key-store-type=PKCS12 server.ssl.key-alias=springboot
保存配置后启动应用,控制台应显示Tomcat started on port(s): 8443 (https)等类似日志。访问https://localhost:8443时,浏览器会开始TLS握手。如果是自签名证书,浏览器会警告证书不受信任,需要手动继续或导入证书。这个警告说明TLS已经生效,只是证书链不受系统信任,不能说明配置失败。
三、实现HTTP自动跳转到HTTPS
仅将端口切到8443后,用户输入http://localhost:8080会直接连接失败,因为8080端口已经不再监听。实际部署时,用户通常不会主动输入https前缀,所以需要让HTTP请求自动跳转到HTTPS。对于Tomcat内嵌容器,可以通过额外注册一个监听8080的Connector,并设置redirectPort为8443来实现。
下面的Java配置类会在Tomcat容器上增加HTTP连接器,并给所有请求添加安全约束,使其自动转发到HTTPS端口。匿名内部类中重写postProcessContext方法,就是对当前Context追加CONFIDENTIAL约束。
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 HttpsRedirectConfig {
@Bean
public ServletWebServerFactory servletContainer() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
@Override
protected void postProcessContext(Context context) {
SecurityConstraint securityConstraint = new SecurityConstraint();
securityConstraint.setUserConstraint("CONFIDENTIAL");
SecurityCollection collection = new SecurityCollection();
collection.addPattern("/*");
securityConstraint.addCollection(collection);
context.addConstraint(securityConstraint);
}
};
tomcat.addAdditionalTomcatConnectors(createHttpConnector());
return tomcat;
}
private Connector createHttpConnector() {
Connector connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
connector.setScheme("http");
connector.setPort(8080);
connector.setSecure(false);
connector.setRedirectPort(8443);
return connector;
}
}
这个配置保留了8080端口,当请求到达HTTP连接器时,Tomcat会根据安全约束返回302重定向,Location指向8443端口。对于纯API服务,也可以不保留8080端口,直接要求客户端使用HTTPS;但面向浏览器或需要兼容旧客户端的场景,跳转能减少用户手工修改地址的成本。
如果应用前面已经挂了Nginx或云负载均衡,也可以在网关层完成HTTP到HTTPS的跳转。这种方式下,Spring Boot只需处理HTTPS或通过X-Forwarded-Proto头感知原始协议,网关统一管理证书还能简化多实例的证书更新。两种方案可以并存,但要避免网关和后端都配置跳转导致的重定向循环。
四、证书信任链与常见启动问题
自签名证书启动后在浏览器中会显示不安全,并不是因为TLS链路没有建立,而是客户端找不到可信的签发者。生产环境使用CA证书时,务必确认Spring Boot加载的密钥库包含完整证书链。使用openssl转换时如果漏掉-certfile参数,服务端只返回自己的证书,中间CA证书缺失会导致部分客户端握手失败。可以通过openssl s_client -connect命令查看服务端返回的证书链,确认签发者层级是否完整。
openssl s_client -connect localhost:8443 -showcerts
另一个容易踩坑的地方是密钥库密码。很多团队把测试环境的密码直接提交到配置文件,但生产环境建议使用环境变量注入,例如在YAML中写成${KEYSTORE_PASSWORD},然后由部署平台或启动脚本提供实际值。这样既能保护私钥,也方便不同环境切换证书。如果密钥库密码包含特殊字符,还要注意YAML解析时的转义规则。
如果应用在启动时报出Protocol handler start failed、port already in use或SSL配置错误,可以先检查8443端口是否被占用,以及密钥库文件是否真的在classpath中。打包后的JAR中可以使用jar tf命令查看资源是否存在。对于Windows环境,keytool路径通常位于JDK安装目录的bin子目录,例如C:\Program Files\Java\jdk-17\bin,需要保证PATH配置正确。最后,如果希望只允许TLS1.2及以上协议,可以在配置中增加server.ssl.protocol和server.ssl.enabled-protocols,减少旧协议带来的降级攻击风险。
以上配置完成后,应用就具备了基本的HTTPS通信能力。对安全性要求更高的场景,还可以进一步结合HSTS响应头、证书自动续期和密钥保护机制,把TLS从能用到用好。
Spring BootHTTPSSSL/TLS修改时间:2026-09-20 18:32:33