Java 访问 https 网站

发布于 2021-05-15 21:32:03 字数 5911 浏览 1545 评论 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

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

0 文章
0 评论
84961 人气
更多

推荐作者

书间行客

文章 0 评论 0

神妖

文章 0 评论 0

undefined

文章 0 评论 0

38169838

文章 0 评论 0

彡翼

文章 0 评论 0

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