HttpClient的SSL证书的相关问题及解决方案

问题描述

访问某网站时服务器报出Algorithm constraints check failed on signature algorithm: MD2withRSA

这是因为在进行SSL握手时,服务器所采用的ssl证书算法不符合某种约束条件而抛出异常!

 

问题分析:

1. 查询网站证书信息

openssl s_client -showcerts -connect hostname:443

VeriSign(威瑞信)公司根证书的签名算法是md2WithRSAEncryption!

 

 2. 为什么使用md2WithRSAEncryption会出异常?

由于MD2被广泛认为是不安全的,JDK6u17版本开始,MD2算法被禁用。打开$JAVA_HOME/jre/lib/security/java.security文件可以看到

可以肯定,必定是代码中对算法做了校验引起的。

 

3. JDK代码实现原理

代码中我们在初始化SSLContext的时候调用了loadTrustMaterial方法

进入loadTrustMaterial方法,此时tm是X509ExtendedTrustManager的子类,进入SSLContextBuilder类

trustManager被强转成父类X509TrustManager,最终被封装成了TrustManagerDelegate,TrustManagerDelegate实现了X509TrustManager接口。

 继续跟踪到sun.security.ssl.SSLContextImpl

其中var1[var2]即TrustManagerDelegat对象,跳过判断,TrustManagerDelegate又被AbstractTrustManagerWrapper封装返回。

AbstractTrustManagerWrapper继承了X509ExtendedTrustManager实现了X509TrustManager接口

AbstractTrustManagerWrapper会对服务器的证书算法进行验证,检查它们是否符合java.security里的配置要求。

 

4. JDK修复方案 

JDK1.7之后修改了SSLContext的实现,解决了上述的问题 

定位sun.security.ssl.SSLContextImpl,默认var2为null,由var4.getTrustMangers初始化

var2是一个TrustManager对象的数组,内部元素是X509TrustManagerImpl实例。

X509TrustManagerImpl继承了X509ExtendedTrustManager

进入chooseTrustManager方法,最终返回X509TrustManagerImpl实例对象

X509TrustManagerImpl类没有对服务端做证书算法校验的方法,因此如果用法不对,还是会导致Certificates does not conform to algorithm constraints复现。

 

解决方案 

方案一:

修改文件$JAVA_HOME/jre/lib/security/java.security,找到如下配置:

修改配置(或者直接注释)
jdk.certpath.disabledAlgorithms=
jdk.tls.disabledAlgorithms=

缺点:

1. 系统安全级别降低,JDK8提高了对SSL证书的算法安全要求
2. 线上所有服务器的JDK配置需要修改,如果增加新服务器也需要配置,维护麻烦

 

方案二:

自定义实现X509ExtendedTrustManager,JDK会使用TrustAnyTrustManager来验证证书算法,而这个类所有的验证方法都是空方法,也就是不验证。

缺点:

对服务端的证书无条件的信任是不安全的。

 

方案三:

我们选择JDK默认的实现方式

 

访问其他网站又出现PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

这个错误的原因是因为服务端的证书机构不被客户端信任。值得信任的CA机构可以有效避免中间人攻击。


1. 通过openssl s_client -showcerts -connect hostname:443查询到CA机构是Symantec(赛门铁克)

2. 查询JDK默认信任的机构,测试类启动的时候加上命令-Djavax.net.debug=ssl,handshake具体文件见$JAVA_HOME/jre/lib/security/cacerts

经查询之后发现Symantec不是JDK信任的机构。将Symantec添加到JDK的cacerts中即可解决问题。 

猜你喜欢

转载自blog.csdn.net/ghaohao/article/details/79454913
今日推荐