简介

Web开发人员都知道HTTP和HTTPS协议,后者相比前者更加安全。所以现在看到的网站,大都是基于HTTPS协议部署的。通常所说的HTTPS协议,它其实并不是一个新的协议,而是HTTP over TLS/SSL。TLS协议并不严格对应于OSI或者TCP/IP分层模型。大致的一个范围是,位于HTTP协议之下,TCP协议之上。当进行HTTPS通信时,首先会经过TLS握手,建立一个安全的会话,之后双方的通信都经由这个会话加密后进行。类似还有FTP和FTPS的关系。

因此,HTTPS协议的核心其实是TLS/SSL协议。为什么叫TLS/SSL协议呢?因为此协议起源于SSL协议,SSL协议是Netscape公司开发的。因为前几个版本有问题,所以Netscape重新设计了3.0版本的协议。后来,TLS小组成立,开始将SSL 3.0迁移至IETF。彼时,微软和Netscape因为Web大战不可开交,进展缓慢。最后还是发布了TLS 1.0版本,相比SSL 3.0改动不大。为了保持中立,进行了改名,即为TLS协议。全称是transport layer security

TLS协议包含记录协议,握手协议,加密等几个大的方面。还有其他很多的知识点,可以参考RFC 5246,或者其他HTTPS相关的书。这里只介绍主要的握手建立连接过程。采用的是TLS 1.2版本。

TLS协议

记录协议

图片

TLS消息传递的格式。每个消息配一个标头,之后跟上数据,数据一般是密文。

握手协议

初始握手过程

图片

一个典型的握手过程如图。

1. 客户端发送ClientHello消息

ClientHello消息包含:协议版本,随机字符串,SessionId,加密套件列表,扩展字段(例如,支持的椭圆曲线E类型等)等。

2. 服务器发送ServerHello消息

ServerHello消息包含:协议版本,随机字符串,选中的加密套件。

3. 服务器发送证书

4. ServerKeyExchange

根据TLS协议选中的加密套件,这个消息发送的数据也会不同。某些场景可能不会发送任何数据。

5. ServerHelloDone

表明服务器发送完了所有的消息,等待客户端响应。

6. ClientKeyExchange

同上。客户端根据选中的密钥协商算法,发送参数。

7. ChangeCipherSpec

表明已生取得连接所需的所有参数信息。已生成加密密钥。并且将切换到加密模式。

8. Finished

握手完成,后续将会进行加密通信。

会话恢复

完整的握手协议比较复杂。如果每次连接都进行上面的流程,无疑会消耗很多时间。因此,引入会话机制,允许两端在关闭连接后一段时间,保持会话。方便后续恢复。

图片

会话恢复过程

1. 客户端发送ClientHello

消息携带了SessionID,表明自己还有上次的会话信息,可恢复。

2. 服务器发送ServerHello

服务器愿意恢复的话,就将SessionID放在这里。然后使用之前协商的master secret重新生成一套密钥。

3. Finished

表明连接建立,后续加密进行。

加密套件

图片

如上。当进行连接时,从选中的加密套件,即可大致知道这个过程了。典型的就是上面的加密套件。

它的意思是,此连接使用RSA进行身份验证,然后使用ECDHE进行密钥交换。通信时,消息加密方式是128位密钥GCM模式的AES加密算法,计算密钥的PRF算法是sha-256。

密钥交换和身份认证

从之前的握手过程,能够看到,服务器给客户端发送了自己的证书信息,用于身份验证。

证书是包含服务器公钥的数字签名文件,由权威机构颁发。当客户端收到服务器的证书后,就会对证书进行验证。到颁发机构,然后用机构的公钥去计算签名比对是否一致。如果一致,则表明证书无误。然后就能确定公钥的正确性。

对于ECDHE密钥交换算法,客户端会用公钥加密密钥交换的参数发送给服务器,服务器则用私钥加密参数,发送给客户端。两者相互解密,即可得到密钥交换参数了,用于后续密钥计算。对于RSA密钥交换的话,则是由客户端生成预备主钥,采用公钥加密后发送给服务器端。

密钥计算

经过上面的ECDHE流程,两端会计算出一个预主钥,pre-master-secret,参数即是KeyExchange传递的。然后,两端各自进行master secret计算

masterSecret = PRF(preMasterSecret, "master secret", clientHello.Random + serverHello.Random)

记住,这里计算的只是,masterSecret。它是后面计算各个加密密钥的关键。masterSecret永远是48字节。

密钥生成

keyBlocks = PRF(masterSecret, "key expansion", server_random + client_random)

