OkHttp配置HTTPS访问+服务器部署
1 概述
OkHttp配置HTTPS访问,核心为以下三个部分:
- sslSocketFactory()
- HostnameVerifier
- X509TrustManager
第一个是ssl套接字工厂,第二个用来验证主机名,第三个是证书信任器管理类.通过OkHttp实现HTTPS访问需要自己实现以上三部分.另外还简单提及了服务器端的部署,用的是Tomcat9,最后是一些常见问题的可能解决方案.
2 OkHttp介绍
OkHttp是一款开源的处理网络请求的轻量级框架,有Square公司贡献,用于替代HttpUrlConnection与Apache HttpClient,目前Github上有36.4k的star.优点有
- 共享socket,HTTP/2支持所有连接到同一个主机的请求共享socket
- 连接池可以减少请求延迟
- 缓存响应数据减少重复的网络请求
- 自动处理gzip压缩
总的来说OkHttp是一款支持get/post请求,支持文件上传/下载的优秀的HTTP框架.
3 准备工作
- 一台服务器
- 一个域名
- 一个证书
什么?都没有?买!
当然证书可以不用买,可以使用openssl之类的工具生成,不过自签名的证书后面验证的时候会有点麻烦,建议还是购买.
4 OkHttp部分
4.1 暴力方案
public static String test() {
OkHttpClient client = new OkHttpClient.Builder()
.sslSocketFactory(createSSLSocketFactory(), new TrustAllCerts())
.hostnameVerifier(new TrustAllHostnameVerifier()).build();
String url = "https://xxxxxxx"; //修改成自己的url
Request request = new Request.Builder().url(url).build();
Call call = build.newCall(request);
Response response = call.execute();
if(response.body() != null)
{
String result = response.body().string();
//处理result
}
}
private static class TrustAllCerts implements X509TrustManager {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
public X509Certificate[] getAcceptedIssuers() {return new X509Certificate[0];}
}
private static class TrustAllHostnameVerifier implements HostnameVerifier {
public boolean verify(String hostname, SSLSession session) { return true; }
}
private static SSLSocketFactory createSSLSocketFactory() {
SSLSocketFactory ssfFactory = null;
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, new TrustManager[]{new TrustAllCerts()}, new SecureRandom());
ssfFactory = sc.getSocketFactory();
} catch (Exception e) {
e.printStackTrace();
}
return ssfFactory;
}
这是一种暴力的方案,看类名就知道了,信任所有的证书与主机:
public boolean verify(String hostname, SSLSession session) { return true; }
这个方法直接返回true,也就是信任所有的主机.
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
这里两个check函数没有做任何的工作,表示接受任意的客户端与服务端的证书.这样写的话相当于是使用了一个没用的TrustManager,这样还不如不加密,不推荐使用.
4.2 推荐方案
从两方面入手修改,一是从X509TrustManager入手,二是从HostnameVerifier入手.
4.2.1 HostnameVerifier
先说个简单的,这里主要是验证主机名,简单的话,可以如下实现:
HostnameVerifier hnv = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
if("www.test.com".equals(hostname)){
return true;
}
else {
HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
return hv.verify(hostname, session);
}
}
};
这里验证主机名是www.test.com就返回true,实现得比较简单,业务复杂的话可以结合配置中心,黑/白名单等动态校验.
4.2.2 X509TrustManager
这里其实有两种方式,一种是以流的方式添加信任证书:
private static X509TrustManager trustManagerForCertificates(InputStream in)
throws GeneralSecurityException
{
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
Collection<? extends Certificate> certificates = certificateFactory.generateCertificates(in);
if (certificates.isEmpty()) {
throw new IllegalArgumentException("expected non-empty set of trusted certificates");
}
char[] password = "password".toCharArray(); // 这里可以使用任意密码
KeyStore keyStore = newEmptyKeyStore(password);
int index = 0;
for (Certificate certificate : certificates) {
String certificateAlias = Integer.toString(index++);
keyStore.setCertificateEntry(certificateAlias, certificate);
}
// Use it to build an X509 trust manager.
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(
KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, password);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager))
{
throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers));
}
return (X509TrustManager) trustManagers[0];
}
完整代码见文末.这里把工具类的方法实现成了静态,调用时可以直接:
OKHTTP.send("https://xxxxx");
另一种方式是直接自定义一个TrustManager,重写里面的三个方法:
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, new TrustManager[]{
new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain,String authType) throws CertificateException {}
@Override
public void checkServerTrusted(X509Certificate[] chain,String authType) throws CertificateException {
for (X509Certificate cert : chain) {
// Make sure that it hasn't expired.
cert.checkValidity();
// Verify the certificate's public key chain.
try {
cert.verify(((X509Certificate) ca).getPublicKey());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (NoSuchProviderException e) {
e.printStackTrace();
} catch (SignatureException e) {
e.printStackTrace();
}
}
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
}, null);
第一个方法为
@Override
public void checkClientTrusted(X509Certificate[] chain,String authType) throws CertificateException {}
该方法检查客户端的证书,由于不需要对客户端进行认证,默认即可.
第二个方法为
@Override
public void checkServerTrusted(X509Certificate[] chain,String authType)
该方法检查服务器的证书,若不信任该证书则抛出异常,通过自己实现该方法可以信任任何自己指定的证书,不做任何处理的话,不会抛出任何异常,相当于信任所有证书.这里检查了证书是否过期以及证书的签名是否匹配.
第三个方法为
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
返回受信任的X509证书数组.
这种方法笔者没有试过,仅供参考.
5 服务器部署
服务器用的是Tomcat,简单介绍一下部署.
5.1 上传工程
后端处理用的Spring Boot的工程,就不演示了,使用IDEA打成war包后上传到webapps下即可.
5.2 Tomcat配置
重点说一下Tomcat的配置,首先需要一个域名,修改conf/server.xml文件,找到默认的名叫localhost的Host:
然后直接复制Host标签,把name修改成自己的域名即可.
然后是证书的配置,笔者的证书在某某云上购买的,这里提供了几种格式的证书下载:
Tomcat的是两个文件,一个是pfx文件,一个是密码文件,把pfx文件上传到服务器的Tomcat后,继续修改server.xml,大约87行左右的位置(Tomcat版本9.0.33):
修改如下:
添加了scheme,secure,keystoreFile,keystoreType,keystorePass,clientAuth,sslProtocol配置,同时去掉里面的<SSLHostConfig>,keystoreFile是刚才的pfx文件,采用绝对路径,keystorePass是密码.
另外默认的端口为8443,这里修改成了8123.
重启Tomcat后输入
https://www.test.com:port
进行测试
这样就成功了.
6 验证与源码
这个因为没有完整的Demo很难做验证,具体来说前端用的OkHttp核心都介绍了,后端的话服务器Tomcat也介绍了,用Spring Boot做个Demo应该不难.
这里只给出了工具类OKHTTP的源码:
github
7 常见问题
7.1 Tomcat HTTPS无法访问
- 证书文件错误,不过这个可能性比较少.
- 配置错误,请检查配置文件是否正确,可以ps -ef | grep tomcat查看Tomcat是否开启以及查看logs/catalina.out日志.
- 端口错误,访问的端口需要与<Connector>中的端口对应(Tomcat默认的HTTPS端口为8443,笔者居然看成了8433,然后netstat 无数次都没有看到被监听...)
- 安全组/防火墙问题,云服务器的话需要在安全组配置中开启相应端口,同时应查看有没有把某个ip列入黑名单导致无法访问.防火墙的话这里主要指iptables,如果没有开启的话不需要理会,如果开启的话需要开放对应端口.
7.2 OkHttp HTTPS无法访问
- 无法读取证书文件:需要把证书文件放在工程对应路径下读取,比如AS中放在assets下然后使用getAssets().open("xxx.xxx")获取,Maven工程的话放在resources下直接使用FileInputStream获取.
- singed fields invalid:
证书文件格式错误,使用.crt/.pem等证书. - Signature does not match:这个有可能是使用openssl自生成证书在验证的时候出现的异常,可能的解决办法是转换证书的格式,如果不行就重新生成一次证书.
8 参考链接
1.苹果核 - Android App 安全的HTTPS 通信
2.Android OkHttp实现HTTPS访问,支持Android 4.X系统HTTPS访问
3.Android使用OkHttp请求自签名的https网站
OkHttp配置HTTPS访问+服务器部署的更多相关文章
- 配置HTTPS网站服务器
配置HTTPS网站服务器 案例1:配置安全Web服务 1.1问题 本例要求为站点http://server0.example.c ...
- Linux Apache配置https访问
配置https访问 该环境是rh254课程配套的一个环境,不过配置方法步骤相同. 要求: 使用虚拟主机技术部署两个网站: 网站1: 绑定域名 www0.example.com 目录在 /srv/www ...
- 使用docker搭建最新版本的gitea,并配置HTTPS访问
使用docker搭建最新版本的gitea,并配置HTTPS访问 博客说明 文章所涉及的资料来自互联网整理和个人总结,意在于个人学习和经验汇总,如有什么地方侵权,请联系本人删除,谢谢! 简介 之前有搭建 ...
- lamp之apache配置https访问
配置apache 使用https 注:怕其他人由于路径的原因出问题,首先声明一下,本人apache的安装目录为 : /usr/local/httpd2.4.25,如果不是,请参考进行配置 注: 对于如 ...
- 本地测试Tomcat配置Https访问
一.tomcat开启HTTPS配置 1) 准备证书 使用jdk工具keytool生成一个ssl测试用证书, 一路按照提示操作输入即可 keytool -genkey -alias tomcat -ke ...
- 阿里云 rails nginx 配置https访问
1.申请免费型dv ssl证书:https://common-buy.aliyun.com/?spm=a2c4e.11155515.0.0.7zzvOZ&commodityCode=cas#/ ...
- nginx配置https访问
一.准备 环境:centos6.8 nginx:1.13.6 二.开始 首先安装依赖包: yum install -y gcc gcc-c++ autoconf automake make ...
- 基于openresty配置https访问
安装方法:http://openresty.org/cn/linux-packages.html 1. openssl的版本信息 [root@localhost conf]# openssl vers ...
- Apache 配置 HTTPS访问
将需要配置的项目移动到另一根目录下,作为https访问位置. 修改bitnami配置文件..\Bitnami\wampstack-5.6.19-0\apache2\conf\bitnami\bitna ...
随机推荐
- 19_MySQL表的内连接
本节所涉及的SQL语句: -- 表连接查询 -- 查询每名员工(员工名字,编号)的部门信息(部门编号,部门名称) SELECT e.empno,e.ename,d.dname FROM t_emp e ...
- windows server2012 搭建FTP服务器过程
搭建过程链接地址:https://blog.csdn.net/smalllu161226/article/details/53887751 1.打开windows server2012R2 服务器管理 ...
- 翻译:《实用的Python编程》02_05_Collections
目录 | 上一节 (2.4 序列) | 下一节 (2.6 列表推导式) 2.5 collections 模块 collections 模块为数据处理提供了许多有用的对象.本部分简要介绍其中的一些特性. ...
- Android - 利用扩展函数为Bitmap添加文字水印
<异空间>项目技术分享系列--扩展函数为Bitmap添加文字水印 对图片Bitmap绘制文字水印还是比较常见的需求,毕竟版权意识都在增强(用户可以给自己图片加上用户名),还可以为用户提供更 ...
- 178. 分数排名 + MySql + RANK() OVER
178. 分数排名 LeetCode_MySql_178 题目描述 题解分析 排名函数 DENSE_RANK().如果使用 DENSE_RANK() 进行排名会得到:1,1,2,3,4. RANK() ...
- 剑指 Offer 22. 链表中倒数第k个节点
剑指 Offer 22. 链表中倒数第k个节点 Offer 22 常规解法 常规解法其实很容易可以想到,只需要先求出链表的长度,然后再次遍历取指定长度的链接即可. package com.walega ...
- 2.2 Python3基础-基本数据类型
>>返回主目录 源代码 # 基本数据类型 # Number类型:如何查看变量的数据类型? name = 'Portos' print(type(name)) # 结果:str print( ...
- ElasticSearch 进阶
目录 ElasticSearch 进阶 SearchAPI 检索信息 Query DSL 基本语法格式 查询-match 查询-match_phrase 查询-multi_match 查询-bool复 ...
- P3160 [CQOI2012]局部极小值 题解(状压DP+容斥)
题目链接 P3160 [CQOI2012]局部极小值 双倍经验,双倍快乐 解题思路 存下来每个坑(极小值点)的位置,以这个序号进行状态压缩. 显然,\(4*7\)的数据范围让极小值点在8个以内(以下示 ...
- YoloV3 记录
常用于目标检测,因为最近要从目标分类问题转到目标检测中去. tensoflow.Keras(大公司一般都用这个).pytorch(本次学习)------------------主要框架 程序设计模块规 ...