解决Java Https请求PKIX path building failed报错问题

PKIX path building failed 通俗讲解。

通俗的讲,PKIX path building failed 出现的原因是因为自己的Java环境没有相关网站的证书而导致的。

PKIX path building failed 具体内容。

PKIX的全称为Public-Key Infrastructure (X.509),通过wiki百科我们可以知道X.509是一种证书的标准,这种标准用在很多网络协议,比如TLS/SSL。而TLS/SSL是HTTPS协议的标准(HTTPS比HTTP多的部分就在于TLS/SSL),所以本文章我们掌握TLS/SSL的知识。

TLS/SSL协议详解

接下是TLS和SSL的的关系以及其详解

TLS和SSL的关系

  • SSL 又称Secure Sockets Layers,而TLS又称Transport Layer Security。
  • TLS位于传输层上,而SSL位于传输层和应用层之间。
  • SSL 总共有3版 分别是 1995年的SSL v1.0, 1995年的SSL v2.0, 1996年的SSL v3.0。
  • TLS 目前有四版分别是 1999年的TLS v1.0, 2006年的TLS v1.1, 2008年的TLS v1.2, 2018年的TLS v1.3。
  • SSL 是 TLS 的前身,并且目前已经不推荐使用, TLS v1.0 修正了SSL v3.0中的安全缺陷,但是由于TLS v1.0是可以降级到SSL v3.0所以依旧存在不安全的情况(当你访问使用较低版本的TLS协议或者任意版本的SSL协议时,你的浏览器会提示你,这个时候如果想规避风险,建议就不要继续了。)

TSL 握手机制。

  • TSL handshake
  1. Client 发送 clientHello 到Sever,内容包括
    • 支持的TSL最高版本号
    • cipher suite(一堆支持的加密算法)
    • 客户端随机数
  2. Server 返回ServerHello 到Client,内容包括
    • Server决定的TSL版本号
    • 服务器随机数
    • 选择的cipher suite
  3. Server发送他的certificate message(这里包含了server的public-key)到Client,这里使用证书可以保证public-key是正确的,因为certificate受到可信部门认证。
  4. Server发送ServerHelloDone信息到Client,告诉Client他的handshake已结束
  5. Client 发送ClientKeyExchange message 到 Server。包含:
    • PremasterSecret(这个里面包含的是sharekey,用server的public加密)。
      除此之外,Client使用服务端随机数,客户端随机数,PremasterSecret形成share key
  6. Server使用自己的private key 解密 ClientKeyExchange message,并使用服务端随机数,客户端随机数,PremasterSecret形成share key。
  7. client 发送ChangeCipherSpec到Server,目的是告诉Server可以开始使用以上协商的share key了。包含
    • Finished massage:这个是之前握手信息的hash或者MAC(message authentication code (MAC) algorithm)算法的值
  8. Server 收到ChangeCipherSpec,后计算自己本地的内容,检查收到的hash/mac是否和自己的一致,不一致,这次握手将失败,一致发送ChangeCipherSpec到client,目的是告诉Client开始使用协商的share key。

cipher suite 详解

 

cipher suite 是为了保证连接过程的安全性,其中包括很4种算法原语的组合。客户端和服务器handshake时,由服务器确定使用的算法,之后由服务器和客户端一起使用这样的算法。

  • 四种算法原语(对于一个cipher suite,只能有一个Kx,一个Au一个Enc,一个MAC,但是这些算法可以选择不同的)
    • Key Exchange(Kx),常见DH 和 ECDH,(类似TLS握手机制)
    • Authentication (Au),常见DSA/RSA/ECDSA(证书,比如server发送回来的public key 就是放在sever的证书里的,client可以检查这个证书是否有效)
    • Encryption(Enc),主要AES(加密算法,和密码学有关,我们此处不谈)
    • Message Authentication Code(MAC),常见SHA1、SAH256、SHA384(对于message,对整体求hash/md等作为单独的tag,即作为客户端检查message完整性和未被篡改的凭证)

解决方法(程序内部自动过滤ssl,推荐)

然而有的时候,比如小程序去获取user的openid和session-key时,需要访问https://api.weixin.qq.com/sns/jscode2session,此时因为微信官方的api限制了必须使用https,所以去掉s则会报错。此时我们采用在本地网络连接时忽略SSL。
我认为,在开发软件时,很多主机如果没有ssl认证,执行需要的网络连接就会失败,所以需要过滤ssl。
可以使用如下的工具类

package com.auth.verification;
 
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
 
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
public class HttpsUtils {
	private static Logger logger = LoggerFactory.getLogger(HttpsUtils.class);
	static CloseableHttpClient httpClient;
	static CloseableHttpResponse httpResponse;
 
	public static CloseableHttpClient createSSLClientDefault() {
		try {
			SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
				// 信任所有
				public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
					return true;
				}
			}).build();
			HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
			SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
			return HttpClients.custom().setSSLSocketFactory(sslsf).build();
		} catch (KeyManagementException e) {
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (KeyStoreException e) {
			e.printStackTrace();
		}
		return HttpClients.createDefault();
 
	}
 
	/**
	 * 发送https请求
	 * 
	 * @param jsonPara
	 * @throws Exception
	 */
	public static String sendByHttp(Map<String, Object> params, String url) {
		try {
			HttpPost httpPost = new HttpPost(url);
			List<NameValuePair> listNVP = new ArrayList<NameValuePair>();
			if (params != null) {
				for (String key : params.keySet()) {
					listNVP.add(new BasicNameValuePair(key, params.get(key).toString()));
				}
			}
			UrlEncodedFormEntity entity = new UrlEncodedFormEntity(listNVP, "UTF-8");
			logger.info("创建请求httpPost-URL={},params={}", url, listNVP);
			httpPost.setEntity(entity);
			httpClient = HttpsUtils.createSSLClientDefault();
			httpResponse = httpClient.execute(httpPost);
			HttpEntity httpEntity = httpResponse.getEntity();
			if (httpEntity != null) {
				String jsObject = EntityUtils.toString(httpEntity, "UTF-8");
				return jsObject;
			} else {
				return null;
			}
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		} finally {
			try {
				httpResponse.close();
				httpClient.close();
				logger.info("请求流关闭完成");
			} catch (IOException e) {
				logger.info("请求流关闭出错");
				e.printStackTrace();
			}
		}
	}
 
	public static void main(String[] args) throws Exception {
		Map<String, Object> map = new HashMap<>();
		map.put("authCode", "FX:123");
		map.put("userName", "jianghaida");
		map.put("pwd", "jianghaida");
		
 
		System.out.println(HttpsUtils.sendByHttp(map, "https://localhost:8010/postDoc"));;
	}
}

 

 

 

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值