这一步会生成一个密钥串,分割成6个密钥:两个MAC密钥,两个加密密钥,两个初始向量。供后续的加密等使用。

TLS抓包

熟悉上诉流程后,可以使用Wireshark抓包来实际体验下整个过程。Wireshark配置TLS抓取的方式这里就不介绍了,网上也能搜到。如图是抓取到的一次TLS握手流程。

图片

接下来,一步一步来分析抓取的数据。

ClientHello

图片

首先是客户端发送ClientHello消息。里面包含信息有

  • 随机字符串Random,每次连接随机产生。用于后面的密钥计算。
  • SessionID信息。表明客户端想复用上次的会话。
  • 客户端加密套件列表,用于加密套件协商。
  • 扩展。支持很多扩展,截图是支持的椭圆曲线方程组。因为椭圆曲线的基点和方程都是已知的,有一个统一的标准。下面还有一个ALPN应用层协议字段,表明客户端支持的应用协议列表。例如http2协议等。

ServerHello

图片

随后,服务器响应一个ServerHello消息。携带的信息有

  • 一个服务器端的随机数。同样用于后续的密钥计算。
  • SessionID信息。这里服务器没有SessionID信息,表明,服务器并不想复用上次会话。于是后面会重新计算协商密钥,建立连接。
  • Cipher Suite。到这一步,服务器就确定了,选中TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256加密套件。这里其实有很多标准,大家感兴趣可以了解其他的加密套件。无非是几种算法组合。对于不同的加密套件,也会有一些流程的区别。
  • ALPN。这一步,服务器支持http2,所以确认了接下来的应用层协议。

Certificate,ServerKeyExchange

图片

服务器发送证书信息。客户端拿到证书后就去校验证书有效性,并从中取到服务器的公钥。

图片

验证通过后。服务器使用私钥加密椭圆曲线参数,发送给客户端。这里可以看到,椭圆曲线采用的是x25519。

接下来还发送了一个ServerHelloDone消息。表示,服务器的信息都发送完了。

ClientKeyExchange,ChangeCipherSpec

图片

客户端收到服务器的消息后,同样的,发送公钥加密的椭圆曲线参数。至此,双方拿到了密钥计算的所有信息。然后客户端发送ChangeCipherSpec表明,接下来的通信采用加密方式进行。具体的加密算法就是aes-128-gcm。至于分组加密的向量,密钥,和MAC密钥等,则从密钥计算那里一步步算出来。

至此,TLS便完成了整个连接过程。

中间人攻击

在学习的过程中,恰好发生一件互联网安全的问题。网上反映,Github遭遇了中间人攻击。具体的现象是,打开自己的HTTPS博客地址,响应了一个不知道哪来的证书。什么是中间人攻击呢?我们的网络是不可信的。我输入网址,打开页面,这个页面不一定就是那个服务器返回的。黑客可能劫持了我们的流量,在IP转发过程中,将请求指向了自己的服务器。TLS中就考虑到了这点,证书就是验证用户身份的。所以在证书验证这一步我们发现遭到了攻击。试想下,如果我们的电脑被不小心安装了非法的根证书。然后,黑客再劫持我们的流量,我们这时候并不会发现出了问题。这样,HTTPS也就没有安全可言了。

那就有一个问题了。怎么进行中间人攻击的呢?黑客是怎么把我们请求的流量转发到他的服务器的呢。方法其实很多。

ARP欺骗

ARP协议是将IP和mac地址对应的协议。发送伪造的ARP数据包,刷新其他主机的ARP表。这样,下次通信时,就会响应劫持者的mac地址。进而被劫持了。

DNS劫持

在进行HTTP通信时,首先要进行DNS查询。劫持者修改DNS记录,让域名指向自己的服务器地址。这时候就达到了劫持的目的。

DNS缓存中毒

DNS有缓存。当查询一个不存在的域名时,会进行递归查询。这时候,攻击者发送大量的伪造DNS响应给缓存DNS服务器。其收到响应后,则记录在解析表中。后续真正的响应到达时,则会被忽略。

BGP路由劫持

边际网关协议,就是IP路由的协议。骨干网某些路由设备,接受非法路由信息后。会导致该路由的流量被劫持。

最后

TLS协议涵盖了密码学的方方面面。最初学习HTTPS协议时,只是简单记住了几个加密算法名字,但是并不太熟悉其内容。后来,看了《图解密码》这本书。对密码学有了一个了解后,再回过头来看TLS协议,发现能够深入一些了。知道了其整个设计解决的问题,以及它为什么安全。

参考资料