javax.net.ssl.SSLHandshakeException:异常解决方案

javax.net.ssl.SSLHandshakeException:java.security.cert.CertificateException: No subject alternative names matching IP address xxxx解决方案

报错原因

一般出现这种问题是因为目标服务器的证书问题, 证书的 Subject Alternative Names 字段中没有包含客户端所使用的连接地址(这里是 IP 地址)

一般建议不要使用IP地址来进行链接,如果实在是要用IP地址来进行连接的话,有两种处理方案:

方法一:可以将IP地址加入到服务器证书的 Subject Alternative Names 字段中;

方法二:在程序中进行处理,绕过目标服务器的安全验证

下面来介绍的就是方法二:在程序中绕过服务器的安全验证

在程序中绕过服务器的安全验证

以下就是绕过服务器验证的具体实现代码

java 复制代码
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.security.SecureRandom;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;


/**
 * @author cbcbcb
 *
 */
public class Test {

	public static void main(String[] args) {
		// 测试绕过主机验证
		String pathUrl ="https://IP:PORT/api/test";
		String json = "{\"name\":\"ccc\"}";
		StringBuffer sbf = new StringBuffer();
        try {
            // 创建信任所有证书的 TrustManager
            TrustManager[] trustAllCerts = new TrustManager[]{
                    new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {
                        }

                        @Override
                        public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {
                        }

                        @Override
                        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                            return new java.security.cert.X509Certificate[]{};
                        }
                    }
            };

            // 创建 SSLContext 并初始化
            SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new SecureRandom());

            // 获取 SSLSocketFactory
            SSLSocketFactory ssf = sslContext.getSocketFactory();

            // 创建绕过主机名验证的 HostnameVerifier
            HostnameVerifier allHostsValid = new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            };

            URL urlx = new URL(pathUrl);
            HttpsURLConnection connection = (HttpsURLConnection) urlx.openConnection();
            connection.setDoInput(true);
            connection.setDoOutput(true);
            connection.setRequestMethod("POST");
            connection.setUseCaches(false);
            connection.setInstanceFollowRedirects(true);
            connection.addRequestProperty("Content-Type", "application/json");
            connection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");

           

            // 设置 SSLSocketFactory 和 HostnameVerifier
            connection.setSSLSocketFactory(ssf);
            connection.setHostnameVerifier(allHostsValid);

            connection.connect();
            DataOutputStream out = new DataOutputStream(connection.getOutputStream());

            if (!"".equals(json)) {
                out.write(json.getBytes());
            }
            out.flush();
            out.close();

            BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            String lines;
            while ((lines = reader.readLine()) != null) {
                lines = new String(lines.getBytes(), "UTF-8");
                sbf.append(lines);
            }
//             System.out.println("crm返回参数:" + sbf);
            reader.close();
            // 断开连接
            connection.disconnect();
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(decodeUnicode(sbf.toString()));
		
	}

    //下面这个方法是对输出的内容进行编译,有些接口返回的数据在输出台可能会是乱码展示
    //这个时候在什么方法都无用的情况下,可以通过这个方法将乱码重新编译成正确的展示
	    public static String decodeUnicode(String str) {
	        Pattern pattern = Pattern.compile("(\\\\u(\\p{XDigit}{4}))");
	        Matcher matcher = pattern.matcher(str);
	        char ch;
	        while (matcher.find()) {
	            ch = (char) Integer.parseInt(matcher.group(2), 16);
	            str = str.replace(matcher.group(1), ch + "");
	        }
	        return str;
	    }
	

}

注意点

在上面这串代码中,有一些需要注意的一点就是在设置绕过验证的时候一定要注意设置的是对当前实例绕过还是全部都绕过,稍微有点不注意,设置成了全局的话,那么整个项目所有的链接都会收到相应的影响,所以这里一定要注意注意再注意

HttpsURLConnection.setDefaultHostnameVerifier-----全局设置

java 复制代码
//全局设置
HostnameVerifier allHostsValid = new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;           
            }
        };
        HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);

connection.setHostnameVerifier(allHostsValid);-------设置对当前实例的

java 复制代码
// 创建绕过主机名验证的 HostnameVerifier
            HostnameVerifier allHostsValid = new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            };
 connection.setHostnameVerifier(allHostsValid);

最后多说一句

如果不好把控这个代码究竟有没有用的话,可以先不要更新到正式环境,先在本地或者测试服务器尝试一下在更新

相关推荐
裕晟资质规划1 分钟前
三类涉密资质延续时限差异分析:军工60日与集成印制3个月的边界
java·服务器·前端·网络·安全
念念清晰2 分钟前
000-OpenJDK17 源码构建:MacOS环境(M芯片)
java·后端
Wang's Blog26 分钟前
Java 项目实战: 交友项目 - 百度人脸识别入门案例
java·百度·交友
wuminyu1 小时前
JMM学习总结:深入理解happens-before关系
java·linux·c语言·jvm·c++
电商API_180079052471 小时前
反向海淘多币种结算:汇率该在哪个时点被冻结
java·开发语言·数据库·跨境电商·1688 api
开开心心就好2 小时前
多份文档怎么批量打印?支持多种格式
java·服务器·开发语言·pdf·ocr·散列表·启发式算法
Pniubi2 小时前
模拟一个充值送token怎么保证幂等?一致性?原子性?
java
企业数字化笔记2 小时前
多租户配额怎么控制?用量口径、并发预留与超额处理的实现方法
java·数据库·spring boot
巴勒个啦3 小时前
Prompt Engineering 实战:5 个让 AI 生成生产级业务代码的工程模式
java·前端
倚楼听风语3 小时前
Kotlin 协程与 suspend 原理详解
java·算法·kotlin