天天看点

Android App 安全的HTTPS 通信

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

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

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

信任所有主机名。

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

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

它会抛出一个<code>sslhandshakeexception</code>的异常。

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

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

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

如果你用上述同样的代码访问 https://www.taobao.com/ 或者 https://www.baidu.com/ ,则会抛出那个<code>sslhandshakeexception</code>异常,也就是说对于特定证书生成的<code>trustmanager</code>,只能验证与特定服务器建立安全链接,这样就提高了安全性。如之前提到的,对于非浏览器 app 来说,这是可以接受的。

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

服务器证书是否过期

证书签名是否合法

同样上述代码只能访问 certs.cac.washington.edu 相关域名地址,如果访问 https://www.taobao.com/ 或者 https://www.baidu.com/ ,则会在<code>cert.verify(((x509certificate) ca).getpublickey());</code>处抛异常,导致连接失败。

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

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

<a href="http://security.tencent.com/index.php/blog/msg/41">窃听风暴: android平台https嗅探劫持漏洞</a>

<a href="http://drops.wooyun.org/tips/3296">android证书信任问题与大表哥</a>

<a href="http://jaq.alibaba.com/blog.htm?id=60">android https中间人劫持漏洞浅析</a>

<a href="http://drops.wooyun.org/tips/2775">数字证书及其在安全测试中的应用</a>

<a href="http://www.wooyun.org/bugs/wooyun-2014-080117">wooyun-2014-080117</a>

<a href="http://www.wooyun.org/bugs/wooyun-2014-079358">wooyun-2014-79358</a>

<a href="http://www.pianyissl.com/support/lists/1">ssl证书百科</a>

<a href="http://developer.android.com/intl/zh-cn/training/articles/security-ssl.html#commonhostnameprobs">security with https and ssl</a>

<a href="http://www.oschina.net/translate/android-security-implementation-of-self-signed-ssl">为你的安卓应用实现自签名的 ssl 证书</a>

<a href="http://frank-zhu.github.io/android/2014/12/26/android-https-ssl/">android https ssl双向验证</a>

<a href="https://www.securecoding.cert.org/confluence/pages/viewpage.action?pageid=134807561">drd19. properly verify server certificate on ssl/tls</a>