赞
踩
今年年初就已经吵吵着要把大部分的服务端由http转成https了,但是由于很多公司还是比较懒,而且有的公司可能不想再多掏一些钱去对自己的网址加入CA认证,所以这件事就一直拖下来了,但是随着用户数据越来越多暴露在一些不法分子眼前,所以信息安全越来越被用户重视,一些金融、贷款公司已经开始使用这种技术了,今天就来讲解一下android上面的通过https对服务器进行请求。
首先先来解答一下疑惑,我们在做测试的时候经常会对https://www.baidu.com或者https://www.github.com进行一个网络工具类的测试,但是不知道大家有没有注意到,这些网址链接之前全都是https://的,为什么我们在访问的时候完全没有报错,也能够正常的访问呢。ok,其实这两个大网站已经被CA认证过了,而CA证书已经被android设备默认支持了,所以这些CA认证的网站可以直接通过HttpUrlConnection进行连接,当然也可以通过HttpsUrlConnection进行连接。
但是除了被CA认证的网址就不能够正常的连接了,比如我们访问神奇的网站12306时,在他的注册页面其实已经升级成了Https协议的了,而且这个网站的证书是没有被CA认证过的。我们来分别对比下百度的 和github 还有我们神奇的网站12306的 签名文件~~~
见图:
第一张是百度网站的 证书文件信息
这张是github的证书信息
这张当然就是12306的喽
大家可以自己打开电脑浏览器,打开开发者工具(或者F12),然后点击security就能看到这个信息了,如果对证书感兴趣,还可以点击上边的“view certificate”去查看证书的信息
我们通过上面的三个图,不难分析出baidu 和github使用的是CA的认证的证书,而12306并没有,12306用的是自己证书
这就导致了12306需要我们特别去写一下网络请求,而百度和github则不需要。
那我们怎么去正常的访问12306呢,这里我封装了一个网络请求类,核心代码在这里:
- try {
- URL url = new URL(path);
- //1.改成s
- HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
- //2.SSLContext 初始化
- SSLContext tls = SSLContext.getInstance("TLS");
- MyX509TrustManager myX509TrustManager = new MyX509TrustManager(getX509Certificate(context));
-
- TrustManager[] trustManagers={myX509TrustManager};
- tls.init(null,trustManagers,new SecureRandom());
- //3.ssl工厂
- SSLSocketFactory factory = tls.getSocketFactory();
- //4.添加一个主机名称校验器
- conn.setHostnameVerifier(new HostnameVerifier() {
- @Override
- public boolean verify(String hostname, SSLSession session) {
- if (hostname.equals("kyfw.12306.cn")) {
- return true;
- }else{
- return false;
- }
-
- }
- });
- conn.setSSLSocketFactory(factory);
- conn.setRequestMethod("GET");
- conn.setReadTimeout(5000);
- conn.setConnectTimeout(5000);
- conn.connect();
- InputStream inputStream = conn.getInputStream();
-
- StringBuilder sb=new StringBuilder();
- int flag;
- byte[] buf=new byte[1024];
- while((flag=inputStream.read(buf))!=-1){
- sb.append(new String(buf,0,flag));
- }
- String s = sb.toString();
- //调用对方传入callback完成回调操作
- callBack.onSuccess(s);
- } catch (Exception e) {
- e.printStackTrace();
- callBack.onFail(e);
- }

1.先将我们常用的httpurlconnection变成HttpsConnection
2.初始化我们的SSLContext 这个类是ssl的一个帮助类,能够帮助我们去验证我们的证书文件
这个环节中其实稍微多一些操作,比如获取SSLContext的实例
SSLContext tls = SSLContext.getInstance("TLS");还有创建SSLContext的初始化参数,这个MyX509TrustManager是我自己封装的类
MyX509TrustManager myX509TrustManager = new MyX509TrustManager(getX509Certificate(context));
封装的类如下
- package com.guaju.httpsrequesttest.http;
-
- import java.security.InvalidKeyException;
- import java.security.NoSuchAlgorithmException;
- import java.security.NoSuchProviderException;
- import java.security.SignatureException;
- import java.security.cert.CertificateException;
- import java.security.cert.X509Certificate;
-
- import javax.net.ssl.X509TrustManager;
-
- /**
- * Created by guaju on 2017/11/7.
- */
-
- public class MyX509TrustManager implements X509TrustManager {
- //如果需要对证书进行校验,需要这里去实现,如果不实现的话是不安全
- X509Certificate mX509Certificate;
-
-
- public MyX509TrustManager(X509Certificate mX509Certificate) {
- this.mX509Certificate = mX509Certificate;
- }
-
- @Override
- public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
-
- }
-
- @Override
- public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
- for (X509Certificate certificate:chain){
- //检查证书是否有效
- certificate.checkValidity();
- try {
- certificate.verify(mX509Certificate.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];
- }
- }

而上个类中传入的构造方法中的证书文件
X509Certificate mX509Certificate;
这个证书文件需要通过我们下载的证书去获得,12306的证书在官网首页,而我们如果开发自己的公司的网站的话,后台应该会给我们一份,我们拿着这个证书放到assets目录下(或者后台的服务器上)就可以转变成我们自己的签名了,下午是12306下载证书的地方:
下方是提供的将assets中的证书文件流转化成证书的方法,很简单:
- //拿到自己的证书
- X509Certificate getX509Certificate(Context context) throws IOException, CertificateException {
- InputStream in = context.getAssets().open("srca.cer");
- CertificateFactory instance = CertificateFactory.getInstance("X.509");
- X509Certificate certificate = (X509Certificate) instance.generateCertificate(in);
- return certificate;
- }
TrustManager[] trustManagers={myX509TrustManager};
然后调用SSLContext的初始化方法
tls.init(null,trustManagers,new SecureRandom());3.上方的sslcontext初始化好之后,我们就可以做SSLSocketFactory的创建了
SSLSocketFactory factory = tls.getSocketFactory();
然后把这个工厂为我们的连接conn设置上
conn.setSSLSocketFactory(factory);
4.添加主机名称校验器,记住这里的主机名称地址需要查看我们的证书的配置,不能瞎写
证书配置如下图
下方的名称及上方的常用名称
conn.setHostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { if (hostname.equals("kyfw.12306.cn")) { return true; }else{ return false; } } });这样的话就可以访问12306的注册页面了。
ok,为了方便大家使用,我已经提交到github了,如果大家觉得不错,记得star 或者fork哦 ,多谢~~~
github:https://github.com/guaju/HttpsRequestTest
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。