天天看点

关于Android的https通讯安全

前段时间,同事拿着一个代码安全扫描出来的 bug 过来咨询,我一看原来是个 https

通信时数字证书校验的漏洞,一想就明白了大概;其实这种问题早两年就有大规模的暴露,各大厂商app

也纷纷中招,想不到过了这么久天猫客户端里还留有这种坑;然后仔细研究了漏洞所在的代码片段,原来所属的是新浪微博分享 sdk 内部的,因为这个 sdk

是源码引用的,一直没有更新,年久失修,所以也就被扫描出来了。因此给出的解决方案是:

先获取最新的 sdk,看其内部是否已解决,已解决的话升级 sdk 版本即可;

第1步行不通,那就自己写校验逻辑,猫客全局通信基本已经使用 https 通信,参考着再写一遍校验逻辑也不是问题;

后来查了一下网上信息,早在2014年10月份,乌云

平台里就已经暴露过天猫这个漏洞,想必当时一定是忙于双十一忽略了这个问题。

虽然这个问题通过升级 sdk

解决了,但是这个问题纯粹是由于开发者本身疏忽造成的;特别是对于初级开发人员来说,可能为了解决异常,屏蔽了校验逻辑;所以我还是抽空再 review

了一下这个漏洞,整理相关信息。

对于数字证书相关概念、android 里 https 通信代码就不再复述了,直接讲问题。缺少相应的安全校验很容易导致中间人攻击,而漏洞的形式主要有以下3种:

在使用httpsurlconnection发起 https 请求的时候,提供了一个自定义的x509trustmanager,未实现安全校验逻辑,下面片段就是当时新浪微博 sdk 内部的代码片段。如果不提供自定义的x509trustmanager,代码运行起来可能会报异常(原因下文解释),初学者就很容易在不明真相的情况下提供了一个自定义的x509trustmanager,却忘记正确地实现相应的方法。本文重点介绍这种场景的处理方式。

在握手期间,如果 url 的主机名和服务器的标识主机名不匹配,则验证机制可以回调此接口的实现程序来确定是否应该允许此连接。如果回调内实现不恰当,默认接受所有域名,则有安全风险。代码示例。

分而治之,针对不同的漏洞点分别描述,这里就讲的修复方案主要是针对非浏览器app,非浏览器 app 的服务端通信对象比较固定,一般都是自家服务器,可以做很多特定场景的定制化校验。如果是浏览器 app,校验策略就有更通用一些。

自定义x509trustmanager。前面说到,当发起 https 请求时,可能抛起一个异常,以下面这段代码为例(来自官方文档):

它会抛出一个sslhandshakeexception的异常。

android 手机有一套共享证书的机制,如果目标 url 服务器下发的证书不在已信任的证书列表里,或者该证书是自签名的,不是由权威机构颁发,那么会出异常。对于我们这种非浏览器 app 来说,如果提示用户去下载安装证书,可能会显得比较诡异。幸好还可以通过自定义的验证机制让证书通过验证。验证的思路有两种:

不论是权威机构颁发的证书还是自签名的,打包一份到 app 内部,比如存放在 asset 里。通过这份内置的证书初始化一个keystore,然后用这个keystore去引导生成的trustmanager来提供验证,具体代码如下:

这样就可以得到正确的输出内容:

同方案1,打包一份到证书到 app 内部,但不通过keystore去引导生成的trustmanager,而是干脆直接自定义一个trustmanager,自己实现校验逻辑;校验逻辑主要包括:

•服务器证书是否过期

•证书签名是否合法

•自定义hostnameverifier,简单的话就是根据域名进行字符串匹配校验;业务复杂的话,还可以结合配置中心、白名单、黑名单、正则匹配等多级别动态校验;总体来说逻辑还是比较简单的,反正只要正确地实现那个方法。

•主机名验证策略改成严格模式

文/尹star(简书作者)

原文链接:http://www.jianshu.com/p/7c1bc2daef8d

著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

继续阅读