更换ssl证书报错

Just Do It
2023-07-20 / 0 评论 / 28 阅读 / 正在检测是否收录...

1.背景

又到了一年一度的ssl证书替换的时间了,
这次替换证书并没有和往常一样预期的那么丝滑,
这不刚替换了非生产环境的证书业务就开始反馈报错了,
自此期间也度娘和谷歌了一番,有说改java代码的、有说证书问题的、有说服务器问题的
各抒己见
下面贴下报错信息,
给有和我一样的童鞋做个借鉴

2. 报错信息

org.springframework.web.client.ResourceAccessException: I/O error on POST request for "https://labelservice-dev.wangmanyuan.com/rest/label/condition": sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target; nested exception is javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:674)
        at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:621)
        at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:415)
        at com.tal.file.business.client.LabelRestClient.condition(LabelRestClient.java:51)
        at com.tal.file.core.common.utils.CoursewareUtil.copyLabel(CoursewareUtil.java:2778)
        at com.tal.file.business.service.impl.CoursewareServiceImpl.packageOnCopy(CoursewareServiceImpl.java:1122)
        at com.tal.file.business.service.impl.CoursewareServiceImpl.copyCommon(CoursewareServiceImpl.java:329)
        at com.tal.file.business.service.impl.CoursewareServiceImpl.copyAsync(CoursewareServiceImpl.java:258)
        at com.tal.file.business.service.impl.CoursewareServiceImpl$$FastClassBySpringCGLIB$$b182efe0.invoke(<generated>)
        at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)

3.思考证书报错的原因

清晰可见他们的牌子和加密算法是一样的
可是切换过去就报错

3.1证书解析过程

3.2 HTTPS在传输的过程中会涉及到三个密钥:

服务器端的公钥和私钥,用来进行非对称加密
客户端生成的随机密钥,用来进行对称加密
一个HTTPS请求实际上包含了两次HTTP传输,可以细分为8步
  1. 客户端发起HTTPS请求
    用户在浏览器里输入一个https网址,然后连接到server的443端口。
  2. 服务端的配置
    采用HTTPS协议的服务器必须要有一套数字证书,可以自己制作,也可以向组织申请。区别就是自己颁发的证书需要客户端验证通过,才可以继续访问,而使用受信任的公司申请的证书则不会弹出提示页面。这套证书其实就是一对公钥和私钥。如果对公钥和私钥不太理解,可以想象成一把钥匙和一个锁头,只是全世界只有你一个人有这把钥匙,你可以把锁头给别人,别人可以用这个锁把重要的东西锁起来,然后发给你,因为只有你一个人有这把钥匙,所以只有你才能看到被这把锁锁起来的东西。
  3. 传送证书
    这个证书其实就是公钥,只是包含了很多信息,如证书的颁发机构,过期时间等等。
  4. 客户端解析证书
    这部分工作是有客户端的TLS来完成的,首先会验证公钥是否有效,比如颁发机构,过期时间等等,如果发现异常,则会弹出一个警告框,提示证书存在问题。如果证书没有问题,那么就生成一个随即值。然后用证书对该随机值进行加密。就像上面说的,把随机值用锁头锁起来,这样除非有钥匙,不然看不到被锁住的内容。

客户端收到服务器端的证书之后,会对证书进行检查,验证其合法性,如果发现发现证书有问题,那么HTTPS传输就无法继续。

严格的说,这里应该是验证服务器发送的数字证书的合法性。如果公钥合格,那么客户端会生成一个随机值,这个随机值就是用于进行对称加密的密钥,我们将该密钥称之为client key,即客户端密钥,这样在概念上和服务器端的密钥容易进行区分。

然后用服务器的公钥对客户端密钥进行非对称加密,
这样客户端密钥就变成密文了,
至此,HTTPS中的第一次HTTP请求结束。

  1. 传送加密信息
    这部分传送的是用证书加密后的随机值,
    目的就是让服务端得到这个随机值,
    以后客户端和服务端的通信就可以通过这个随机值来进行加密解密了。

