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 忽略证书_对接外部接口,又一次证书问题!相关推荐

  1. eap wifi 证书_用openssl为EAP-TLS生成证书(CA证书,服务器证书,用户证书)

    我用的是openssl-1.0.2k. 脚本支持生成RSA,ECC证书. 运行时带参数指定类型. -->开始.按以下路径建立文件,脚本.ssl_create-cert-v0.4.7z ssl_c ...

  2. phpstudy安装ssl证书_给网站安装免费SSL证书

    突然有一天老板让我给用Flask写的小网站安装SSL证书,虽然之前没弄过但是感觉应该不难. 主要分为以下几个步骤: 购买域名 购买SSL证书 DNS(域名解析) 部署SSL证书 1. 购买域名 因为我 ...

  3. python sanic 设置ssl证书_配置自签https ssl证书

    由于人们越来越重视网络安全,所以很多平台及系统都要求使用https方式接入.而且一些开源服务框架在调用时也只接受https请求,这将导致平时开发/测试时需要用到ssl证书的地方越来越多. 在2016年 ...

  4. 苹果企业证书_今日更新:丨企业证书已更新丨苹果丨安卓软件下载说明丨

    今日更新 苹果软件下载说明 企业证书☆已更新 苹果☆安卓软件☆规整说明 为了方便大家下载的时候不那么麻烦,我把所以的软件都归类到了一起,大家只要 回复关键词→111即可获得苹果软件列表 回复关键词→2 ...

  5. acme云服务器生成证书_使用 acme.sh 申请 SSL 证书并且定期自动更新

    在我们的实际项目生产过程中往往需要为部署的服务和域名配置 SSL 证书,可以采用的方法有很多种,例如可以申请阿里云的免费 SSL 证书,或者也可以使用 CloudFlare 的 SSL 服务.本文介绍 ...

  6. cloudflare免费证书_免费获取cloudflare的ssl证书

    点击ssl 证书 选中 中间那个 保存文件 xxx.pem   一个 为xxx.key server { listen 80; #listen [::]:80; server_name  xxx.ne ...

  7. aws 证书_从AWS Certificate Manager获得证书

    aws 证书 最近, AWS在欧洲地区提供了" 证书管理器 "服务. 使用此服务,您将能够对托管在AWS上的应用程序使用SSL证书 (免费). 与我在此描述的解决方案相比,最大的优 ...

  8. jodd忽略ssl证书_关于java访问https资源时,忽略证书信任问题

    java程序在访问https资源时,出现报错 sun.security.validator.ValidatorException: PKIX path building failed: sun.sec ...

  9. HttpClient 忽略证书直接访问https站点

    使用HttpClient访问https 站点时,如果Java没有导入该站点的证书的话,则会报如下错误: javax.net.ssl.SSLHandshakeException: sun.securit ...

最新文章

  1. 鸿蒙系统支持最低处理器,这四款华为手机可升级到鸿蒙系统,老机型居多,最低只需千元!...
  2. Pytorch —— GPU的使用
  3. iPhone 13 Pro系列被抢疯:官网已推迟36天发货
  4. matlab调和均值滤波_MATLAB--数字图像处理 均值滤波
  5. openai-gpt_为什么GPT-3感觉像是编程
  6. mysql扩容方案_MySQL分库分表:扩容方案
  7. c语言编译运行的几步
  8. python中步长什么意思,python步长是什么
  9. 用计算机中的知识秀恩爱,教你用专业知识取情侣网名
  10. Nicholas C. Zakas:最佳职业生涯建议
  11. 苹果App store 2015最新审核标准
  12. curse库的使用总结
  13. ad17如何生成坐标文件_pcb如何导出坐标文件
  14. 工作了,总少不了饭局的,抄来学习学习
  15. tinymce php,php - 用TinyMCE制作的PHP样式表(Hor Zebra) - SO中文参考 - www.soinside.com
  16. Revi开发 - 碰撞检测
  17. windows开源工具大全
  18. 常见外挂分类及原理概述
  19. AI时代大点兵——国内外知名AI公司2018年最新盘点【完整版】
  20. C++面向对象程序设计 024:这是什么鬼delete ---- (北大Mooc)

热门文章

  1. SqlServer常用函数
  2. 自定义的调试函数clr/c++
  3. OBJECT_ID 与objectproperty
  4. Parent属性也可释放子对象
  5. mysql 最大并发连接数
  6. LIVE555再学习 -- testRTSPClient 源码分析
  7. DM8168学习--USB的over-current 问题总结
  8. 【译】Advanced Blockchain Concepts for Beginners
  9. 第二篇 - EOS Currency 合约案例
  10. 区块链基础知识系列 第二课 区块链共识算法