java程序跳过https证书验证方式
问题描述
在企业应用开发场景中,跨系统接口对接是常见需求。现代企业往往部署多个异构系统,这些系统由不同供应商开发,采用不同的技术架构实现。系统间需要通过HTTP/HTTPS协议进行功能调用和数据交互。
HTTPS协议的安全机制可能带来开发挑战。当对接方的HTTPS证书存在配置问题时,标准的Java HTTP客户端会因证书验证失败而拒绝连接。
Java安全体系对HTTPS连接有严格的证书验证机制。客户端会检查服务器证书的颁发机构、有效期、域名匹配等信息。任何一项验证失败都会导致SSLHandshakeException异常。当对接方使用自签名证书或证书链不完整时,这种严格验证机制反而会成为系统集成的障碍。
这种情况通常需要特殊处理,暂时绕过证书验证环节,以保障系统间的正常通信。
问题复现
未跳过验证的代码
public static String request(String requestUrl,
String requestMethod, String body, String contentType, Map<String, String> heads) throws Exception{
HttpsURLConnection connection;
StringBuilder buffer = new StringBuilder();
try {
URL url = new URL(requestUrl);
connection = (HttpsURLConnection) url.openConnection();
// 创建不验证主机名的 HostnameVerifier
connection.setHostnameVerifier((hostname, session) -> true);
// 设置请求头属性
if(heads != null){
for (Map.Entry<String, String> map : heads.entrySet()) {
String key = map.getKey();
String value = map.getValue();
connection.setRequestProperty(key, value);
}
}
// 设置请求方式
connection.setRequestMethod(requestMethod);
if (StrUtil.isNotEmpty(contentType)){
connection.setRequestProperty("content-type", contentType);
}
// 当有数据需要提交时
if (null != body) {
OutputStream outputStream = connection.getOutputStream();
// 设置编码格式,防止中文乱码
outputStream.write(body.getBytes("UTF-8"));
outputStream.close();
}
// 将返回的输入流转换成字符串
InputStream inputStream = connection.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(
inputStream, "utf-8");
BufferedReader bufferedReader = new BufferedReader(
inputStreamReader);
String str = null;
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
bufferedReader.close();
inputStreamReader.close();
// 释放资源
inputStream.close();
connection.disconnect();
return buffer.toString();
} catch (Exception e) {
throw new Exception(e);
}
}
运行结果

调用上述方法后,运行出现了" javax.net.ssl.SSLHandshakeException"的错误,看这句错误 提示信息:
Caused by: 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。
这条错误提示信息意味着Java无法找到一条有效的证书链来验证请求的目标(通常是服务器)的证书。
这通常是因为服务器的证书没有被一个Java信任的证书颁发机构(CA)签发,或者证书链中的某个证书不在Java的信任库中。
解决方案一
我们可以通过在调用HTTPS接口时跳过证书验证的方式处理上述问题。
具体代码
public static String requestIgnoreSSL(String requestUrl,
String requestMethod, String body, String contentType, Map<String, String> heads) throws Exception{
HttpsURLConnection connection;
StringBuilder buffer = new StringBuilder();
try {
// 创建一个信任所有证书的 TrustManager
TrustManager[] trustManagers = new TrustManager[]{
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
// 安装信任所有证书的TrustManager
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustManagers, new java.security.SecureRandom());
URL url = new URL(requestUrl);
connection = (HttpsURLConnection) url.openConnection();
connection.setSSLSocketFactory(sslContext.getSocketFactory());
// 创建不验证主机名的 HostnameVerifier
connection.setHostnameVerifier((hostname, session) -> true);
// 设置请求头属性
if(heads != null){
for (Map.Entry<String, String> map : heads.entrySet()) {
String key = map.getKey();
String value = map.getValue();
connection.setRequestProperty(key, value);
}
}
// 设置请求方式
connection.setRequestMethod(requestMethod);
if (StrUtil.isNotEmpty(contentType)){
connection.setRequestProperty("content-type", contentType);
}
// 当有数据需要提交时
if (null != body) {
OutputStream outputStream = connection.getOutputStream();
// 设置编码格式,防止中文乱码
outputStream.write(body.getBytes("UTF-8"));
outputStream.close();
}
// 将返回的输入流转换成字符串
InputStream inputStream = connection.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(
inputStream, "utf-8");
BufferedReader bufferedReader = new BufferedReader(
inputStreamReader);
String str = null;
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
bufferedReader.close();
inputStreamReader.close();
// 释放资源
inputStream.close();
connection.disconnect();
return buffer.toString();
} catch (Exception e) {
throw new Exception(e);
}
}
说明:
自定义信任管理器(TrustManager):创建一个X509TrustManager,覆盖验证方法以信任所有证书。
- checkClientTrusted和checkServerTrusted方法留空,跳过证书验证。 - getAcceptedIssuers返回空数组,表示不限制可接受的CA。
配置SSLContext:使用自定义的TrustManager初始化SSLContext。
- - 使用TLS协议初始化SSLContext。
- - init方法的第一个参数为null表示不使用客户端证书,第二个参数传入信任所有证书的TrustManager数组。
设置默认的SSL套接字工厂和主机名验证器:替换HttpsURLConnection的默认设置,跳过主机名验证。
- - 设置HostnameVerifier直接返回true,接受所有主机名。
解决方案二
直接使用Hutool工具提供的 HttpRequest 对象,它会默认跳过 SSL 验证。
具体代码
1、引入依赖
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.24</version>
</dependency>2、代码示例:
public static void main(String[] args) throws Exception {
// GET示例
System.out.println(HttpRequest.get("https://localhost:8080/testGet/").execute().body());
JSONObject jsonObject = new JSONObject();
jsonObject.put("username", "admin");
jsonObject.put("password", "123456");
// POST示例
System.out.println(HttpRequest.post("https://localhost:8080/login").body(jsonObject.toString()).execute().body());
}
总结
总的来说,如果程序需要跳过HTTPS证书验证,使用Hutool工具可以用最少最简单的代码达到我们的需求,如果项目中未使用hutool就需要修改我们的代码创建并安装一个信任所有证书的 TrustManager便可解决问题。
在Java应用程序中跳过HTTPS证书验证通常是不推荐的,因为这会削弱应用程序的安全性,使其容易受到中间人攻击。因此跳过HTTPS证书验证仅适用于受控的环境中。推荐使用有效证书,或通过正规CA签发自签名证书,并将证书导入Java信任库(cacerts)来解决问题。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
相关文章
Java查询Elasticsearch数据根据指定id检索(in查询)、sql权限过滤、多字段匹配检索及数据排序
在Java开发中Elasticsearch(简称ES)是一个非常流行的搜索引擎,它提供了强大的全文搜索和分析功能,这篇文章主要给大家介绍了关于Java查询Elasticsearch数据根据指定id检索(in查询)、sql权限过滤、多字段匹配检索及数据排序的相关资料,需要的朋友可以参考下2024-05-05
java环境配好后jar文件打开命令框闪退(无打开方式,无反应)解决办法
在Java开发中我们经常会遇到运行Jar包时闪退的问题,下面这篇文章主要给大家介绍了关于java环境配好后jar文件打开命令框闪退(无打开方式,无反应)的解决办法,文中通过图文介绍的非常详细,需要的朋友可以参考下2024-04-04
springboot跨域过滤器fetch react Response to p
这篇文章主要介绍了springboot跨域过滤器fetch react Response to preflight request doesn‘t pass access control check问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教2024-03-03


最新评论