一个干净的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
  • 路径和密码配置
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接口,将其中的验证方法置空,就不用验证书了。但是记住这是存在风险的,在正式环境中切勿这样做。

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;
    }
}

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请求

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值