解决HttpClient访问https(包括通过http代理)出现unable to find valid certification path to requested target的问题

1. 知识预备

要理解本文,需要掌握以下知识:

  • https基本原理,包括证书分发和密钥协商等 [1];
  • http代理和https代理的基本原理 [2];
  • 常用的本地http代理工具,如Fiddler, BurpSuite;
  • 懂Java语言,了解HttpClient的基本功能和API [3]。

2. 问题描述与分析

使用httpclient写程序访问https页面,中间需要通过本地的http/https代理,如下所示:
Java程序(基于httpclient) <——-> 代理工具 (如Fiddler) <———> Web服务器
当运行Java程序后,程序出现异常,提示:

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

从错误提示可以看到是无法验证网站的证书,找不到证书验证链。为了解决问题,将代理工具生成的证书作为可信根证书导入系统证书库,但是问题依然存在。在阅读了资料[1]之后才恍然大悟,原来Java的证书验证系统是独立于操作系统和浏览器的,而是使用JRE中证书库,所有必须把代理工具的证书加入到JRE的证书库中。

3. 问题解决

在Windows系统中,JRE证书库路劲为Program Files\Java\jdk1.x.x\jre\lib\security\cacerts。Java使用Keytool管理证书,其路径为Program Files\Java\jdk1.8.0_144\bin\keytool.exe。所以,需要的操作是使用keytool将代理工具的证书加入到cacerts中。在[2]对上述过程有详细的原理解释。打开命令行,进行如下操作:
Step 1. cd到keytool.exe所在目录;
Step 2. 执行下述命令(命令参数说明参考keytool帮助文件)

>keytool -import -alias FIDDLER -keystore ../lib/security/cacerts -file 代理工具证书路径\证书文件名

如果提示输入口令,java默认口令是changeit,最后输入y信任此证书。
Step 3. 确认证书已经被导入可信根证书库

keytool -list -keystore ../lib/security/cacerts

参考资料

[1] Java 和 HTTP 的那些事(四) HTTPS 和 证书
[2] https代理原理
[3] HttpClient 4.5

猜你喜欢

转载自blog.csdn.net/write_down/article/details/79114573