一直困扰于HTTP和HTTPS的区别,现在专门找一个时间来抓住痛点,解决掉该麻烦。
1. HTTP + 加密 + 认证 + 完整性保护 = HTTPS
我们知道HTTP是明文传输的,就必不可免存在如下问题:
- 重要数据被明文获取
- 通信双方可能被伪冒
- 数据被篡改
一般获取简单数据用于展示的,可能无所谓以上的安全缺陷。但假如涉及类似银行密码的数据,就必须慎重考虑这一点了。
所以能够规避以上缺陷的HTTP就是HTTPS(HTTP Secure)。
1.1 如何做到加密 + 认证 + 完整性保护
我们都知道OSI7层模型,其中HTTP属于应用层协议,HTTP下一层是TCP(传输层协议)。完全性是一个难题,专注于传输速率的传输层协议TCP为了单一职责的理念,自是不会多管闲事去保证安全性而降低自身的传输速率的。
HTTP本身假如要去保证部分数据的安全性而去专注安全性的开发,也是得不偿失。想到这里,很是有一些学java感受到的职责单一、职责分离这样的思想,哈哈。所以应该就是这样,HTTP与TCP之间再加上一层SSL/TLS(Secure Sockets Layer/Transport Layer Security)协议。
这样就算是明白HTTP、HTTPS的区别了吗?怎么可能呢?不去搞懂为啥就能安全了、为啥是SSL/TLS这两个什么东西、为啥用TLS而不是SSL?不搞明白这些问题,怎么能安心呢?
2. SSL/TLS是什么
上一小节讲到,SSL/TLS是HTTP和TCP之间的中转协议。如图,可知SSL/TLS也是一个应用层的协议。
那么我们可以把SSL/TLS当作一个黑盒子,就像TCP、HTTP,我们知道数据先丢给HTTP,HTTP丢给SSL/TLS加密,然后SSL/TLS丢给TCP传输...诸如此类,其中具体细节,暂先不表。
3. SSL和TLS的区别与历史
Android 8.0禁用了SSL,所以我们一定非常好奇二者之间的区别,为什么会有两种协议,而且总是并列提起。
SSL是TLS的前身,SSL从1.0、2.0到3.0一步步修订,但安全性都不是非常完美。知道后来SSL3.0摇身一变变成TLS1.0,发展至今已经达到TLS1.2的稳定版本。另外18年今年,TLS1.3的草案也已经提出,在不断开发中吧
- SSL 1.0,未发布公开,因为严重的安全性漏洞
-
SSL 2.0,1995.02,包含一些需要在SSL3.0解决的安全漏洞
SSL 2.0 在2011年被RFC 6176禁止 -
SSL 3.0,1996,代表着该协议的完整重新设计,
SSL 3.0也在后来June 2015被RFC 7568禁止. - TLS 1.0 在January 1999首次在RFC 2246中定义,作为SSL 3.0的升级版本
- TLS 1.1April 2006在RFC 4346 中定义
- TLS 1.2August 2008 在 RFC 5246定义,基于TLS 1.1进行升级
所有TLS版本在2011年3月rfc 6176中进一步完善,取消了它们对SSL的向下兼容,TLS再也不支持安全套接字层(SSL)2.0版。
TLS各个版本的更新情况可以看这里 - 维基百科
所以日常提起总是SSL/TLS,TLS是后来的所以放在后面。而维基百科是TLS/SSL,考虑的应该是TLS现在是主流吧。我们现在差不多也可以说成是TLS了,毕竟SSL已经被禁用了。
以下有几张图,可以比较直观地说明,为什么用TLS,TLS相对于SSL有哪些优势:
最后这一张太大了,截不完整,只能管中窥豹了。在此仅仅截下Android部分,毕竟是学习Android的。小伙伴们感兴趣自己到维基百科查看。
4. TLS/SSL工作机制
4.1 加密方法
共享密钥方式加密 = 对称加密 = 处理速度较快
公开密钥方式加密 = 非对称加密 = 更复杂,处理速度较慢
共享密钥方式加密只要密钥ok就足够安全,服务器只要把密钥交给客户端,然后通信过程中和客户端使用同一把密钥进行加密解密即可。毕竟是HTTP通信过程肯定是需要速度尽量快才是最好。
Q1:但是共享密钥如何安全地递交给对方?比如服务端如何把共享密钥安全交给客户端?
这时候就需要使用公开密钥方式加密。想用密文和公钥恢复到信息原文是异常困难的,相当于对离散对数进行求值,这不是轻而易举能达到的。(还是没有一个很好的概念,总之这很安全就对了)
发送方使用接收方的公钥对数据进行加密,然后接收方收到密文后使用密钥对数据进行解密。
接上一个问题:通信双方持有对方的公钥,发送共享密钥时使用公钥加密,就不怕共享密钥被获取了。
Q2:公钥毕竟是要发放出去的,如何证明发给客户端的过程中,公钥没有被替换掉呢?假如公钥被替换掉,伪冒者就可以假装成服务端和用户进行通信。
接下来就是数字证书认证机构出场。
HTTPS中,服务端将公钥发给数字证书认证机构进行安全认证并对公钥进行数字签名,完成后公钥和签名组合成数字证书。在和客户端通信时,服务端将数字证书发给客户端,客户端通过第三方安全认证机构发布的公钥(一般会在浏览器开发时,内置在浏览器中)对数字证书上的签名进行验证,假如验证通过,则能证明以下事实:
- 认证该服务器的公钥的机构是真实有效的数字证书认证机构
- 该服务器发过来的公钥是值得信赖的
因为通信双方都需要证明自己发出的公钥真实可靠,所以也就存在两种目的性不同的数字证书:可证明组织真实性的EV SSL证书、用以确认客户端的客户端证书
4.2 工作流程
TCP需要三次握手四次挥手,TLS/SSL也需要握手。
以上这些ClientHello都是报文的名称,一个箭头表示一次报文发送。
- ClientHello:包含支持的TLS最高版本、随机数、加密组件(cipher suites)列表、支持的压缩方法
- ServerHello:根据ClientHello选择的TLS版本号、加密组件、压缩方法,以及随机数。假如连接需要从异常关闭中恢复,还会发送一个Session id。
- Certificate:包含公钥证书。(该次报文也可能不发送,取决于加密组件的选择)
- ServerKeyExchange:取决于加密组件,所有DHE 和 DH_anon 加密组件都会发送该报文。但google已经弃用DHE加密组件了,所以该报文在《图解HTTP》一书中甚至没有提及。
- ServerHelloDone:通知客户端,最初阶段的握手协商完成了。
- ClientKeyExchange:可能包含称为PreMasterSecret的随机密码串、公钥或者啥都不包含(取决于使用的加密组件),其中PreMasterSecret会使用Certificate报文中的数字证书中的公钥进行加密。
- The client and server then use the random numbers and PreMasterSecret to compute a common secret, called the "master secret". All other key data for this connection is derived from this master secret (and the client- and server-generated random values), which is passed through a carefully designed pseudorandom function.
粗劣翻译:客户端和服务器使用随机数和PreMasterSecret,通过精心设计的伪随机函数来计算出一个共同的密钥,称为“master secret”。当前连接的所有其他密钥公钥数据都需由master secret(以及客户端和服务器生成的随机值)派生。
- ChangeCipherSpec:告诉服务端,从现在起所有我发的信息都会经过认证了!
- Finished:该报文起就已经是加密认证过的报文了,其中包含了握手至今全部报文的整体散列值hash和MAC(Message Authentication Code)。服务端会试图解密该报文并验证hash和MAC。如果验证失败,这次握手就失败了,关闭。
- ChangeCipherSpec:告诉客户端,从现在起所有我发的信息都会经过认证了!
- Finished:客户端同样去解密该报文并校验。解密校验失败,一样会关闭握手。
- HTTP request/response:接下来就可以进行HTTP的请求了。
- close_notify:最后由客户端通知服务端进行关闭,发送close_notify报文。当然此时关闭的是TLS连接,继续下一层TCP的四次挥手依旧会进行。
还有一个Client-authenticated TLS handshake,翻译过来差不多是客户端认证的握手流程,和基本流程差不大,就不重新写一遍了,感兴趣的同学去维基百科看一遍。
至此,总结一下:通过本文,了解了HTTP和HTTPS之间的区别、TLS/SSL的历史发展、TLS/SSL的工作机制。差不多算是达到目的了。
可惜水平有限、时间有限,无法深入去追求把加密方面的内容深入了。
参考文献: