一个干净的SSL连接

你是不是想要写一个尽量干净的SSL连接,最好能够完全通过JDK就能完成,不需要借助任何其他依赖,那么看这篇博客就对了。

我会将这部分的代码展示出来,作为分享,作为回报你们应该也多多的分享自己的作品!

我这里分两个类,一个是包含请求方法的类,一个是实现X509TrustManager接口的类。

我这里做了一个比较丰富例子,那么我介绍一下.

  1. 对本地ES发起的一个SSL请求
  2. POST请求类型
  3. 含有账号密码认证BASIC Auth
  4. 请求体内容为JSON格式

额外说明

因为是SSL请求必不可少就是信任问题,面对信任问题,SSL有单向和双向认证,我这里很简单就是单项验证,请求方 验证响应方 ,那么作为请求的发起程序就需要有信任证书库,库里面要有响应方的证书的签发者即根证书。这里我们可以

  1. 导入JDK默认的证书库中

借助JDK自带的keytool 工具将根证书放到一个信任证书库中,JDK有一个默认的库,JDK8中的位置是JAVA_HOME\jre\lib\security ,名字是cacerts 密码是changeit,8以上的JDK版本证书位置会不一样,但是名字和密码都是一样的。

  • 导入证书

    //说明 -keystore 是证书库名 -file后面是证书名称, -alias是证书在证书库中别名方便我们找到他
    keytool -import -keystore cacerts -file root.cer -alias xxx-root

  1. 自建证书库

也可以我们自己建一个库里面放根证书,然后将路径配置到系统配置中。

  • 建立证书库

    //说明 -keystore 是证书库名如果没有就会自动创建库然后做导入操作 -file后面是证书名称, -alias是证书在证书库中别名方便我们找到他
    keytool -import -keystore mycacerts -file root.cer -alias xxx-root

  • 路径和密码配置

java 复制代码
System.setProperty("javax.net.ssl.trustStore", TrustStorePath);
System.setProperty("javax.net.ssl.trustStorePassword", TrustStorePassword);

如果没有做上面的两个步骤来保证单向认证的畅通,那么尝试建立连接的话就会报以下错误。

复制代码
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

代码

我这里提供了一个跳过验证过程也就是insecure的模式,需要实现一个X509TrustManager接口,将其中的验证方法置空,就不用验证书了。但是记住这是存在风险的,在正式环境中切勿这样做。

java 复制代码
package com.java;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import java.io.*;
import java.net.Authenticator;
import java.net.MalformedURLException;
import java.net.PasswordAuthentication;
import java.net.URL;


public class REST {
    public static void main(String[] args) throws IOException {
        String url = "https://xxx.xxx.xxx.xxx:9200/index/_search";
//        String url = "https://www.sun.com";
        String data = "{\t\t\n" +
                "\t\t\"query\": {\n" +
                "            \"bool\": {\n" +
                "                \"must\": [\n" +
                "                  {\"match\": {\n" +
                "                    \"status\": 1\n" +
                "                  }},\n" +
                "                  {\"match\": {\n" +
                "                    \"xx_name\": \"xxxx\"\n" +
                "                  }}\n" +
                "                ]\n" +
                "              }\n" +
                "\t\t}}";
        String res = httpRequest(url, data);
    }


    public static String httpRequest(String httpsUrl, String data) {
		/**
		*下面两行就是指定自建库位置和密码的配置
		*当你导入了根证书或者配置了自建库下面的四行空验证insecure模式代码就可以去掉,推荐证书链完整的验证方式
		*/
		//System.setProperty("javax.net.ssl.trustStore", "F:\\JDKversions\\JDK11\\lib\\security\\mycacerts");
		//System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
        HttpsURLConnection urlCon = null;

        try {
            urlCon = (HttpsURLConnection)(new URL(httpsUrl)).openConnection();
            urlCon.setDoInput(true);
            urlCon.setDoOutput(true);
            urlCon.setRequestMethod("POST");
            urlCon.setRequestProperty("Content-Type", "application/json");
            //下面的四行就是为了配置一个自定义的空验证,即不需要验证就建立连接的一个insecure模式,不建议
            TrustManager[] tm = {new MyX509TrustManager ()};
            SSLContext sslContext = SSLContext.getInstance("SSL","SunJSSE");
            sslContext.init(null, tm, new java.security.SecureRandom());
            urlCon.setSSLSocketFactory(sslContext.getSocketFactory());
            Authenticator authenticator = new Authenticator() {
                @Override
                protected PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication("xxxxxx", "xxxx".toCharArray());
                }
            };
            urlCon.setAuthenticator(authenticator);
            urlCon.setRequestProperty("Content-Length", String.valueOf(data.getBytes().length));
            urlCon.setUseCaches(false);
            urlCon.getOutputStream().write(data.getBytes("utf-8"));
            urlCon.getOutputStream().flush();
            urlCon.getOutputStream().close();
            BufferedReader in = new BufferedReader(new InputStreamReader(urlCon.getInputStream(), "utf-8"));
            StringBuffer sb = new StringBuffer();

            String line;
            while((line = in.readLine()) != null) {
                sb.append(line + "\r\n");
            }

            return sb.toString();
        } catch (MalformedURLException var6) {
            var6.printStackTrace();
        } catch (IOException var7) {
            var7.printStackTrace();
        } catch (Exception var8) {
            var8.printStackTrace();
        }

        return null;
    }
}
java 复制代码
package com.java;

import javax.net.ssl.X509TrustManager;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

public class MyX509TrustManager implements X509TrustManager {
    @Override
    public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

    }

    @Override
    public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

    }

    @Override
    public X509Certificate[] getAcceptedIssuers() {
        return new X509Certificate[0];
    }

}

参考博客

java HttpsURLConnection发送https请求

相关推荐
呆呆的私房菜9 分钟前
你了解数据库区域和编码吗?
数据库
信徒_33 分钟前
Kafka 如何保证消息可靠性?
数据库·分布式·kafka
qq_260241231 小时前
宝塔面板使用CDN 部署后获取真实客户端 IP教程
网络·网络协议·tcp/ip
magic 2451 小时前
Spring启示录、概述、入门程序以及Spring对IoC的实现
java·开发语言·数据库·spring
-天凉好秋-1 小时前
Springboot同时支持不同的数据库,Oracle,Postgresql
数据库·spring boot·oracle
courniche2 小时前
CSMA/CA与CSMA/CD的区别
网络·网络协议·信息与通信·信号处理
不平衡的叉叉树2 小时前
MySql表达式中字符串类型与整型的隐式转换
数据库·mysql
三月七(爱看动漫的程序员)2 小时前
LLM面试题八
数据库·gpt·算法·langchain·prompt·启发式算法·llama
玄明Hanko2 小时前
Redis到底能不能做主数据库?
数据库·redis·后端
程序员鱼皮2 小时前
如何开发 MCP 服务?保姆级教程!
数据库·程序员·ai编程