Java 访问 https 网站
下面的测试在节点 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 用以下优先级处理可信证书库:
sslContext.init()
的第 2 个参数传入优先级最高。这个在讲 双向SSL 的章节中有说明。-Djavax.net.ssl.trustStore
系统属性传入优先级次之- JDK 默认可信证书库 cacerts 优先级最低
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论