Java 访问 https 网站

发布于 2021-05-15 21:32:03 字数 5911 浏览 1556 评论 0

下面的测试在节点 c7304 上进行,操作系统 centos7.3,JDK 是 Oracle JDK 1.8。测试目录 /opt/https

import java.io.BufferedReader;
import java.net.URL;
import java.io.OutputStream;
import java.io.InputStreamReader;
import java.io.InputStream;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.SSLSocketFactory;

public class HttpsTest {
/*
* 处理https GET/POST请求
* 请求地址、请求方法、参数
* */
  public static String httpsRequest(String requestUrl,String requestMethod,String outputStr) {
    StringBuffer buffer=null;
    try{
       //创建SSLContext
       SSLContext sslContext=SSLContext.getInstance("SSL");
       //初始化。第一个null是KeyManager,第二个null是TrustManager。
       sslContext.init(null, null, null);

       //获取SSLSocketFactory对象
       SSLSocketFactory ssf=sslContext.getSocketFactory();
       URL url=new URL(requestUrl);
       HttpsURLConnection conn=(HttpsURLConnection)url.openConnection();
       conn.setDoOutput(true);
       conn.setDoInput(true);
       conn.setUseCaches(false);
       conn.setRequestMethod(requestMethod);

       //设置当前实例使用的SSLSoctetFactory
       conn.setSSLSocketFactory(ssf);
       conn.connect();
       //往服务器端写内容
       if(null!=outputStr) {
          OutputStream os=conn.getOutputStream();
          os.write(outputStr.getBytes("utf-8"));
          os.close();
        }
        //读取服务器端返回的内容
        InputStream is=conn.getInputStream();
        InputStreamReader isr=new InputStreamReader(is,"utf-8");
        BufferedReader br=new BufferedReader(isr);
        buffer=new StringBuffer();
        String line=null;
        while((line=br.readLine())!=null) {
          buffer.append(line);
        }
      } catch(Exception e){
        e.printStackTrace();
      }
    return buffer.toString();
  }

  public static void main(String[] args) {
    if(args.length==0) {
      System.out.println("Please enter URL.");
      return;
    }
    String s = httpsRequest(args[0],"GET",null);
    System.out.println(s);
  }
}

在上述代码中,需要关注是的 sslContext.init(null, null, null); 这行代码。第 2 个参数代表 可信证书库,null 表示使用默认的可信证书库,即 cacerts。至于第 1 个参数,双向 SSL 会用到,编译运行:

$ javac HttpsTest.java
$ java HttpsTest https://baidu.com                         (正常执行)
$ java HttpsTest https://kyfw.12306.cn                     (报错)

kyfw.12306.cn 报错是因为它的证书不是公共 CA 签发的。

自建信任库

首先,查询 kyfw.12306.cn 的公钥:

$ openssl s_client -connect kyfw.12306.cn:443

将显示在屏幕上的 -----BEGIN CERTIFICATE----- 和 -----END CERTIFICATE----- 之间的内容(包括这两行)复制到一个文件(12306.crt)中。
执行下列 keytool 命令后会生成文件 trust.jks,-trustcacerts 参数保证了导入的条目类型是 可信证书

$ keytool -import -trustcacerts -keystore trust.jks -alias 12306 -file 12306.crt -storepass vagrant
$ java -Djavax.net.ssl.trustStore=trust.jks HttpsTest https://kyfw.12306.cn      (正常执行)

自制信任库中只有 kyfw.12306.cn 网站的证书,访问其他网站会报错,如:

$ java -Djavax.net.ssl.trustStore=trust.jks HttpsTest https://baidu.com         (报错)

导入 java 信任库

用 keytool 将 12306.crt 导入到 JDK 的信任库:

$ keytool -import -trustcacerts -keystore /usr/java/jdk1.8.0_131/jre/lib/security/cacerts -alias 12306 -file 12306.crt -storepass changeit

重新发送请求:

$ java HttpsTest https://kyfw.12306.cn

不再报错。说明 kyfw.12306.cn 已经在 JDK 的信任库中,JDK 允许客户端发送请求到这个主机。

小结

Java 用以下优先级处理可信证书库:

  1. sslContext.init() 的第 2 个参数传入优先级最高。这个在讲 双向SSL 的章节中有说明。
  2. -Djavax.net.ssl.trustStore 系统属性传入优先级次之
  3. JDK 默认可信证书库 cacerts 优先级最低

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

JSmiles

生命进入颠沛而奔忙的本质状态,并将以不断告别和相遇的陈旧方式继续下去。

文章
评论
84965 人气
更多

推荐作者

李珊平

文章 0 评论 0

Quxin

文章 0 评论 0

范无咎

文章 0 评论 0

github_ZOJ2N8YxBm

文章 0 评论 0

若言

文章 0 评论 0

南…巷孤猫

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文