本篇文章已授权微信公众号 guolin_blog(郭霖)独家发布

 

对于Android N之前自定义或非CA证书的使用,一般有两种方式:

1、自定义X509TurstManager和HostnameVerifier,替换原有的HttpsURLConnection中的校验类。自定义方法以烂大街的转载版为主。

2、在手机中安装证书。通过设置列表完成

其实从2016年5月17日起,Google Play内容政策和开发者分发协议第 4.4条的相关规定中就指出将禁止发布X509TrustManager接口实施方式不安全的任何新应用或应用更新。传统的针对X509TurstManager和HostnameVerifier的修改不符合Google商店的发布要求。虽然我们在墙的庇护下,不用去google商店发布,但不可否认它确实是一种安全隐患,很容易遭受中间人攻击(MITM攻击)

因此,在Android N中,google在这证书认证一块调整了原来的校验策略。即默认配置不会信任用户添加的CA证书。同时提供网络安全性配置规范证书的使用。

根据官网的介绍(https://developer.android.google.cn/training/articles/security-config.html#manifest ),我们可以通过设置network_security_config.xml对非CA证书进行适配。

鉴于官网的介绍缺少实例,在这里,我用12306网站的证书作为展示例子。

1、创建一个网络安全性配置network_security_config.xml,用来声明证书校验方式。

文件格式被设定为如下样子:

   <?xml version="1.0" encoding="utf-8"?><network-security-config><base-config>//应用范围的默认配置,只能配置一次。<trust-anchors>//信任锚,就是信任数据源。<certificates src="..."/>//证书。...</trust-anchors></base-config><domain-config>//域名级配置,针对待访问的网站域名,可以存在对多个,同时要考虑子域名,尽可能的将域名罗列详细。<domain>android.com</domain>...<trust-anchors><certificates src="..."/>...</trust-anchors><pin-set>//证书公钥设置,用于证书固定,一般可以不用配置,除非确定证书长期有效。<pin digest="...">...</pin>...</pin-set>...//如果域名之间存在父子关系,可以进行嵌套设置,同时对于证书的使用,可以用includeSubdomains对父域名设置,使证书具有继承属性。</domain-config>...<debug-overrides>//DEBUG调试时采用的信任源,只在DEBUG时起作用。<trust-anchors><certificates src="..."/>...</trust-anchors></debug-overrides></network-security-config>

其中需要关注的是<certificates>,参数共有三种类型:

1、system      设备中预装的系统证书

2、user        用户自装证书

3、resourceID  /raw文件下的证书

官网上指出,Android N的变化实际是对<base-config>的参数做了改动,面向Android 6.0(API级别23)及更低版本的应用的默认配置

     <base-config cleartextTrafficPermitted="true"><trust-anchors><certificates src="system" /><certificates src="user" /></trust-anchors></base-config>

面向 Android 7.0(API级别24)及更高版本应用的默认配置

     <base-config cleartextTrafficPermitted="true"><trust-anchors><certificates src="system" /></trust-anchors></base-config>

也就是说,我们可以通过在应用中增加<certificates src="user" />,即可重新使用手机设备上的自装证书了。这一点该文作者已作出了证明(https://www.kalvin.cn/article/14);也可以通过域名<domain-config>指定证书的使用,但此时的证书只能配置在/raw中()

最终结合12306网站域名特点,network_security_config.xml编辑如下:

        <network-security-config><base-config  cleartextTrafficPermitted="true"><trust-anchors><certificates src="system"/></trust-anchors></base-config><domain-config>//网站域名,利用属性includeSubdomains,将配置的trust-anchors可以向下作用。<domain includeSubdomains="true">www.12306.cn</domain>//自定义信任证书<trust-anchors>//信任的自定义CA证书<certificates src="@raw/srca" overridePins="true"/></trust-anchors> //cleartextTrafficPermitted属性不详,这里是参考官网添加的<domain-config cleartextTrafficPermitted="true">  //子域名<domain includeSubdomains="true">kyfw.12306.cn</domain></domain-config></domain-config></network-security-config>

2、将应用对应的自定义证书放置到/res/raw/中。官网中尤其强调证书的格式,必须是DER或PEM格式编码,12306使用的srca.cer是DER格式编码,符合要求。我没有试过PEM格式的,手里只有P12格式的,转格式后没有成功,干扰因素太多,希望有人试验成功后交流一下。

3、在AndroidManifest.xml的<application>中声明network_security_config.xml

         android:networkSecurityConfig="@xml/network_securiy_config"

4、此时就可以正常访问www.12306.cn了。 综上就是Android N的适配方案,官网给出了方案固然是好事,但是不如例子看起来直观,还需要大家一起摸索啊,关于证书校验的问题,希望和大家一起成长。

附加:

当然,目前Android N的市场占比并不多,针对更多的旧版系统,使用自定义的X509TrustManager更为便捷。但是还是希望大家不要忽略校验,毕竟我们也算做产品的,最起码要对自己的东西负责啊。同时贴出我采用的方法(部分参考了X509TurestManagerImpl),方法如下:

   public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {//参数有效性校验if (chain == null || chain.length == 0 || authType == null || authType.length() == 0) {throw new CertificateException();}//证书有效性校验for(X509Certificate cert : chain){cert.checkValidity();}//证书完整性校验check(chain);}private static final int MIN_MODULUS = 1024;private static final String[] OID_BLACKLIST = {"1.2.840.113549.1.1.4"}; // MD5withRSApublic static final void check(X509Certificate[] chain) throws CertificateException {for (X509Certificate cert : chain) {checkCert(cert);}}private static final void checkCert(X509Certificate cert) throws CertificateException {checkModulusLength(cert);checkNotMD5(cert);}private static final void checkModulusLength(X509Certificate cert) throws CertificateException {Object pubkey = cert.getPublicKey();if (pubkey instanceof RSAPublicKey) {int modulusLength = ((RSAPublicKey) pubkey).getModulus().bitLength();if (!(modulusLength >= MIN_MODULUS)) {throw new CertificateException("Modulus is < 1024 bits");}}}private static final void checkNotMD5(X509Certificate cert) throws CertificateException {String oid = cert.getSigAlgOID();for (String blacklisted : OID_BLACKLIST) {if (oid.equals(blacklisted)) {throw new CertificateException("Signature uses an insecure hash function");}}}//HostnameVerifier可以借用源码HttpsUrlConnection中NoPreloadHolder中默认设置的OKHostnameVerifier进行域名合法性校验。public boolean verify(String host, SSLSession session) {HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();return hv.verify(host, session);}

学徒浅析Android——Android7.0(N)对于自定义证书和非CA机构证书的适配校验相关推荐

  1. 学徒浅析Android——Android原生下载机制针对0K大小文件下载异常的分析

    本篇文章已授权微信公众号 guolin_blog(郭霖)独家发布 最近在进行一次测试用例中,发现测试手机在利用本地下载功能下载0K大小的文件时,进度条一直处于进度模糊状态中,虽然查看本地存储路径,发现 ...

  2. 浅析Android 4.0的通知系统(附Android 4.0设计指南全文翻译)

    通过手机的通知系统,可以将应用程序的一些重要消息告知给用户.流畅.舒适.友好的应用程序离不开精心设计的消息提醒机制.但是并不是所有的通知都是用户想看的,否则只会给用户造成骚扰,所以要谨慎使用通知. 在 ...

  3. android屏幕适配的五种方式_讲一讲Android 9.0系统的新特性,对刘海屏设备进行适配...

    黑客技术点击右侧关注,了解黑客的世界! Java开发进阶点击右侧关注,掌握进阶之路! Python开发点击右侧关注,探讨技术话题!作者丨郭霖来源丨郭霖(guolin_blog) 其实Android 9 ...

  4. 学徒浅析Android开发:第三讲——Dialog的常用方法介绍(二)

    经过(一)的基础介绍,现在小编将在(二)中给大家介绍以下几种效果: 1.点击查看组图(模拟QQ空间图片浏览) 2.缩略图放大(自定义Dialog) 3.动态加载进度条 一.点击产看组图(模拟QQ空间图 ...

  5. 学徒浅析Android——Role带来的角色扮演

    在Q以前,如果我们的应用是一个短信或拨号之类的特殊应用,想要通知用户将我们的应用替换掉手机自带的预搭载应用,TelecomManager.ACTION_CHANGE_DEFAULT_DIALER和Te ...

  6. Android 10.0 手势导航自定义左右手势滑动返回样式UI布局

    目录 1.概述 2.自定义左右手势返回UI样式的核心代码 3.自定义左右手势返回UI样式的核心代码功能分析

  7. Android 7.0 Nougat(牛轧糖)---对开发者来说

    Android 7.0出来了.让你的app准备迎接最新的android版本吧,支持节省电量和内存,这样新的系统行为.使用多窗口UI.直接恢复通知以及其他操作来扩展你的app. android 7.0介 ...

  8. nfc android 7.0 apk,分屏/NFC一卡通 一加3安卓7.0氢OS体验

    [IT168 评测]谷歌在今年的8月份推出了全新的Android 7.0系统,各家手机厂商也抓紧了时间进行适配.作为一个较为少见的刷机也保修的手机厂商--一加,上周放出了适用于一加手机3的第六版公测系 ...

  9. Android 12.0 rom定制专栏系列解读

    一.前言 在从事android系统rom定制化的这几年里,经历了坎坎坷坷,开发过好几种类型的产品,也随着google对android系统的更新加快,也需要跟随上时代的进步,所以需要把平时工作中遇到的问 ...

最新文章

  1. abap中取内表中每一类中的一行的方法
  2. c++中实现域内,左,右对齐的方法
  3. 搞IT的技术人员为什么会如此苦逼
  4. project开发的程序设计与逻辑设计
  5. 操作系统(王道笔记第三章内存)
  6. python simdjson_python+json
  7. android日记本实训报告,实训笔记
  8. 机器人防火墙出击 提升在线业务的安全未来
  9. 算法(algorithm):#include<algorithm>
  10. 怎么检查计算机网络是连接,电脑怎么查看网络连接
  11. JavaScript 关灯游戏
  12. android开发实现微博正文效果、顶部悬浮、ScrollView嵌套ListView
  13. html5积分墙联盟,积分墙是一种革新的移动广告联盟
  14. 解决 SSL握手失败问题
  15. Android投屏神器scrcpy
  16. Unity中的存档与读档
  17. HBuilderX 开发工具
  18. CPU、内存、磁盘三者的关系
  19. 华云数据加入上海信息技术应用创新联盟!
  20. Linux性能观测——dstat命令详解

热门文章

  1. js 获得明天0点时间戳_开群通知!昨日提示厦门信达、申通地铁、国林科技、隆盛科技全部涨停!明天这只龙头股有望继续涨停!...
  2. Python | 凸多边形间重叠面积计算
  3. ffmpeg命令行视频剪辑与拼接
  4. STM32F10xxx20xxx21xxxL1xxxx Cortex-M3程序设计手册 阅读笔记二(1):Cortex-M3处理器程序模型
  5. JSF是什么?JSF的优点
  6. Python之建模规划篇--线性规划
  7. 什么是堡垒机?堡垒机有何优势?
  8. 数据结构实验6_压缩矩阵的转置、普通转置、快速转置算法
  9. Sort sort =new Sort(Sort.Direction.ASC,“id“)
  10. CAD图纸导入REVIT内并精准建模