魏名华

不要偷懒,做更好的自己

Nothing


No Welcome Message

HTTPS证书验证

南峰子_老驴 1月18日 08:21 来自 微话题-ios知识小… #iOS知识小集# by @康祖彬 我们对使用 Charles 进行 HTTP 抓包调试已经非常熟悉了,下面分享一下如何进行 HTTPS 抓包。

(1) 在 Mac/Windows 上下载安装 Charles 后并打开,点击 Start Recording 按钮,这时该电脑在其所在局域网内就可以作为一台代理服务器;

(2) 把 iPhone 与上述电脑连接到同一个局域网(WiFi),并把 iPhone 所连的 WiFi 的代理设为上述电脑的 IP,以及代理端口设为:8888,如图1;

(3) 在 iPhone 里打开 Safari 访问 chls.pro/ssl 安装 Charles 提供的一个 Root CA 证书到系统本地可信任 CA 列表中,如图2,这时由该 Root CA 证书颁发的用户证书都将是可信任的!

(4) 在 Charles 中给指定的域名颁发证书:Proxy -> SSL Proxying Setting,勾选 Enable SSL Proxying,点击 Add 添加你要抓的 HTTPS 包的域名,如图3;

(5) 此时在 iPhone 上发的 HTTPS 的请求和响应内容基本都可以看到了。

这是一种非常典型的中间人攻击的例子,那么我们如何避免 App 的 HTTPS 请求被监听呢?

SSL Pinning:在客户端本地钉一个服务端的证书,在 SSL 握手阶段除了校验服务端返回的证书的有效性和合法性之外,还对服务端证书内容与本地的进行比对,只有相同才通过校验!如图4。

另外 HTTPS 双向验证(除了客户端验服务端身份,服务端也要验证客户端的身份,例如银行 U 盾,支付宝/微信的个人数字证书等)也可以有效避免中间人攻击。

南峰子_老驴 1月20日 09:02 来自 微博 weibo.com //@康祖彬: 另一种更新方案:用 domain2.com 域名的 HTTPS 接口给 domain1.com 域名更新证书,同时反过来用 domain1.com 的 HTTPS 接口给 domain2.com 更新证书,(当然对于 domain1.com 和 domain2.com 的 HTTPS 请求客户端都是做了 SSL Pinning 的),保证这两个域名的证书不是同一时间到期的就行。

@南峰子_老驴 #iOS知识小集# 上一个小集中我们讲到对 HTTPS 请求做 SSL Pinning,即在客户端本地钉一个服务端的证书,在 SSL 握手阶段除了校验证书的有效性和合法性之外,还对服务端返回证书内容与本地的进行比对,只有相同才通过校验,这样可以阻止中间人攻击,以及避免数据被抓包监听。

但做 SSL Pinning 存在一个问题是,钉在客户端本地的证书也是有有效期的,它过期了怎么办?(服务端虽然可以随时更换新证书,但是其更换新证书后旧版本的客户端用老证书是对比校验不过的。)

有一种解决方法是,证书过期前,发版让用户强制升级,这显然是很不友好的!因此我们需要设计一种证书在线更新机制。

假设要更新证书的域名为(domain1.com),可以使用另一个域名(domain2.com)的 HTTPS 接口来更新本域名(domain1.com)的证书,但如果本地不 Pinning 这个域名(domain2.com)的证书,则这个更新证书接口存在被中间人攻击的风险;如果要做 Pinning,那么这个接口的证书也过期了又怎么办?

我们可以 HTTP 接口来解决问题,又同时保证安全,如图所示: (1)服务端计算出新证书文件的 MD5 值,作为这个文件的数字签名; (2)服务端通过 RSA 私钥加密第(1)步算出的 MD5 值,得到一个加密后的 MD5 值; (3)服务端把新证书文件和加密后的 MD5 值通过 HTTP 接口一起下发给客户端; (4)客户端拿到加密后的 MD5 值,通过事先保存在客户端的 RSA 公钥解密; (5)客户端计算接收到的证书文件的 MD5 值; (6)对比第(4)、(5)步的两个 MD5 值,若相等则通过校验。

只要通过校验,就能确保新证书文件在传输的过程中没有被篡改,因为第三方若要篡改证书文件,必须计算出新的证书文件 MD5 并用私钥加密,客户端公钥才能解密出这个 MD5 值,而在服务端未泄露的情况下第三方是拿不到私钥的。

另外,证书本身也是要公开的,所以不必加密,这里只要保证它没被篡改就行了。

这与 JSPatch 下发脚本的策略基本一致。

以上简要介绍了更新证书实现的步骤,需要服务端配合,以后我们再详细讲一下具体如何实现。