客户端会发起HTTPS中的第二个HTTP请求,将加密之后的客户端密钥发送给服务器。

  1. 服务段解密信息
    服务端用私钥解密后,得到了客户端传过来的随机值(私钥),然后把内容通过该值进行对称加密。
    所谓对称加密就是,
    将信息和私钥通过某种算法混合在一起,这样除非知道私钥,不然无法获取内容,而正好客户端和服务端都知道这个私钥,所以只要加密算法够彪悍,私钥够复杂,数据就够安全。
  2. 传输加密后的信息
    这部分信息是服务段用私钥加密后的信息,可以在客户端被还原
  3. 客户端解密信息
    客户端用之前生成的私钥解密服务段传过来的信息,于是获取了解密后的内容。整个过程第三方即使监听到了数据,也束手无策。

这样HTTPS中的第二个HTTP请求结束,整个HTTPS传输完成。

SSL的位置

SSL介于应用层和TCP层之间。应用层数据不再直接传递给传输层,而是传递给SSL层,SSL层对从应用层收到的数据进行加密,并增加自己的SSL头。

3.3 根证书每15年更换

https://help.aliyun.com/document_detail/179033.htm?spm=0.2020520163.help.dexternal.3cb237119U1VUd

https://help.aliyun.com/document_detail/610069.html

3.4 思考当前运行环境

我们现在运行的服务环境go、nodejs、python、c、java
从报错日志来看目前出现问题的是java+jdk1.7的组合下发生的问题
那么就开始从这里下手

目前根据阿里提供的新的根证书进行导入到jdk1.7内,
原则上导入后恢复,从实际现象来看是需要重启服务的才能生效

3.5 具体操作流程

3.5.1 上传G2根证书

可根据阿里给的文件进行下载,要是不知道的童鞋可以加群和我要下

3.5.2 确认jdk1.7所在服务器目录

执行导入命令

echo yes|keytool -importcert -file  Digicert-OV-DV-root.cer -alias DigicertWangManYuan20240717 -keystore /usr/local/jdk1.7.0_79/jre/lib/security/cacerts -storepass changeit

3.5.2 导入后测试

在导入后发现有的服务重启后生效 有的却不生效 
具体排查方式有一个demo文件可以进行测试

3.5.3 demo文件

[root@wangmanyuan abc]# cat SSLPoke.java 
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import java.io.*;

public class SSLPoke {
    public static void main(String[] args) {
		if (args.length != 2) {
			System.out.println("Usage: "+SSLPoke.class.getName()+" <host> <port>");
			System.exit(1);
		}
		try {
			SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
			SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket(args[0], Integer.parseInt(args[1]));

			InputStream in = sslsocket.getInputStream();
			OutputStream out = sslsocket.getOutputStream();

			out.write(1);

			while (in.available() > 0) {
				System.out.print(in.read());
			}
			System.out.println("Successfully connected");

		} catch (Exception exception) {
			exception.printStackTrace();
		}
	}
}

3.5.4 编译一下 执行

编译
javac SSLPoke.java
编译后生成SSLPoke.class文件
执行命令测试
/usr/local/jdk1.7.0_79/bin/java -Djavax.net.debug=all  SSLPoke confi.wangmanyuan.com 443
如下图展示
发现读取的并不是常规的cacerts这个文件而是jssecacerts文件
重新指定文件执行命令后解决
echo yes|keytool -importcert -file  Digicert-OV-DV-root.cer -alias DigicertWangManYuan20240717 -keystore /usr/local/jdk1.7.0_79/jre/lib/security/jssecacerts -storepass changeit

3.5.5 查看导入G2根证书是否成功

keytool  -list  -keystore  /usr/local/jdk1.7.0_79/jre/lib/security/jssecacerts  -storepass changeit|grep -i wangmanyuan

3.5.6开启搬砖模式

由于非生产和生产环境数量非常多 
那么接下来我就是去做这件事了
毕竟生产环境得重启 真是一个高危操作

好了,就写这么多吧,有遇到和我类似问题的童鞋可以进群交流~~~
1

评论 (0)

取消