Android支持Https总结

整合了一个工具类HttpsUtil,地址:

https://github.com/kabuzai/Android-Https

基本使用

  1. 全局支持Https只需在Application中调用
    HttpsUtil.initHttpsUrlConnection(this);

  2. 适用的网络请求:

  • 直接使用HttpUrlConnection的请求
  • 底层实现是HttpUrlConnection的框架(比如Volley(Api 9+)、ImageLoader、Glide等)
  1. OkHttp不适用,可以调用
    HttpsUtil.getHttpsOkHttpClient(Context context)
    来获取支持Https的OkHttpClient。

  2. 服务端证书放在Assets目录下
    修改证书名:
    private static final String[] CERTIFICATES = new String[]{"证书名.cer"};
    如有多个证书,向CERTIFICATES添加即可。

  3. 默认支持的是单向验证,安全性已足够

  • 如需要不进行验证,将CERTIFICATES元素清空即可,但这样存在极大的安全隐患,慎用!!
  • 如需要双向认证,需修改initHttpsUrlConnection的实现:
    public static void initHttpsUrlConnection(Context context) {
        InputStream[] certificates = getCertificates(context, CERTIFICATES);
        SSLSocketFactory sslSocketFactory = getSSLSocketFactory(certificates, null, null);
        HttpsURLConnection.setDefaultSSLSocketFactory(sslSocketFactory);
        if (certificates == null) {
            HttpsURLConnection.setDefaultHostnameVerifier(getUnSafeHostnameVerifier());
        }
    }

其中getSSLSocketFactory方法的后两个参数需要传入合适的值
具体实现可参考:
http://blog.csdn.net/lmj623565791/article/details/48129405

为什么Https请求需要这样额外配置?

简单来说,Https相比Http多了一层SSL验证,这个验证有很多步骤。其中有一步是对服务器证书的校验,而服务器证书的获得:

  • 可以由权威机构颁发,这些机构大多数都已经在Android设备的信任列表中,这样的证书不需要额外配置就能直接访问Https,那些不在设备信任列表的机构颁发的证书就需要进行配置。
    注意:不同Android设备的信任列表可能是不同的。
  • 可以是自签名证书,这种证书肯定无法通过默认的验证,需要自己实现验证方法,或者直接配置不验证,信任所有证书。
    注意:信任所有证书是存在极大的安全隐患的,这意味着你的请求也不会被加密,任何人都可以拦截你的请求并伪装成你的服务器与你通信,并记录你的信息比如登录账号和密码等。
  • 可以是由权威机构授权的中间机构颁发的中间证书,这种情况下进行SSL验证时服务器必须返回整个证书链,不能只返回根证书,否则也会验证失败。

深入了解可参考:
http://www.cnblogs.com/P_Chou/archive/2010/12/27/https-ssl-certification.html

其他可能出现的问题

SSL验证时会对证书的有效期进行验证,如果用户设备的时间不在有效期内也会验证失败。如果想忽略有效期,可以使用HttpsUtil中的NotValidateTimeTrustManager类:

private static class NotValidateTimeTrustManager implements X509TrustManager {

        private X509TrustManager defaultTrustManager;

        public NotValidateTimeTrustManager(X509TrustManager defaultTrustManager) {
            this.defaultTrustManager = defaultTrustManager;
        }

        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            defaultTrustManager.checkClientTrusted(chain, authType);
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            try {
                defaultTrustManager.checkServerTrusted(chain, authType);
            } catch (CertificateException e) {
                e.printStackTrace();
                Throwable t = e;
                while (t != null) {
                    if (t instanceof CertificateExpiredException
                            || t instanceof CertificateNotYetValidException)
                        return;
                    t = t.getCause();
                }
                throw e;
            }
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return defaultTrustManager.getAcceptedIssuers();
        }
    }

在checkServerTrusted方法中捕获了CertificateException,并不断向上寻找原因。如果发现是CertificateExpiredException(证书过期)或者CertificateNotYetValidException(证书还未生效)则通过验证,否则继续抛出异常。

使用方法:

private static TrustManager[] prepareTrustManager(InputStream... certificates) {
        ...
            return trustManagerFactory.getTrustManagers();
            // TODO: 2016/11/11 针对有效期异常导致校验失败的情况,目前没有完美的解决方案
//            TrustManager[] keyStoreTrustManagers = trustManagerFactory.getTrustManagers();
//            return getNotValidateTimeTrustManagers((X509TrustManager[]) keyStoreTrustManagers);
        ...
    }

将第一行注释,放开最后两行注释

但要注意,这个方案仍然有一定的安全隐患,因为查看底层进行SSL验证的源码后发现,对证书有效期的校验并不是最后的环节,例如在校验有效期通过后还会校验设备上的吊销证书列表,确认证书是否不在该列表中,其他还有一些自定义校验项。

上述方案在校验有效期异常后就会通过验证,漏掉了剩下的一些校验项,仍然存在一些隐患,如果安全级别要求非常高,并不推荐使用。

更多SSL验证问题可以参考:
https://developer.android.com/training/articles/security-ssl.html#MissingCa

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容