Computer Network

http和https的区别

http到https的演变

NetworkHTTP&HTTPS

http到https的演变

首先http和https都是应用层数据传输的协议。将他们传输数据的过程比做传纸条就很好理解。

A(客户端)和B(服务端)想要传纸条(传输数据),由于他们隔得比较远,所以需要由你们之间的中间人帮忙传递(运营商,路由器等)。

http在这个传输过程中就好比明文传输。你传输的数据会面临三个问题:

  1. 被监听
  2. 被篡改
  3. 被冒充

监听指的就是:客户端和服务器传输的这些数据能够被很轻易的截获,并且由于http明文传输,很容易就能让其他人知道你们传输的内容是什么。

https通过加密解决了监听的问题。加密主要有两种:对称加密和非对称加密。

常见的对称加密算法:

  • AES
  • DES
  • SM4

特点是:加密速度快,适合大量数据加密,密钥分发是难点

常见的非对称加密算法:

  • RSA
  • ECC
  • SM2
  • DH

特点是:加密速度慢,消耗cpu资源较多,适合交换对称密钥,签名等。更安全

对称加密指的就是:加密和解密用的都是同一份密钥。他的问题在于如何安全地将密钥传输到对方手中呢?对密钥再加密吗?那外层的密钥又怎么传输呢?会发现对称密钥的问题就在于此,始终会有最外层的密钥无法安全传输的问题。

所以后面又有了非对称加密。非对称加密指的就是加密和解密用的是完全不同的两个密钥。通常来说加密的是公钥,解密的是私钥。服务端直接将公钥匙传输给客户端。虽然中间人也能截获请求,得知公钥是什么。但是他们无法知道后续加密后传输的数据究竟是什么。因为解密公钥加密的信息只能使用对应的私钥解密,而私钥通常存储在服务器内部,不会对外公布。

但这样真的就安全了吗?显然这里面还有一个致命的bug就是篡改。

试想一下这样的场景:服务端将公钥A传输给客户端,中间人截获这个请求,将公钥A替换成了他们自己生成的公钥B,再将这个请求下放给客户端。客户端后续传输的数据都用的公钥B加密的,此时中间人再截获客户端发的请求,用对应的私钥B解密,拿到了数据,最后再用公钥A加密,传输给服务器。服务器再用私钥A解密获取数据。这样就做到了神不知鬼不觉地得到了你们传输的内容。

所以这里就需要解决一个问题:公钥在传输的过程中可能被中间人篡改。

可能会想到在嵌套一层公私钥,但是你还是会发现,这和对称加密相似,总有一层公钥的传输的明文的,是可以被篡改的。所以单纯依靠客户端和服务端双方,是无法真正防止中间人攻击的。

所以这里引入了第三方机构CA,也就是证书认证机构。数据被篡改的核心原因就是客户端并不知道传来的消息是否是和自己期望通讯的那个服务端。因此这些服务端需要向第三方机构CA申请数字证书。这些数字证书由CA机构授权,首CA信任。在浏览器里通常会内置受信任的CA根列表。因此中间人能伪造CA证书,但是无法伪造受CA信任的证书。

因此上述的内容就是https在安全性层面做的改变。他通过加密解决了窃听的问题,通过签名+CA数字证书解决了篡改以及中间人攻击等问题。

此时https对于http有这些不同之处:

  1. 安全性,https在http下层又加入了SSL/TLS协议,通过加密防止窃听,通过签名防止篡改,通过CA数字证书防止冒充。进一步提升了数据传输的安全性。
  2. 性能方面由于https为了确保传输安全,数据的传输需要经过加密,签名,解密等步骤。因此http通常会快很多。但由于HTTP/2之后就有了多路复用,以及TLS1.3时对握手进行了优化能够在1-RTT甚至是0-RTT内完成握手。因此HTTPS为了安全而导致的性能损失,在现代网络和设备的加持下其实可以忽略不计了
  3. 端口方面,http默认端口80,https默认端口443
  4. 浏览器态度方面,目前Google,百度等搜索引擎都优先收录https的网站。以Google举例,现在http协议的网站会直接爆红色危险,用户看到根本就不敢浏览。

