在理解抓包HTTPS的原理之前,需要先对HTTPS的原理有一定的理解。
1.HTTPS 简介
HTTPS全称:Hyper Text Transfer Protocol over SecureSocket Layer
,基于SSL的超文本传输协议, HTTPS协议 = HTTP协议 + SSL/TLS协议,在HTTPS数据传输的过程中,需要用SSL/TLS对数据进行加密和解密,然后需要用HTTP对加密后的数据进行传输,由此可以看出HTTPS是由HTTP和SSL/TLS一起合作完成的。
HTTPS的实质:HTTPS为了兼顾安全与效率,同时使用了 对称加密 和 非对称加密。数据是被对称加密传输的,对称加密过程需要客户端的一个密钥,为了确保能把该密钥安全传输到服务器端,采用非对称加密对该密钥进行加密传输。
传输秘钥的SSL协议的握手过程如下:
(1) 客户端发出请求(ClientHello)
首先,客户端(通常是浏览器)先向服务器发出加密通信的请求,这被叫做ClientHello请求。在这一步,客户端主要向服务器提供以下信息。
- 支持的协议版本,比如TLS 1.0版。
- 一个客户端生成的随机数,稍后用于生成"对话密钥"。
- 支持的加密方法。
- 支持的压缩方法。
(2) 服务器回应(SeverHello)
服务器收到客户端请求后,向客户端发出回应,这叫做SeverHello。服务器的回应包含以下内容。
- 确认使用的加密通信协议版本,比如TLS 1.0版本。如果浏览器与服务器支持的版本不一致,服务器关闭加密通信。
- 一个服务器生成的随机数,稍后用于生成"对话密钥"。
- 确认使用的加密方法。
- 服务器证书。
(3) 客户端回应
客户端收到服务器回应以后,首先验证服务器证书。如果证书不是可信机构颁布、或者证书中的域名与实际域名不一致、或者证书已经过期,就会向访问者显示一个警告,由其选择是否还要继续通信。
如果证书没有问题,客户端就会从证书中取出服务器的公钥。然后,向服务器发送下面三项信息。
- 一个随机数。该随机数用服务器公钥加密,防止被窃听。
- 编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送。
- 客户端握手结束通知,表示客户端的握手阶段已经结束。这一项同时也是前面发送的所有内容的hash值,用来供服务器校验。
上面第一项的随机数,是整个握手阶段出现的第三个随机数,又称"pre-master key"
。有了它以后,客户端和服务器就同时有了三个随机数,接着双方就用事先商定的加密方法,各自生成本次会话所用的同一把"会话密钥"。
(4) 服务器的最后回应
服务器收到客户端的第三个随机数pre-master key
之后,计算生成本次会话所用的"会话密钥"。然后,向客户端最后发送下面信息。
- 编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送。
- 服务器握手结束通知,表示服务器的握手阶段已经结束。
至此,整个握手阶段全部结束。接下来,客户端与服务器进入加密通信,就完全是使用普通的HTTP协议,只不过用"会话密钥"加密内容。
2.抓包工具抓取HTTPS原理
以上就是HTTPS的实现过程,在理解了Https的实现后,就很容易理解抓包的实现原理,下图就是实现抓包的过程:
HTTPS抓包的原理还是挺简单的,简单来说,就是Charles作为“中间人代理”,拿到了 服务器证书公钥 和 HTTPS连接的对称密钥,前提是客户端选择信任并安装Charles的CA证书,否则客户端就会“报警”并中止连接。这样看来,HTTPS还是很安全的。
提醒大家,除非你确实有非常明确的需求,否则千万不要在自己的手机或电脑上安装来路不明的证书,不然你的数据安全性可能就会面临非常大的威胁。
2.Android网络安全的现状
Http
因为没有加密,属于明文传输,是可以抓包的。
但是从 Android 9.0
开始,默认是禁止 App 使用 Http 这种使用所有未加密的连接,使用 Http 会导致程序报错。
Https
Https 是一种使用了加密传输的协议,防止了 App 和 服务器之间的中间人进来拦截、伪造、篡改问题。
但是如果是手机持有人,主动在手机里安装 charles 的根证书,实现了认证环节,是可以实现抓包的。
然而 Android 也发现了这种漏洞,为了保护应用开发公司的通讯安全,在 Android 7.0
以后,只信任 Android 设备的 系统根证书。也就是如果你安装的 charles 根证书这类属于 用户证书 分类的证书,Android 系统是不认的,照样不让 Https 请求正常通过。
3.抓Android App的 Https 包
如果第三方只是使用默认的 Android Https 配置,那么可以使用这两种方法可以抓到它们的请求包。
(1) 使用 Android7.0 以下的手机安装应用,然后抓包
很好理解,上面讲过了只有 Android 7.0
以后,才开始不信任用户根证书。
(2) 想办法把 你的 charles 证书或者其他证书,变成设备的根证书
比如你是手机设备厂家,或者你可以编辑一套ROM出来,当然可以把任何个人证书给搞成是系统证书。另一种方法是,需要一部有Root权限的手机,安装 Xposed 的 JustTrustMe 模块来信任所有的证书。
4.怎么防止被抓包(各端通用)
各端通用 的意思就是,不管是前端还是后端、App还是Web,防止抓包的原理是一样的,毕竟Https的实现逻辑是统一的。
客户端对证书的处理往往有三种情况(https):
- 情况1,客户端不存在证书校验,服务器也不存在证书校验。
- 情况2,客户端存在校验服务端证书,服务器也不存在证书校验,单项校验。
- 情况3、客户端存在证书校验,服务器也存在证书校验,双向校验。
情况1:客户端与服务端都没有存在证书校验:
设置代理,伪造证书,即可成功抓取数据包
情况2:存在检测服务器端证书(SSL pinning):
SSL pinning:是一种防止中间人攻击的技术,主要机制是在客户端发起请求->收到服务器发来的证书进行校验,如果收到的证书不被客户端信任,就直接断开连接不继续请求。可以发现中间人攻击的要点的伪造了一个假的服务端证书给了客户端,客户端误以为真。解决思路就是,客户端也预置一份服务端的证书,比较一下就知道真假了。
SSL-pinning有两种方式:证书锁定(Certificate Pinning) 和 公钥锁定( Public Key Pinning)
证书锁定:
需要在客户端代码内置仅接受指定域名的证书,而不接受操作系统或浏览器内置的CA根证书对应的任何证书,通过这种授权方式,保障了APP与服务端通信的唯一性和安全性,因此客户端与服务端之间的通信是可以保证绝对安全。但是CA签发证书都存在有效期问题,缺点是在证书续期后需要将证书重新内置到APP中。
Android中可以使用系统配置支持的证书,或者使用类似OkHttp等库中提供的api 来验证证书是否正确。
公钥锁定:
提取证书中的公钥并内置到客户端中,通过与服务器对比公钥值来验证连接的正确性。制作证书密钥时,公钥在证书的续期前后都可以保持不变(即密钥对不变) ,所以可以避免证书有效期问题,一般推荐这种做法。
情况3:双向认证
当服务器启用了证书双向认证之后,除了客户端去验证服务器端的证书外,服务器也同时需要验证客户端的证书,也就是会要求客户端提供自己的证书,如果没有通过验证,则会拒绝连接,如果通过验证,服务器获得用户的公钥。
因为双向认证需要服务器和客户端提供身份认证,只能是服务器允许的客户方能访问,安全性相对于高一些。所以需要做双向认证的SSL证书多数是企业,尤其是像金融行业等对安全性要求较高的企业。一般Web应用都是采用SSL单向认证的,用户数自由无限制。
单向认证是客户端验证服务器端证书身份的过程,双向认证是在单项认证基础上服务端还需要验证客户端提供的证书真实性,比如网银U盾登录。