众所周知,HTTP 协议通过明文传输,是不安全的。于是,就在 HTTP 协议的基础上,进行了数据加密,也就诞生了 HTTPS 协议。注意,HTTPS 并不是一个新的协议,它只不过是在 HTTP 的基础上加了一层 TLS ( Transport Layer Security )
TLS是传输层加密协议,前身是SSL ( Secure Sockets Layer 翻译为安全套接层)。由网景公司于1995年发布。后改名为TLS
随着公众对数据安全性越来越重视,HTTPS 逐渐成为主流,现在还在使用 HTTP 的网站,在谷歌浏览器地址栏前会有 “不安全” 字样的提示。作为开发者,我们理应对 HTTPS 加密的原理有所了解。
HTTPS 的加密流程
概括来说,HTTPS 中的数据是通过对称加密的方式来加密的,而对称加密的密钥是由客户端生成的随机字符串来充当,再通过非对称加密的方式加密后传递到服务端。接下来是详细的流程。这里,我们参考建立 tcp 连接中的三次握手的概念,在 https 加密过程中,服务端与客户端也有三次握手
第一次握手(服务端发送公钥到客户端)
服务端将公钥以证书的形式发送给客户端,证书内包含服务器端的公钥,证书颁发机构,证书有效期,服务端域名等信息。
第二次握手(客户端对证书进行校验并且向服务端发送对称密钥)
客户端收到证书后,会选择是否信任证书,这里是否信任可以根据域名,颁发机构,有效期等信息来判断,如果证书校验不通过,就给予风险提示并断开连接;如果校验通过,就生成一个随机数,用作对称加密的密钥,并取出证书中的公钥,用该公钥对随机数进行加密,将加密后的结果发送到服务端。
第三次握手(服务端用收到的对称密钥加密一段握手信息,发送到客户端)
服务端收到客户端发来的密钥,先用自己的私钥解密,解密成功后,用该对称密钥发送一段握手信息到客户端。客户端收到后,解密成功,至此,HTTPS 连接成功,后续的数据传输就会使用该对称密钥来进行加密。
以上就是 HTTPS 加密的大概的流程,接下来是一些细节上的问题。
HTTPS 是怎样防止中间人攻击的
我们知道,在第一次握手的过程中,中间人完全可以截获服务端发送给客户端的公钥,并且将自己的公钥发送给客户端。客户端用中间人的公钥加密对称密钥,再将结果发送给服务端,中间人再次截获,用自己的私钥解密,获取密钥,再用服务端的公钥加密后发送给服务端。这样,中间人分别冒出服务端和客户端跟彼此交互,就可以窃取信息了。
解决方案
以上中间人攻击成功的主要原因,是客户端无法识别公钥的来源是否来自真正的服务端。这里的解决方案就是数字证书。
- 服务端通过向 CA 等被信任的机构申请获取 CA 私钥,并对服务端公钥等信息通过 hash 算法生成消息摘要,用 CA 私钥对该消息摘要加密,生成签名,将该签名封装到证书中一起发送到客户端;
- 客户端收到证书后,用 CA 公钥对签名进行解密,再对服务端公钥等信息生成消息摘要,并将其与解密的结果进行比对,如果一致,就证明服务端的公钥来源正确
这里用到的 CA 私钥是服务端向 CA 机构申请来的,而 CA 公钥是客户端系统内置的。所以,从这里可以看出,如果使用 CA 认证的证书,系统会自动信任服务端公钥来源;如果使用自签名的证书,就需要客户端提前内置该自签名的证书,当收到服务端发来的证书时,需要与自己内置的证书进行比对,无误后才可以信任,否则会有被中间人攻击的风险。
在 Android 端,校验证书的方式可以参考
如果考虑到一种极端情况,中间人所用的证书也是向 CA 机构申请的,那么处理方式就和自签名证书一样,将服务端的证书提前放在本地,建立 HTTPS 连接的时候,将服务器发送来的证书与本地的证书进行严格比对。
总结
以上就是 HTTPS 加密的大致流程,它在一定程度上解决了 HTTP 协议明文传输的痛点,但是我们得清楚,世界上并不存在完全安全的系统,尽管 HTTPS 的加密机制的设计已经足够精妙了,但它也并不是无懈可击的。在 Android 端,我们可以使用 Xposed 或者其他 hook 框架对校验证书的方法进行 hook,使其在任何情况下都校验通过,这样就绕过了证书校验的过程。
加密与破解的过程本来就是魔高一尺,道高一丈的过程,再精妙绝伦的加密算法也不是无懈可击的,但这并不能否定加密的意义。就像再安全坚固的防盗门也会被撬开,但这并不能说防盗门的存在就没有意义。安全机制的演进就是不断提高破解成本的过程,当破解成本大于破解后的收益的时候,那就是安全的。