https的SSL/TLS握手的流程

SSL/TLS协议的演进

HTTPS 使用的加密协议从最初的 SSL 演变为 TLS,目前广泛使用的是 TLS 1.2 和 TLS 1.3。TLS 1.3 引入了更快的握手机制 0-RTT,进一步降低了延迟,QUIC 内嵌使用这个协议。

简单了解下 SSL/TLS 协议的演进之路:

1)SSL 1.0 从未公开发布,存在严重的安全漏洞

2)SSL 2.0 在 1995 年发布,是第一个公开发布的 SSL 版本,提供了基本的加密和认证功能,但存在多种安全问题,如容易受到截断攻击、缺乏握手完整性保护等

3)SSL 3.0 在 1996 年发布,对 SSL 2.0 进行了显著改进,包括引入消息完整性校验、握手的改进以及更强的加密算法,但后来被发现的 POODLE 攻击导致 SSL 3.0 被废弃

4)TLS 1.0 在 1999 年发布,是 SSL 3.0 的演进版,改进了加密算法、密钥生成、消息认证码机制,并增加了对握手的保护

5)TLS 1.1 在 2006 年发布,引入了对 CBC 模式攻击的保护,改进了消息认证码算法

6)TLS 1.2 在 2008 年发布,支持更强的加密算法如 AES-GCM,引入更灵活的握手机制,允许使用 SHA-256 进行握手完整性校验

7)TLS 1.3 在 2018 年发布,显著简化了握手过程,减少了加密套件的数量,移除了不安全的加密算法如 RSA 密钥交换,采用了 0-RTT 握手以减少连接建立的延迟,并增强了前向保密性

ECDHE握手流程

首先https使用的是TLS协议握手,根据握手的算法不同,流程也有细微的差别。

ECDHE握手的大致流程:

  1. 客户端发送Client Hello消息,消息主要包含:
    • TLS版本
    • 客户端支持的加密算法套件
    • 生成的随机数
  2. 服务端收到后,回复Server Hello + Server Certification + Server Key Exchange
    • Server Hello是确认TLS版本, 确认加密算法套件,生成随机数
    • Server Certification主要是服务端将自己的数据证书发送给客户端进行验证,并且还包含自己的公钥
    • ECDHE握手相较于RSA握手多了一步Server Key Exchange,因为ECDHE是基于椭圆曲线的,需要交换选择的椭圆曲线。并生成一个随机数作为服务端椭圆曲线的私钥,并基于椭圆曲线算出公钥。Server Key Exchange会将选择的椭圆曲线和公钥一并发送给客户端,并且为了防止被篡改,还会使用服务器私钥对交换的数据进行签名
  3. 客户端收到后,需要Client Key Exchange + Change Cipher Spec + Client Finished
    • 首先客户端会验证服务端发来的数字证书,主要是通过操作系统或浏览器内置的CA根证书来验证服务端传来的证书是否安全可靠
    • Client Key Exchange这里客户端同样会生成一个随机密钥,并基于相同的椭圆曲线算法计算出一个公钥并发送给服务端
    • 随后此时双方都拥有这几个关键参数:客户端随机数,服务端随机数,客户端椭圆曲线公钥,服务端椭圆曲线公钥。 此时客户端会利用自己的椭圆曲线私钥和服务端的椭圆曲线公钥计算出一个Pre-Master Secret。 随后使用这个Pre-Master Secret和两个随机数,生成本次会话的最终密钥Master Secret
    • 紧接着客户端发送Change Cipher Spec,这个步骤后,后续的传输数据都是加密的
    • 发送完Change Cipher Spec后,客户端再发送一个Client Finished。这个 Finished 会带上 Encrypted Handshake Message,这个 message 就是之前发送的所有数据的摘要,并且还用生成的对称加密密钥加密了,传递给服务器端验证,预防握手过程中的握手信息被修改。
  4. 服务端收到后,先是利用自己的椭圆曲线私钥和客户端的椭圆曲线公钥生成一个Pre-Master Secret,再通过两个随机数,也计算出Master-Secret。然后也是发送Change Cipher Spec。一切正常后ECDHE TLS握手就结束了。

