openssl 获取服务端证书并导入到本地 jdk 证书库 + 忽略证书检测,解决 'unable to find valid certification path to requested target'

从一滴水开始 的个人博客 纵有疾风起,人生不言弃 本文由博客端 http://www.lizhenhua.fun 主动推送

在调用服务端接口时出现如下异常 unable to find valid certification path to request target,从异常信息中可以看到错误是因为找不到证书导致的。解决方案有两个:

第一种方案呢,要先获取服务端证书,然后安装到本地 JDK 的证书库。我们使用 openssl 来获取证书信息,这里我写成了一个 shell 脚本,方便使用。

get_certs_by_domain_port.sh

#!bin/bash
#服务端地址
host=$1
#端口
port=$2

#证书名称
certName=$3

#获取证书
echo "Q"|openssl s_client -connect ${host}:${port} -servername ${host} -showcerts | openssl x509 -outform pem > ${certName}.crt

如果需要循环获取多个证书可以用下面的脚本

#设置域名列表
hosts=(www.baidu.com www.csdn.net www.cnblogs.com)
#设置端口,HTTPS默认端口为443
port=443
#循环获取证书
for host in ${hosts[@]};do
  echo "Q"|openssl s_client -connect ${host}:${port} -servername ${host} -showcerts|openssl x509 -outform pem > ${host}.crt
done

执行 sh get_certs_by_domain_port.sh www.baidu.com 443 baidu 即可在当前目录下生成名称为 baidu.crt 的证书。
image.png

使用下面的脚本,将获取到的证书导入到 JDK 证书库。

import_jdk_certs.sh

#!/bin/bash
#将证书导入到jdk证书库
#证书别名
alias=$1
#证书文件名
fileName=$2

keytool -import -v -trustcacerts -alias ${alias} -file ${fileName} -storepass changeit -keystore ${JAVA_HOME}/jre/lib/security/cacerts

执行 sh import_jdk_certs.sh baidu baidu.crt 即可将证书导入到 JDK 证书库(需要使用 root 用户,否则会没有权限)。
image.png

image.png

使用下面的脚本可以查看已经添加到 JDK 证书库里的证书信息,如果输出为空则代表没有找到证书。

cat_jdk_certs.sh

#!/bin/bash
certName=$1
keytool -list -keystore "${JAVA_HOME}/jre/lib/security/cacerts" -storepass changeit |grep ${certName}

执行 sh cat_jdk_certs.sh baidu 查看。
image.png

第二种方案:取消证书认证,信任所有请求链接。

/**
	 * 获取 HttpClient
	 * 
	 * @param host
	 * @param path
	 * @return
	 * @author 李振华
	 */
	private static CloseableHttpClient wrapClient(String host, String path) {
		CloseableHttpClient httpClient = HttpClientBuilder.create().build();
		if (host != null && host.startsWith("https://")) {
			return sslClient();
		} else if (StringUtil.isBlank(host) && path != null && path.startsWith("https://")) {
			return sslClient();
		}
		return httpClient;
	}

	/**
	 * 在调用SSL之前需要重写验证方法,取消检测SSL 创建ConnectionManager,添加Connection配置信息
	 * 
	 * @return HttpClient 支持https
	 * @author 李振华
	 */
	private static CloseableHttpClient sslClient() {
		try {
			// 在调用SSL之前需要重写验证方法,取消检测SSL
			AppLogger.debug("在调用SSL之前需要重写验证方法,取消检测SSL");
			X509TrustManager trustManager = new X509TrustManager() {

				@Override
				public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
				}

				@Override
				public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
				}

				@Override
				public X509Certificate[] getAcceptedIssuers() {
					return new X509Certificate[0];
				}

			};
			SSLContext ctx = SSLContext.getInstance(SSLConnectionSocketFactory.TLS);
			ctx.init(null, new TrustManager[] { trustManager }, null);
			SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(ctx,
					NoopHostnameVerifier.INSTANCE);
			// 创建Registry
			RequestConfig requestConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD_STRICT)
					.setExpectContinueEnabled(Boolean.TRUE)
					.setTargetPreferredAuthSchemes(Arrays.asList(AuthSchemes.NTLM, AuthSchemes.DIGEST))
					.setProxyPreferredAuthSchemes(Arrays.asList(AuthSchemes.BASIC)).build();
			Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
					.register("http", PlainConnectionSocketFactory.INSTANCE).register("https", socketFactory).build();
			// 创建ConnectionManager,添加Connection配置信息

			PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(
					socketFactoryRegistry);
			CloseableHttpClient closeableHttpClient = HttpClients.custom().setConnectionManager(connectionManager)
					.setDefaultRequestConfig(requestConfig).build();
			return closeableHttpClient;
		} catch (KeyManagementException ex) {
			throw new RuntimeException(ex);
		} catch (NoSuchAlgorithmException ex) {
			throw new RuntimeException(ex);
		}
	}
  • Linux

    Linux 是一套免费使用和自由传播的类 Unix 操作系统,是一个基于 POSIX 和 Unix 的多用户、多任务、支持多线程和多 CPU 的操作系统。它能运行主要的 Unix 工具软件、应用程序和网络协议,并支持 32 位和 64 位硬件。Linux 继承了 Unix 以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统。

    795 引用 • 889 回帖 • 494 关注
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    2812 引用 • 8043 回帖 • 749 关注

赞助商 我要投放

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...