当你测试 App 的时候,想要通过 Fiddler/Charles 等工具抓包看下 https 请求的数据情况,发现大部分的 App 都提示网络异常/无数据等等信息。以“贝壳找房”为例:
App 抓包提示网络异常,破解SSL Pinning - 图1
410 x 635455 x 705
Fiddler 中看到的请求是这样的:
App 抓包提示网络异常,破解SSL Pinning - 图2
619 x 215
你可能开始找证书的问题:是不是 Fiddler/Charles 的证书没有导入的手机中去?配置一遍又一遍,又开始对比 Web 端浏览器的 https 发现没问题。这时候你可能已经不知所措了。

那么究竟是不是证书的问题?

没错,就是证书的问题,但跟你想象中的证书有点不同,不是 Fiddler 内置证书的问题,而是 App 内置证书的问题 — SSL Pinning 机制(也可称为证书绑定)

什么是 SSL Pinning?

首先,在 https 的建立连接过程中,当浏览器向服务端发送了连接请求后,服务器会发送自己的证书(包括证书有效期、颁发机构等)给浏览器,浏览器首先在本地根证书区域寻找是否有这个服务器证书的 CA 机构的根证书。如果有继续则下一步会进行验证服务器端的证书,如果没有弹出警告。验证通过后经过一系列服务器和客户端的信息交换,双方最终建立了通讯。

那么为什么 Fiddler 能够抓得到浏览器的 https 请求呢?

原因就是在浏览器面前 Fiddler 伪装成一个 https 服务器,用户可以自由的将 Fiddler 的伪装证书导入到浏览器内置的根证书中。此时 Fiddler 作为中间人在真正的服务器面前伪装成浏览器的角色。
App 抓包提示网络异常,破解SSL Pinning - 图3
728 x 3021151 x 477
明白上述一点之后,我们再回到 App 客户端,App 默认是信任系统(Android or iOS)用户第三方安装的的 CA 证书的,有一些 App 能够通过 Fiddler 抓到包的原因是因为:我们可以在系统的用户 CA 证书集中添加 Fiddler 的证书。这样 App 就能信任证书是安全的,放心的发送请求了。
App 抓包提示网络异常,破解SSL Pinning - 图4
474 x 226
但是现在随着系统的更新,Google or Apple 认识到安全越来越重要,所以就引入 SSL-Pinning 技术:
开发者预先把证书相关信息预置到 App 中再打包,这样在 https 通讯过程中 App 本地可以与服务器返回的证书可以做合法性校验,如果发现不一致,那么可能就是由于中间人攻击(比如 Fiddler/Charles 抓包工具),App 客户端可以终止 https 链接。而在新版本的系统规则中,应用只信任系统默认预置的 CA 证书,如果是第三方安装的证书(比如 Fiddler 安装的)则不会信任:
App 抓包提示网络异常,破解SSL Pinning - 图5
480 x 285

解决方案

上面的都是一些理论方面的内容,到底该如何突破 SSL Pinning 机制能够抓到 App 的 https 请求包呢?

方案一:使用 Android7.0 以下的系统

目前已验证在 Android 7.0 或以上的系统有启用了对第三方证书的限制。但是在 Android 7.0 以下还是依旧可以将 Fiddler/Charles 的证书安装在用户的 CA 集中抓取 https 请求。

方案二:将 Fiddler/Charles 证书安装到系统默认预置的 CA 证书区域中

此种办法前提是需要 root 权限,但是现在很多新款手机获取 root 权限困难,所以此办法并不推荐。

方案三:反编译 APK,修改 AndroidManifest.xml 文件

  • 有些 APK 加了壳,需要先进行脱壳处理
  • 再通过 apktool 等工具进行反编译
  • 在源码的 res/xml 目录添加 network_security_config.xml 文件,内容如下:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <network-security-config>
  3. <base-config cleartextTrafficPermitted="true">
  4. <trust-anchors>
  5. <!-- 信任系统预置CA 证书 -->
  6. <certificates src="system" />
  7. <!-- 信任用户添加的 CA 证书,Charles 和 Fiddler 抓包工具安装的证书属于此类 -->
  8. <certificates src="user" />
  9. </trust-anchors>
  10. </base-config>
  11. </network-security-config>
  • 修改 AndroidManifest.xml 文件,在 application 标签中增加 android:networkSecurityConfig=”@xml/network_security_config”
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest ... >
  3. <application android:networkSecurityConfig="@xml/network_security_config"
  4. ... >
  5. ...
  6. </application>
  7. </manifest>

此种方案比较适用于对反编译比较熟练的童靴

方案四:VitualXposed 框架 +JustTrustMe 模块(推荐)

VitualXposed 介绍:

Use Xposed with a simple APP, without needing to root, unlock the bootloader, or flash a system image

官网下载地址:https://vxposed.com/
简单来说,VitualXposed 可以在不需要设备 root 的情况下,修改 App 的行为。此应用的工作原理类似于应用分身功能,会将应用安装到一个虚拟独立的环境当中,其内部会自带一个已经激活了的 Xposed 工具。
JustTrustMe 介绍:

An xposed module that disables SSL certificate checking for the purposes of auditing an app with cert pinning

JustTrustMe 是 GitHub 上面的一个开源项目,是 xposed 中的一个模块,用于禁止 SSL 证书验证。
https://github.com/Fuzion24/JustTrustMe

操作流程:
  • 将 VitualXposed 安装到真机中,点击应用按钮-> 添加应用,将要调试的 App、JustTrustMe.apk 进行安装
    App 抓包提示网络异常,破解SSL Pinning - 图6516 x 417

  • 打开 Xposed,选择左上角导航栏-> 模块,勾选 JustTrustMe
    App 抓包提示网络异常,破解SSL Pinning - 图7455 x 207

  • 重启 VitualXposed 应用,打开贝壳找房,通过 Fiddler 抓包,可以看到 App 请求正常,https 请求能抓到
    App 抓包提示网络异常,破解SSL Pinning - 图8669 x 206
    App 抓包提示网络异常,破解SSL Pinning - 图9