RSA握手流程

RSA相较于ECDHE区别主要在于第二次握手

  1. 首先同样还是客户端发送Client Hello,包含:TLS版本,支持的加密算法套件,以及随机数
  2. 服务端收到后回复Server Hello + Server Certification。主要是确认TLS版本,确认加密套件,生成随机数。并且将自己的数字证书发送给客户端验证。 最后会发送一个ServerHelloDone表示初步握手结束
  3. 客户端收到后,首先也是通过CA验证数字证书是否安全可靠。并且在此生成一个随机数Pre-Master。通过证书得到的公钥,加密通过客户端密钥交换(Client Key Exchange)发送给服务端。 此时双方就有了三个必要参数:客户端随机数,服务端随机数,客户端生成的Pre-Master,这三个参数可以作为生成对称密钥的参数。因此紧接着再发送开始使用加密(Change Cipher Spec)给服务器端。 发送完(Change Cipher Spec)后,客户端再发送客户端完成(Client Finished),这个 Finished 会带上 Encrypted Handshake Message,这个 message 就是之前发送的所有数据的摘要,并且还用生成的对称加密密钥加密了,传递给服务器端验证,预防握手过程中的握手信息被修改。
  4. 服务端收到后,也发送Change Cipher Spec以及Server Finished。表示RSA握手结束

ECDHE 和 RSA 握手的区别

可以看到RSA握手里,如果服务端的私钥泄漏,就会导致客户端加密传递的Pre-Master被破解,导致对称密钥被破解。进而出现安全漏洞。并且每次会话传递的Pre-Master均是由相同的服务端公钥加密,私钥解密的。因此RSA不具备向前安全性,一旦私钥泄漏,所有历史会话的数据都会被破解。

而ECDHE,每次会话都基于椭圆曲线和随机生成的密钥来计算出临时公钥。并通过双方的临时公钥和自己的私钥,以及随机数生成对称密钥来加密。他没有使用服务端的公私钥直接参数加密或密钥参数的传递,而是利用临时的密钥对生成对称密钥来加密。因此ECDHE私钥泄漏只会影响当前会话,因为每个会话生成的临时私钥都不相同。具备向前安全性

为什么TLS1.3支持1-RTT甚至0-RTT?

在TLS1.3里全面使用ECDHE,移除了RSA密钥交换

而在TLS1.2里握手是需要2-RTT的

第一个RTT:

  • Client Hello
  • Server Hello + Server Certification + Server Key Exchange

第二个RTT:

  • Client Key Exchange + Change Cipher Spec + Client Finished
  • Change Cipher Spec + Server Finished

我们会发现一个问题:客户端必须等服务端响应了他的椭圆曲线密钥后,才生成自己的椭圆曲线密钥。但是这两者之间其实并没有任何前后因果关系。

因此TLS1.3里就让客户端在Client Hello的时候就带上自己的椭圆曲线公钥

那么此时,服务端生成了他的公钥并发送给客户端后,就能在1-RTT之后传输加密数据,提升了性能

那0-RTT又是怎么做到的呢?
  1. 在正常连接完后,服务端会发送一个session ticket。ticket内部包含过期时间,pre shared key等相关信息。客户端收到后将其缓存起来
  2. 第二次连接的时候,客户端取出缓存的ticket,并根据ticket得到pre shared key并派生出early key。然后根据HKDF得到early traffic key用于加密0-RTT时传输的早期数据。将早期加密数据和对应的psk相关信息连同Client Hello一起发送给服务端(Client Hello依旧包含随机数和椭圆曲线公钥等)
  3. 服务端验证psk是否合法,并根据psk派生出early traffic key解密早期数据
  4. 后续双方依旧通过ECDHE计算出的密钥加密数据
0-RTT的缺点

首先就是0-RTT时加密早期数据的这个early traffic key只依赖于上次连接生成的ticket。而不是新的ECDHE。攻击者可以抓到你发的第一个包,然后重复发送给服务器执行。

这样对于一些非幂等操作的接口就会出现严重问题,这就是0-RTT的重放问题。

因此0-RTT只能使用在GET等幂等请求

post.comments