httpclient 忽略证书_对接外部接口,又一次证书问题!
Java技术栈
www.javastack.cn
关注优质文章
作者:funnyZpC
出处:cnblogs.com/funnyzpc/p/10989813.html
最近接一外部接口,接口在本地开发调试及测试都无任何问题(windows下),而上测试环境后测第一次就直接报错误,
错误是这样子的:
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 sun.security.ssl.Alerts.getSSLException(Alerts.java:192) at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1917) at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:301) at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:295) at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1369) at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:156) at sun.security.ssl.Handshaker.processLoop(Handshaker.java:925) at sun.security.ssl.Handshaker.process_record(Handshaker.java:860) at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1043) at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1343) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1371) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1355)
enn~,首先那个接口地址是https的,服务器是linux的。
以上错误其大意是无法找到及验证有效证书,再想想:不对啊,本地jdk和服务器的jdk都是oracle官方jdk 1.8呀,照理说本地调试没问题在服务端应该也不会有什么问题呢~
诶~,不管怎么分析都还是要解决问题呀,首先我分析到这又两个问题点:
本地和服务器OS不一致
接口地址的SSL证书存在不兼容或其他问题
怎么办?要求对方检查证书配置,可能性不大,剩下的就只剩下一种方式:做兼容,就是在请求的时候信任对方的证书。
于是有了第一版。
因为我使用的是CloseableHttpClient,做的请求管理,不如在让CloseableHttpClient兼容https与http不就好了,寻思一项,搜索一番代码即成(这里只给出核心代码)
// 之前// private static CloseableHttpClient httpClient = HttpClients.custom().build();
// 之后private static CloseableHttpClient httpClient;static { try { System.out.println("===>01"); // 忽略证书 SSLContextBuilder SslBuilder = new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy()); //不进行主机名验证 SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(SslBuilder.build(), NoopHostnameVerifier.INSTANCE); Registry registry = RegistryBuilder.create() .register("http", new PlainConnectionSocketFactory()) .register("https", sslConnectionSocketFactory) .build(); PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry); cm.setMaxTotal(100); httpClient = HttpClients.custom() .setSSLSocketFactory(sslConnectionSocketFactory) .setDefaultCookieStore(new BasicCookieStore()) .setConnectionManager(cm).build(); } catch (Exception e) { e.printStackTrace(); System.out.println("===>02"); httpClient = HttpClients.custom().build(); } }}
bingo ~,上线测 。。。
oh~,no,依然是这个错:
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 sun.security.ssl.Alerts.getSSLException(Alerts.java:192) ......
待我分析一番,发现上面的代码仅仅只是为了不验证对方主机,完全没有理会证书的错误。。。
欸~,这是个问题。
后我又想起之前上上家公司也有出现过这个问题,哈~,有办法了,找到源码把主要的几句copy过来走走不就好了。
于是,第二版
核心代码:
HostnameVerifier hv = new HostnameVerifier() {
public boolean verify(String urlHostName, SSLSession session) { return true; }
};
private static void trustAllHttpsCertificates() throws Exception { javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1]; javax.net.ssl.TrustManager tm = new miTM(); trustAllCerts[0] = tm; javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext .getInstance("SSL"); sc.init(null, trustAllCerts, null); javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc .getSocketFactory());}
static class miTM implements javax.net.ssl.TrustManager,javax.net.ssl.X509TrustManager { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null;}
public boolean isServerTrusted( java.security.cert.X509Certificate[] certs) { return true;}
public boolean isClientTrusted( java.security.cert.X509Certificate[] certs) { return true;}
public void checkServerTrusted( java.security.cert.X509Certificate[] certs, String authType) throws java.security.cert.CertificateException { return;}
public void checkClientTrusted( java.security.cert.X509Certificate[] certs, String authType) throws java.security.cert.CertificateException { return; }}
// 在访问前调用trustAllHttpsCertificates();HttpsURLConnection.setDefaultHostnameVerifier(hv);
一整折腾后上线部署测试,啊~,还是同样的错误。。。
分析代码,看到,这种处理逻辑只针对自定义SSL证书有效,对于我现有的情况丁点问题都解决不了。
终版
其实业务代码的什么都没改,只是给jdk添加了点儿东西。
主要解决思路是让jdk忽略指定域名的SSL证书。《图解 https 单向认证和双向认证!》推荐看下。
//InstallCert.java
import java.io.*;import java.net.URL;
import java.security.*;import java.security.cert.*;
import javax.net.ssl.*;
public class InstallCert {
public static void main(String[] args) throws Exception { String host; int port; char[] passphrase; if ((args.length == 1) || (args.length == 2)) { String[] c = args[0].split(":"); host = c[0]; port = (c.length == 1) ? 443 : Integer.parseInt(c[1]); String p = (args.length == 1) ? "changeit" : args[1]; passphrase = p.toCharArray(); } else { System.out.println("Usage: java InstallCert [:port] [passphrase]"); return; }
File file = new File("jssecacerts"); if (file.isFile() == false) { char SEP = File.separatorChar; File dir = new File(System.getProperty("java.home") + SEP + "lib" + SEP + "security"); file = new File(dir, "jssecacerts"); if (file.isFile() == false) { file = new File(dir, "cacerts"); } } System.out.println("Loading KeyStore " + file + "..."); InputStream in = new FileInputStream(file); KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); ks.load(in, passphrase); in.close();
SSLContext context = SSLContext.getInstance("TLS"); TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(ks); X509TrustManager defaultTrustManager = (X509TrustManager)tmf.getTrustManagers()[0]; SavingTrustManager tm = new SavingTrustManager(defaultTrustManager); context.init(null, new TrustManager[] {tm}, null); SSLSocketFactory factory = context.getSocketFactory();
System.out.println("Opening connection to " + host + ":" + port + "..."); SSLSocket socket = (SSLSocket)factory.createSocket(host, port); socket.setSoTimeout(10000); try { System.out.println("Starting SSL handshake..."); socket.startHandshake(); socket.close(); System.out.println(); System.out.println("No errors, certificate is already trusted"); } catch (SSLException e) { System.out.println(); e.printStackTrace(System.out); }
X509Certificate[] chain = tm.chain; if (chain == null) { System.out.println("Could not obtain server certificate chain"); return; }
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
System.out.println(); System.out.println("Server sent " + chain.length + " certificate(s):"); System.out.println(); MessageDigest sha1 = MessageDigest.getInstance("SHA1"); MessageDigest md5 = MessageDigest.getInstance("MD5"); for (int i = 0; i X509Certificate cert = chain[i]; System.out.println (" " + (i + 1) + " Subject " + cert.getSubjectDN()); System.out.println(" Issuer " + cert.getIssuerDN()); sha1.update(cert.getEncoded()); System.out.println(" sha1 " + toHexString(sha1.digest())); md5.update(cert.getEncoded()); System.out.println(" md5 " + toHexString(md5.digest())); System.out.println(); }
System.out.println("Enter certificate to add to trusted keystore or 'q' to quit: [1]"); String line = reader.readLine().trim(); int k; try { k = (line.length() == 0) ? 0 : Integer.parseInt(line) - 1; } catch (NumberFormatException e) { System.out.println("KeyStore not changed"); return; }
X509Certificate cert = chain[k]; String alias = host + "-" + (k + 1); ks.setCertificateEntry(alias, cert);
OutputStream out = new FileOutputStream("jssecacerts"); ks.store(out, passphrase); out.close();
System.out.println(); System.out.println(cert); System.out.println(); System.out.println ("Added certificate to keystore 'jssecacerts' using alias '" + alias + "'"); }
private static final char[] HEXDIGITS = "0123456789abcdef".toCharArray();
private static String toHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(bytes.length * 3); for (int b : bytes) { b &= 0xff; sb.append(HEXDIGITS[b >> 4]); sb.append(HEXDIGITS[b & 15]); sb.append(' '); } return sb.toString(); }
private static class SavingTrustManager implements X509TrustManager {
private final X509TrustManager tm; private X509Certificate[] chain;
SavingTrustManager(X509TrustManager tm) { this.tm = tm; }
public X509Certificate[] getAcceptedIssuers() { throw new UnsupportedOperationException(); }
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { throw new UnsupportedOperationException(); }
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { this.chain = chain; tm.checkServerTrusted(chain, authType); } }}
具体解决步骤:
编译文件
javac InstallCert.java
添加信任
java InstallCert 域名地址
上传证书(需手动将网站证书导出)
rz => 证书.cer
导入证书(密码:changeit)
echo $JAVA_HOME
keytool -import -alias LL1 -keystore $JAVA_HOME/jre/lib/security/cacerts -file /home/证书.cer
关注Java技术栈看更多干货
戳原文,获取精选面试题!
httpclient 忽略证书_对接外部接口,又一次证书问题!相关推荐
- eap wifi 证书_用openssl为EAP-TLS生成证书(CA证书,服务器证书,用户证书)
我用的是openssl-1.0.2k. 脚本支持生成RSA,ECC证书. 运行时带参数指定类型. -->开始.按以下路径建立文件,脚本.ssl_create-cert-v0.4.7z ssl_c ...
- phpstudy安装ssl证书_给网站安装免费SSL证书
突然有一天老板让我给用Flask写的小网站安装SSL证书,虽然之前没弄过但是感觉应该不难. 主要分为以下几个步骤: 购买域名 购买SSL证书 DNS(域名解析) 部署SSL证书 1. 购买域名 因为我 ...
- python sanic 设置ssl证书_配置自签https ssl证书
由于人们越来越重视网络安全,所以很多平台及系统都要求使用https方式接入.而且一些开源服务框架在调用时也只接受https请求,这将导致平时开发/测试时需要用到ssl证书的地方越来越多. 在2016年 ...
- 苹果企业证书_今日更新:丨企业证书已更新丨苹果丨安卓软件下载说明丨
今日更新 苹果软件下载说明 企业证书☆已更新 苹果☆安卓软件☆规整说明 为了方便大家下载的时候不那么麻烦,我把所以的软件都归类到了一起,大家只要 回复关键词→111即可获得苹果软件列表 回复关键词→2 ...
- acme云服务器生成证书_使用 acme.sh 申请 SSL 证书并且定期自动更新
在我们的实际项目生产过程中往往需要为部署的服务和域名配置 SSL 证书,可以采用的方法有很多种,例如可以申请阿里云的免费 SSL 证书,或者也可以使用 CloudFlare 的 SSL 服务.本文介绍 ...
- cloudflare免费证书_免费获取cloudflare的ssl证书
点击ssl 证书 选中 中间那个 保存文件 xxx.pem 一个 为xxx.key server { listen 80; #listen [::]:80; server_name xxx.ne ...
- aws 证书_从AWS Certificate Manager获得证书
aws 证书 最近, AWS在欧洲地区提供了" 证书管理器 "服务. 使用此服务,您将能够对托管在AWS上的应用程序使用SSL证书 (免费). 与我在此描述的解决方案相比,最大的优 ...
- jodd忽略ssl证书_关于java访问https资源时,忽略证书信任问题
java程序在访问https资源时,出现报错 sun.security.validator.ValidatorException: PKIX path building failed: sun.sec ...
- HttpClient 忽略证书直接访问https站点
使用HttpClient访问https 站点时,如果Java没有导入该站点的证书的话,则会报如下错误: javax.net.ssl.SSLHandshakeException: sun.securit ...
最新文章
- 鸿蒙系统支持最低处理器,这四款华为手机可升级到鸿蒙系统,老机型居多,最低只需千元!...
- Pytorch —— GPU的使用
- iPhone 13 Pro系列被抢疯:官网已推迟36天发货
- matlab调和均值滤波_MATLAB--数字图像处理 均值滤波
- openai-gpt_为什么GPT-3感觉像是编程
- mysql扩容方案_MySQL分库分表:扩容方案
- c语言编译运行的几步
- python中步长什么意思,python步长是什么
- 用计算机中的知识秀恩爱,教你用专业知识取情侣网名
- Nicholas C. Zakas:最佳职业生涯建议
- 苹果App store 2015最新审核标准
- curse库的使用总结
- ad17如何生成坐标文件_pcb如何导出坐标文件
- 工作了,总少不了饭局的,抄来学习学习
- tinymce php,php - 用TinyMCE制作的PHP样式表(Hor Zebra) - SO中文参考 - www.soinside.com
- Revi开发 - 碰撞检测
- windows开源工具大全
- 常见外挂分类及原理概述
- AI时代大点兵——国内外知名AI公司2018年最新盘点【完整版】
- C++面向对象程序设计 024:这是什么鬼delete ---- (北大Mooc)