为了尽可能避免安全问题,公司的很多系统服务都逐步https化,虽然开始过程会遇到各种问题,但趋势不改。最完美的https应用是能实现双向认证,客户端用私钥签名用服务端公钥加密,服务端用私钥签名客户端都公钥加密,但现实很多情况不可能让每个客户端都申请一个证书,因此只实现https的单项认证,即只要服务端又证书,客户端只验证https端证书可靠就可进行https通信。在某些情况下为了不花钱买第三方信任机构颁发都证书,客户端在一些情况下也不做服务器端都认证,两边只实现htts的加密通信。最近就遇到一个问题,https调用证书验证失败,最终考虑还是忽略调服务证书的验证。

java程序在访问https资源时,出现报错
sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
这本质上,是java在访问https资源时的证书信任问题。如何解决这个问题呢?
 
为何有这个问题?
解决这个问题前,要了解
1)https通信过程
客户端在使用HTTPS方式与Web服务器通信时有以下几个步骤,如图所示。
(1)客户使用https的URL访问Web服务器,要求与Web服务器建立SSL连接。
(2)Web服务器收到客户端请求后,会将网站的证书信息(证书中包含公钥)传送一份给客户端。
(3)客户端的浏览器与Web服务器开始协商SSL连接的安全等级,也就是信息加密的等级。
(4)客户端的浏览器根据双方同意的安全等级,建立会话密钥,然后利用网站的公钥将会话密钥加密,并传送给网站。
(5)Web服务器利用自己的私钥解密出会话密钥。
(6)Web服务器利用会话密钥加密与客户端之间的通信。
 
 
2)java程序的证书信任规则
如上文所述,客户端会从服务端拿到证书信息。调用端(客户端)会有一个证书信任列表,拿到证书信息后,会判断该证书是否可信任。
如果是用浏览器访问https资源,发现证书不可信任,一般会弹框告诉用户,对方的证书不可信任,是否继续之类。
Java虚拟机并不直接使用操作系统的keyring,而是有自己的security manager。与操作系统类似,jdk的security manager默认有一堆的根证书信任。如果你的https站点证书是花钱申请的,被这些根证书所信任,那使用java来访问此https站点会非常方便。因此,如果用java访问https资源,发现证书不可信任,则会报文章开头说到的错误。
 
解决问题的方法
1)将证书导入到jdk的信任证书中(理论上应该可行,未验证)
2)在客户端(调用端)添加逻辑,忽略证书信任问题
第一种方法,需要在每台运行该java程序的机器上,都做导入操作,不方便部署,因此,采用第二种方法。下面贴下该方法对应的代码。
 
验证可行的代码
1)先实现验证方法
  1. HostnameVerifier hv = new HostnameVerifier() {
  2. public boolean verify(String urlHostName, SSLSession session) {
  3. System.out.println("Warning: URL Host: " + urlHostName + " vs. "
  4. + session.getPeerHost());
  5. return true;
  6. }
  7. };
  8. private static void trustAllHttpsCertificates() throws Exception {
  9. javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1];
  10. javax.net.ssl.TrustManager tm = new miTM();
  11. trustAllCerts[0] = tm;
  12. javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext
  13. .getInstance("SSL");
  14. sc.init(null, trustAllCerts, null);
  15. javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc
  16. .getSocketFactory());
  17. }
  18. static class miTM implements javax.net.ssl.TrustManager,
  19. javax.net.ssl.X509TrustManager {
  20. public java.security.cert.X509Certificate[] getAcceptedIssuers() {
  21. return null;
  22. }
  23. public boolean isServerTrusted(
  24. java.security.cert.X509Certificate[] certs) {
  25. return true;
  26. }
  27. public boolean isClientTrusted(
  28. java.security.cert.X509Certificate[] certs) {
  29. return true;
  30. }
  31. public void checkServerTrusted(
  32. java.security.cert.X509Certificate[] certs, String authType)
  33. throws java.security.cert.CertificateException {
  34. return;
  35. }
  36. public void checkClientTrusted(
  37. java.security.cert.X509Certificate[] certs, String authType)
  38. throws java.security.cert.CertificateException {
  39. return;
  40. }
  41. }
2)在访问https资源前,调用
  1. trustAllHttpsCertificates();
  2. HttpsURLConnection.setDefaultHostnameVerifier(hv);

http://blog.csdn.net/lizeyang/article/details/18983843

解决https证书验证不通过的问题

1、报错信息

java.security.cert.CertificateException: No name matching api.weibo.com found; nested exception is javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No name matching api.weibo.com found

  原因:在调用api.weibo.com的时候,我们使用的是https的方式,正常情况下应该是使用api.weibo.com的证书,但由于某些原因,我们只能使用自己的证书,导致在验证证书的时候,就报了这个错误。

  解决的办法:忽略服务端和客户端的证书校验即可。java 提供的相关的类。

2、具体实现方式

  通过重写TrustManager的checkClientTrusted(检查客户端证书信任)和checkServerTrusted(检查服务端证书验证)。

  以及HostnameVerifier的verify(校验)方法即可取消对证书的所有验证。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import javax.net.ssl.*;
