springboot应用https改造随笔

 

前提

为了迎合等保要求,本人秉承着安全(偷懒)的意识,决定在接手开发的短信服务上集成https。这里以springboot项目为例,通篇以流水账的形式,主要讲述如何生成证书、项目中如何集成以及对外接口如何调用等等。

<!-- more -->

获取证书

进入JAVA_HOME/bin目录下面,cmd执行如下命令

keytool -genkey -alias zkcsdn -keypass zsrj@2022 -keyalg RSA -keysize 2048 -validity 3650 -keystore zkcsdn.p12 -storepass zsrj@2022 -deststoretype pkcs12
​
-alias 别名
​
-keyalg 算法类型
​
-keysize 密码长度
​
-keypass 私钥访问密码
​
-validity 证书有效期
​
-keystore 证书名称
​
-storepass keystone文件访问密码
​

回车后,按提示输入下发信息,即可在执行目录下面生成p12证书文件

result

项目集成

springboot项目集成证书很简单,p12证书放置在项目resource目录下,然后仅需在application.yml中配置以下参数即可

server:
  ssl:
    # 证书路径
    key-store: classpath:zkcsdn.p12
    # 证书密码
    key-store-password: zsrj@2022
    # 证书类型
    key-store-type: PKCS12
    # 证书别名
    key-alias: zkcsdn

对外接口调用

由于我们做了https升级改造,且是自签名的证书,所以浏览器访问时会显示不受信任。这时候用后台调用接口会报错

result

所以我们客户端在接口调用时也需要集成证书, 这里以主流的OkHttpClient为例,SSL证书配置示例

    @Bean
    public OkHttpClient okHttpClient(@Autowired SmsProperty smsProperty) {
        // 创建连接池,设置最大空闲连接数和连接保持时间
        ConnectionPool connectionPool = new ConnectionPool(smsProperty.getMaxIdleConnections()
                , smsProperty.getKeepAliveDuration(), TimeUnit.MINUTES);
        // 创建OkHttpClient并设置连接池
        OkHttpClient.Builder builder = new OkHttpClient.Builder()
                .connectionPool(connectionPool);
        if (smsProperty.isSslEnable()) {
            TrustManagerFactory factory = createTrustManagerFactory();
            SSLSocketFactory sslSocketFactory = createSSLSocketFactory(factory);
            // 将 SSL socket 工厂和 X509TrustManager 添加到 OkHttpClient 的构建器中
            builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) factory.getTrustManagers()[0])
                    .hostnameVerifier((hostname, session) -> smsProperty.getUrl().contains(hostname));
        }
        return builder.build();
    }
​
    private static TrustManagerFactory createTrustManagerFactory() {
        // 从类路径中加载 P12 证书
        KeyStore keyStore = loadP12CertificateFromResource();
        // 创建一个信任管理器,用于信任 KeyStore 中的证书
        TrustManagerFactory trustManagerFactory;
        try {
            trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);
        } catch (NoSuchAlgorithmException | KeyStoreException e) {
            throw new RuntimeException(e);
        }
        return trustManagerFactory;
    }
​
    private static SSLSocketFactory createSSLSocketFactory(TrustManagerFactory factory) {
        // 创建一个 SSL 上下文,使用信任管理器
        SSLContext sslContext;
        try {
            sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, factory.getTrustManagers(), null);
        } catch (NoSuchAlgorithmException | KeyManagementException e) {
            throw new RuntimeException(e);
        }
        return sslContext.getSocketFactory();
    }
​
    private static KeyStore loadP12CertificateFromResource() {
        try (InputStream certInputStream = new FileInputStream("证书路径")) {
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            keyStore.load(certInputStream, "证书密码");
            return keyStore;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

其他问题(FAQ)

SSL秘钥认证异常

JDK 8u301以前的版本中,默认情况下不支持PKCS12格式的密钥库,需要在代码中显式地注册PKCS12密钥库,否则会报错:parseAlgParameters failed: Objectidentifier() -- data isn't an object ID (tag = 48)

所以一般我们推荐jdk升级至JDK 8u301及以上版本

其他客户端集成

我们都知道p12证书仅限于java应用的集成开发,jdk通过java.security.KeyStore类加载和管理P12证书。如果我们对接的第三方应用是其他编程语言开发的,或者我们需要通过nginx做反向代理时需要我们如何操作呢?

我们以GO语言为例,golang支持pem证书认证,而不支持我们生成的p12,所以需要我们将p12证书转换为pem证书

openssl pkcs12 -in zkcsdn.p12 -out zkcsdn.crt -nokeys 
openssl pkcs12 -in zkcsdn.p12 -out zkcsdn.key -nocerts -nodes

在上述命令中,我们使用openssl命令提取客户端证书和私钥。第一行提取证书并将其保存为zkcsdn.crt文件。第二行提取私钥并将其保存为zkcsdn.key文件。使用-nokeys选项不要包括私钥,而使用“-nocerts -nodes”选项来指示openssl不要包括证书链,并且不要加密私钥。

golang http客户端集成示例

func main() {
    // 加载证书配置
    cert, err := tls.LoadX509KeyPair("zkcsdn.crt", "zkcsdn.key")
    if err != nil {
        fmt.Println("Error loading client cert: ", err)
        return
    }
​
    // 创建TLS相关配置
    tlsConfig := &tls.Config{
        Certificates:       []tls.Certificate{cert},
        InsecureSkipVerify: true,
    }
​
    // 创建http客户端
    transport := &http.Transport{TLSClientConfig: tlsConfig}
    httpClient := &http.Client{Transport: transport}
​
    // 发送HTTPS请求
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值