当前位置:   article > 正文

android 使用https请求

android

今年年初就已经吵吵着要把大部分的服务端由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呢,这里我封装了一个网络请求类,核心代码在这里:


  1. try {
  2. URL url = new URL(path);
  3. //1.改成s
  4. HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
  5. //2.SSLContext 初始化
  6. SSLContext tls = SSLContext.getInstance("TLS");
  7. MyX509TrustManager myX509TrustManager = new MyX509TrustManager(getX509Certificate(context));
  8. TrustManager[] trustManagers={myX509TrustManager};
  9. tls.init(null,trustManagers,new SecureRandom());
  10. //3.ssl工厂
  11. SSLSocketFactory factory = tls.getSocketFactory();
  12. //4.添加一个主机名称校验器
  13. conn.setHostnameVerifier(new HostnameVerifier() {
  14. @Override
  15. public boolean verify(String hostname, SSLSession session) {
  16. if (hostname.equals("kyfw.12306.cn")) {
  17. return true;
  18. }else{
  19. return false;
  20. }
  21. }
  22. });
  23. conn.setSSLSocketFactory(factory);
  24. conn.setRequestMethod("GET");
  25. conn.setReadTimeout(5000);
  26. conn.setConnectTimeout(5000);
  27. conn.connect();
  28. InputStream inputStream = conn.getInputStream();
  29. StringBuilder sb=new StringBuilder();
  30. int flag;
  31. byte[] buf=new byte[1024];
  32. while((flag=inputStream.read(buf))!=-1){
  33. sb.append(new String(buf,0,flag));
  34. }
  35. String s = sb.toString();
  36. //调用对方传入callback完成回调操作
  37. callBack.onSuccess(s);
  38. } catch (Exception e) {
  39. e.printStackTrace();
  40. callBack.onFail(e);
  41. }

主要的思路是:

1.先将我们常用的httpurlconnection变成HttpsConnection

2.初始化我们的SSLContext 这个类是ssl的一个帮助类,能够帮助我们去验证我们的证书文件

这个环节中其实稍微多一些操作,比如获取SSLContext的实例

SSLContext tls = SSLContext.getInstance("TLS");
还有创建SSLContext的初始化参数,这个MyX509TrustManager是我自己封装的类

MyX509TrustManager myX509TrustManager = new MyX509TrustManager(getX509Certificate(context));


封装的类如下

  1. package com.guaju.httpsrequesttest.http;
  2. import java.security.InvalidKeyException;
  3. import java.security.NoSuchAlgorithmException;
  4. import java.security.NoSuchProviderException;
  5. import java.security.SignatureException;
  6. import java.security.cert.CertificateException;
  7. import java.security.cert.X509Certificate;
  8. import javax.net.ssl.X509TrustManager;
  9. /**
  10. * Created by guaju on 2017/11/7.
  11. */
  12. public class MyX509TrustManager implements X509TrustManager {
  13. //如果需要对证书进行校验,需要这里去实现,如果不实现的话是不安全
  14. X509Certificate mX509Certificate;
  15. public MyX509TrustManager(X509Certificate mX509Certificate) {
  16. this.mX509Certificate = mX509Certificate;
  17. }
  18. @Override
  19. public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
  20. }
  21. @Override
  22. public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
  23. for (X509Certificate certificate:chain){
  24. //检查证书是否有效
  25. certificate.checkValidity();
  26. try {
  27. certificate.verify(mX509Certificate.getPublicKey());
  28. } catch (NoSuchAlgorithmException e) {
  29. e.printStackTrace();
  30. } catch (InvalidKeyException e) {
  31. e.printStackTrace();
  32. } catch (NoSuchProviderException e) {
  33. e.printStackTrace();
  34. } catch (SignatureException e) {
  35. e.printStackTrace();
  36. }
  37. }
  38. }
  39. @Override
  40. public X509Certificate[] getAcceptedIssuers() {
  41. return new X509Certificate[0];
  42. }
  43. }


而上个类中传入的构造方法中的证书文件

X509Certificate mX509Certificate;


这个证书文件需要通过我们下载的证书去获得,12306的证书在官网首页,而我们如果开发自己的公司的网站的话,后台应该会给我们一份,我们拿着这个证书放到assets目录下(或者后台的服务器上)就可以转变成我们自己的签名了,下午是12306下载证书的地方:



下方是提供的将assets中的证书文件流转化成证书的方法,很简单:

  1. //拿到自己的证书
  2. X509Certificate getX509Certificate(Context context) throws IOException, CertificateException {
  3. InputStream in = context.getAssets().open("srca.cer");
  4. CertificateFactory instance = CertificateFactory.getInstance("X.509");
  5. X509Certificate certificate = (X509Certificate) instance.generateCertificate(in);
  6. return certificate;
  7. }


创建TrustManager数组,将上方的MyX509TrustManager放进数组中去

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



声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/210703
推荐阅读
相关标签
  

闽ICP备14008679号