import java.io.IOException;
import java.net.URL;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate; public final class DisableSSLCertificateCheckUtil { private static final Logger LOGGER = LoggerFactory.getLogger(DisableSSLCertificateCheckUtil.class); /**
* Prevent instantiation of utility class.
*/ private DisableSSLCertificateCheckUtil() { } /**
* Disable trust checks for SSL connections.
*/ public static void disableChecks() {
try {
new URL("https://0.0.0.0/").getContent();
} catch (IOException e) {
// This invocation will always fail, but it will register the
// default SSL provider to the URL class.
}
try {
SSLContext sslc;
sslc = SSLContext.getInstance("TLS");
TrustManager[] trustManagerArray = {new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}};
sslc.init(null, trustManagerArray, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sslc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
});
} catch (Exception e) {
LOGGER.error("error msg:{}", e);
throw new IllegalArgumentException("证书校验异常!");
}
}
}

  调用方式:

DisableSSLCertificateCheckUtil.disableChecks();

  影响的范围:将会影响整个tomcat里面对证书的验证。即通过tomcat里面的其他项目虽然没有执行这一段代码但是也同样会忽略证书的验证。

  影响的时间:执行这段代码之后的所有时间都生效。

Java访问HTTPS时证书验证问题的更多相关文章

  1. java访问https绕过证书信任

    package com.xing.test; import java.io.BufferedReader; import java.io.IOException; import java.io.Inp ...

  2. iOS UIWebView 访问https 绕过证书验证的方法

    在文件开始实现  allowsAnyHTTPSCertificateForHost 方法 @implementation NSURLRequest (NSURLRequestWithIgnoreSSL ...

  3. iOS UIWebView 访问https绕过证书验证的方法

    @implementation NSURLRequest (NSURLRequestWithIgnoreSSL) + (BOOL)allowsAnyHTTPSCertificateForHost:(N ...

  4. How to disable SSL certificate checking with Spring RestTemplate?(使用resttemplate访问https时禁用证书检查)

    How to disable SSL certificate checking with Spring RestTemplate?(使用resttemplate访问https时禁用证书检查) **** ...

  5. java获取https网站证书,附带调用https:webservice接口

    一.java 获取https网站证书: 1.创建一个java工程,新建InstallCert类,将以下代码复制进去 package com; import java.io.BufferedReader ...

  6. java实现https免证书认证

    java实现https免证书认证   解决方法: 1.下载两个包,httpclient-4.2.jar和httpcore-4.2.jar,复制以下代码就可使用. 2.调用类代码: String htt ...

  7. 关于如何取消访问https时的提示:“此网站的安全证书存在问题”的解决方法

    问题描述: 症状1:采用IE浏览器通过https/http协议访问网站时,总是提示:“此网站的安全证书存在问题.” 症状2:采用搜狗浏览器打开网页总是看到网页的图片等元素显示不完整,是一个X的小图片. ...

  8. java程序中访问https时,报 PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

    在java中使用https访问数据时报异常: Caused by: sun.security.validator.ValidatorException: PKIX path building fail ...

  9. 微信支付HTTPS服务器证书验证指引

    1. 背景介绍 2. 常见问题 3. 验证证书 4. 安装证书 背景介绍 微信支付使用HTTPS来保证通信安全, 在HTTPS服务器上部署了由权威机构签发的证书, 用于证明微信支付平台的真实身份. 商 ...

随机推荐

  1. 有关css的选择器优先级以及父子选择器

    css,又称样式重叠表,如今的网页的样式基本是div+css写出来的,功能十分强大,要想在html文件中引入css文件需要在<head></head>标签内输入一行:<l ...

  2. 八:前端---Vue下的国际化处理

    1:首先安装 Vue-i8n npm install vue-i18n --save 注:-save-dev是指将包信息添加到devDependencies,表示你开发时依赖的包裹. -save是指将 ...

  3. 安卓通过UDP协议传输数据,中文乱码的问题

    公司最近需要往智能家居方面发展,需要用到UDP协议传输数据,在网上找到了一些资料,但是发现传输中文的时候有乱码的现象,经过我多番捣鼓,终于解决了这个问题,下面贴上关键代码 客户端: public cl ...

  4. MySQL 优化之 index_merge (索引合并)

    深入理解 index merge 是使用索引进行优化的重要基础之一.理解了 index merge 技术,我们才知道应该如何在表上建立索引. 1. 为什么会有index merge 我们的 where ...

  5. windows server 2012 r2 安装无法找到install.wim 错误代码0x80070026,以及制作U启动盘决解ISO文件超过5G大小限制的解决方案(转)

    戴尔服务器r530 windows server 2012 r2 安装无法找到install.wim 错误代码0x80070026,以及制作U启动盘决解ISO文件超过5G大小限制的解决方案 关于在服务 ...

  6. java JDBC连接 Sqlserver 非默认的实例名问题

    一般我们在连接数据库的时候都是用的默认实例名,今天遇到了用非默认是实例名:连接代码如下(Java): <property name="url" value="jdb ...

  7. Swiper 3D flow轮播使用方法

    swiper 的3d轮播效果,移动端适用 (1). 如需使用Swiper的3d切换首先加载3D flow插件(js和css). <head> <link rel="styl ...

  8. DD打卡

    一.安装逍遥安卓模拟器 二.安装钉钉 三.设置当前GPS座标 位置模拟器: 链接: https://pan.baidu.com/s/1TC5QkrGAgHOJWtzJnX6vhA 提取码: bpu8 ...

  9. javaee字符缓冲输出流

    package Zjshuchu; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOExcepti ...

  10. 【转载】关于DBUtils中QueryRunner的一些解读

    前面已经有文章说了DBUtils的一些特性, 这里再来详细说下QueryRunner的一些内部实现, 写的有错误的地方还恳请大家指出. QueryRunner类 QueryRunner中提供对sql语 ...