(最近上班摸鱼,随机整理一点知识...)
本篇介绍如何给springboot服务增加https端口;思路是先通过openssl生成证书,再跟后端服务结合起来。
0、前期准备
OpenSSL是一个开源的工具包,主要用于实现SSL和TLS协议,以及各种加密功能。它广泛用于生成证书、加密通信等。
在生成证书之前,先检查服务器上有无OpenSSL服务;执行命令:
openssl version
如果不能输出版本号,就需要先安装openssl;这里不做赘述。
1、生成自签名证书
1.1 生成包含加密后的私钥的密钥
openssl genrsa -des3 -out server.pass.key 2048
-des3
:用密码加密私钥(需交互输入密码)2048
:密钥长度(行业标准)- 生成的文件
server.pass.key
包含加密后的私钥
需要输入两次私钥密码;后续相关提示不做赘述,根据提示键入密码即可。
1.2 移除私钥的密码保护
openssl rsa -in server.pass.key -out server.key
- 输出
server.key
是未加密的私钥文件
1.3 生成证书签名请求(CSR)
openssl req -new -key server.key -out server.csr -subj "/C=CN/ST=Guangdong/L=Guangzhou/O=alibaba/OU=it/CN=iap-serv-framewrok-gateway"
-subj
:预置证书主题信息- 主题字段说明:
- /C=CN # 国家
- /ST=Guangdong # 省份
- /L=Guangzhou # 城市
- /O=alibaba # 组织
- /OU=it # 部门
- /CN=iap-serv-framewrok-gateway # 通用名称,需匹配域名(如果有),无域名就随意了,我这里是用服务id
1.4 使用 CSR 和私钥生成自签名证书
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
-days 365
:证书有效期(1年)- 输出
server.crt
是最终的数字证书,仅包含公钥证书(服务器身份凭证)。
1.5 将私钥和证书打包为PFX格式
openssl pkcs12 -export -out server.pfx -inkey server.key -in server.crt
- PFX(PKCS#12)是一种跨平台的标准格式
1.6 将PFX转换为Java专用的JKS格式 (非必要)
keytool -importkeystore -srckeystore server.pfx -srcstoretype pkcs12 -destkeystore server-cert.jks -deststoretype JKS -alias 1
-alias 1
:指定密钥别名
完成以上步骤后,建议只保留server.crt、server.pfx(或jks文件),清理不需要的其余文件;同时执行chmod 600命令修改下权限,提高安全性。
保留的两个文件作用如下:
.crt
文件:仅包含公钥证书,可直接对外分发,例如前端的HTTPS调用;.pfx
文件:包含私钥+公钥证书,需严格保密;
2、后端服务支持https
2.1 添加ssl配置
在springboot的配置文件中,加上:
server:
ssl:
key-store-type: PKCS12
key-store: classpath:server.pfx
key-store-password: [证书密码]
key-alias: 1
注意,这个server.pfx文件应该放在你服务的资源目录下,这个资源目录有默认的位置,这里不做赘述,建议是在服务启动时指定资源目录,并把所有配置放在这个目录下;做法详见我下一篇博客【SpringBoot服务部署(通用)-CSDN博客】;
2.2 代码支持
添加ssl配置后,原配置文件中的server.port会变为https端口;如果想保留http的端口,可以注入一个配置类,示例:
package com.alibaba.iap.serv.framework.gateway.config;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
import org.springframework.boot.web.server.WebServer;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.server.reactive.HttpHandler;
/**
* @project:iap-serv-framework
* @Created-Time:2023/12/7 15:09
* Author: medi
*/
@Configuration
public class WebServerConfig {
@Value("${http.port}")
private int httpPort;
@Autowired
private HttpHandler httpHandler;
private WebServer webServer;
@PostConstruct
public void start() {
NettyReactiveWebServerFactory factory = new NettyReactiveWebServerFactory(httpPort);
webServer = factory.getWebServer(httpHandler);
webServer.start();
}
@PreDestroy
public void stop() {
webServer.stop();
}
}
我的服务是网关gateway,${http.port}是我在配置文件中额外增加的http端口配置;
不同版本的springboot可能会有差异,思路一致。
3、验证HTTPS服务
重启服务,服务正常开启后,可以直接使用接口工具请求https地址了;
如果是curl的方式请求,则需要添加【-k】参数忽略证书校验。
彩蛋
这里提供一份自动化运行https自签名证书生成的脚本。适用于linux系统,前置需要安装自动化交互套件【expect】;
下面是脚本:拿来即用;(注:【SSL_KEYSTORE_PASSWORD】是环境变量,需要配置在调用方脚本中,也可直接替换为你的密码)
#!/usr/bin/expect
# 生成包含秘钥的加密密钥 server.pass.key
spawn openssl genrsa -des3 -out server.pass.key 2048
expect "Enter pass phrase for server.pass.key:"
send "$env(SSL_KEYSTORE_PASSWORD)\n"
expect "Verifying - Enter pass phrase for server.pass.key:"
send "$env(SSL_KEYSTORE_PASSWORD)\n"
expect eof
# 解密私钥
spawn openssl rsa -in server.pass.key -out server.key -passin env:SSL_KEYSTORE_PASSWORD
expect eof
# 生成证书签名请求(CSR)
spawn openssl req -new -key server.key -out server.csr -subj "/C=CN/ST=Guangdong/L=Guangzhou/O=eshore/OU=it/CN=iap-serv-framewrok-gateway"
expect eof
# 使用 CSR 和私钥生成自签名证书 有效期:1年
spawn openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
expect eof
# 生成包含私钥和证书的 PKCS#12 文件
spawn openssl pkcs12 -export -out server.pfx -inkey server.key -in server.crt -passout env:SSL_KEYSTORE_PASSWORD
expect eof
# 将PKCS#12 文件转化为 JKS、PFX格式,适用于java程序
spawn keytool -importkeystore -srckeystore server.pfx -srcstoretype pkcs12 -destkeystore server-cert.jks -deststoretype JKS -alias 1
expect "Enter destination keystore password:"
send "$env(SSL_KEYSTORE_PASSWORD)\n"
expect "Re-enter new password:"
send "$env(SSL_KEYSTORE_PASSWORD)\n"
expect "Enter source keystore password:"
send "$env(SSL_KEYSTORE_PASSWORD)\n"
expect eof