HTTPS原理和TLS认证过程

1,272 阅读13分钟

本文正在参与 “网络协议必知必会”征文活动

了解网络的人应该都知道,HTTP协议让WEB应用开始风靡全球。但现在几乎所有的知名网站却都是使用HTTPS协议进行传输的,因为它在HTTP基础上加了SSL/TLS加密传输通道,保证了数据安全。那HTTPS是怎么通过SSL/TLS保证数据安全呢,本篇文章将详细描述加密通道SSL/TLS的传输过程。

HTTPS协议

HTTP协议是通过明文传输的,用户传输的内容会很容易被别有用心的人拦截,并伪装成服务端,向用户传送错误的信息,且能轻松获取用户的隐私信息,而这些操作用户是完全无感知的。因此,需要有一个机制能确保传输双方的信息被加密过,且无法被第三方破解。这时,HTTPS就应运而生了。

HTTPS其实只是在HTTP协议和TCP层之间增加了一个SSL的安全传输协议,如下图所示。整个传输的加密过程都在新的安全层SSL/TLS中实现,而原来的HTTP层的传输流程保持不变,这样就很好地兼容了旧的HTTP协议,也沿袭了TCP/IP协议族的分层思想。
layer_tls.png

TLS/SSL协议

SSL最早是由网景公司(Netscape)开发的,后被IETF(The Internet Engineering Task Force - 互联网工程任务组)标准化后写入RFC(Request For Comments),SSL在迭代到3.0后才将其标准化,并重新更名为TLS。目前TLS先后迭代了TLS 1.0TLS 1.1TLS 1.2TLS 1.3,目前被广泛使用的是TLS 1.2版本。

TLS加密原理

在传输层中,TCP通过三次握手建立了两端的连接。在已建立TCP连接的基础上,TLS也是通过几次握手来保证应用层的数据安全传输。在详细描述TLS的握手协议之前,我先简要描述下TLS是怎么保证数据安全的。

我们知道,要保证数据的安全,就要对两端的传输的报文进行加密,且要防止被破解。而在密码技术领域,一般有对称加密和非对称加密两种,对称加密算法是加密和解密都用的是同一个秘钥。而非对称加密有公钥和私钥两个秘钥,通过私钥加密的内容,可通过公钥和私钥解密。那应该用哪一种加密算法呢?

可以只用对称加密来保证数据安全吗?

答案是不行的。原因有几个方面:

  1. 一个服务端站点是可以被世界上每一台主机访问的,每个浏览器客户端访问时就建立了一个数据连接通道,而每个连接就要有不同的对称秘钥。如果世界上所有连接都用同一个秘钥,那就没有安全可言了;
  2. 每个不同的TCP连接都要有不同的对称秘钥,那秘钥要怎么协商出来呢,这就是个问题,如果秘钥通过明文传输,那秘钥还是可以被第三方截取,然后用截取的秘钥解密传输的数据,因此还是不安全的;

可以只通过非对称加密来进行数据传输吗?

这样也是不可以的。首先,非对称加密的数据加解密相当耗时,通过这种加密方式传输数据会影响效率,这一点就已经被pass了。其次,通过这种方式也不能保证安全。

那同时使用对称加密+非对称加密方式加密?

TLS就是通过这种方式进行加密的。两者结合后,使用非对称加密的方式应该尽量降低,才能保证传输的效率。因此,TLS的规则就是:服务端生成非对称秘钥对,私钥自己保存,将公钥明文传输给客户端;客户端生成一个对称秘钥,再将对称秘钥使用收到的公钥进行加密,将加密后的秘钥传送给服务端;这样双端都持有相同的对称秘钥,之后的数据就通过该秘钥进行加密再传输。

但这样还有个问题,服务端的公钥如果通过明文传输,还是不安全,传输的数据依然可以被破解。那TLS怎么保证服务端传输的公钥不被调包呢?这时就用到了数字证书和CA(Certificate Authority)证书颁发机构了。

数字证书和CA的关系

数字证书是一个包含了某个服务站点名字、公钥的文件,该文件由CA颁发,能够证明服务站点的真实性。就好像每家公司都必须会在工商局办理一个营业执照,用于证明自己公司的真实身份一样。服务端通过发送数字证书给客户端,由客户端验证向CA验证证书的真实性,如果验证通过才取出证书中的公钥进行下一步的处理。此外,全球有无数多的网站,伴随着也会有很多层级的CA机构,就像工商局也分省级、市级的,CA的认证是逐级链式认证的过程。这点在后面会详细描述。

TLS的认证原理可以简略地用下图来表示:
exchange_tls.png

TLS的握手过程

前面TLS的原理只描述了大概的流程,在具体执行时,客户端和服务端是怎么交互从而建立一条安全的TLS连接呢?下图是TLS握手的整体流程图:

此外,我们通过一个实验来观察TLS握手的细节。首先,用浏览器访问一个HTTPS的网站,然后使用wireshark抓包工具抓取所有往返数据报文。由于基于TLS的HTTP协议传输的应用层数据都是密文,无法阅读HTTP的内容,为了分析方便,需要将传输的内容在wireshark进行解密,MAC的设置的方法:

  1. 在命令行输入以下命令,将Chrome浏览器和网站建立TLS连接后的对称秘钥保存在/tmp/tmp-google/.ssl-key.log文件下;
SSLKEYLOGFILE=/tmp/tmp-google/.ssl-key.log /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --user-data-dir=/tmp/tmp-google


  1. 将生成的对称秘钥设置到Wireshark中,具体路径Preference——Protocols——SSL(或TLS),在(Pre)-Master-Secretlog filename中填入刚才的秘钥文件,如图所示;
    set_master_key.png

  2. 在Chrome浏览器打开一个HTTPS协议的网站,如小米官网,这时就会在/tmp/tmp-google生成小米的对称秘钥.ssl-key.log,然后Wireshark就会读取该秘钥并解密抓到的HTTP密文,下图抓到的请求小米官网的部分数据报文;
    https_data.png

接下来,我们主要分析TLS握手的数据报,观察握手的具体步骤,从截图中可知TLS握手经历了以下几个主要的握手流程,我们一个一个解析:

Client Hello

在上图中 No. 一栏代表的是数据帧编号,其中编号为5226的数据帧就是 Client Hello 的数据帧,双击打开后查看数据帧详细结构,从上到下分别为物理层、数据链路层、网络层、传输层和TLS层,展开TLS层可看出 Client Hello 报文包含如下信息:
client_hello.png

  • 类型(Content Type):占用一个字节,表示当前为Handshake数据类型,TLS的数据类型可参考TLS类型
  • 版本(Version):TLS 1.2 也是 SSLv3.2。表示浏览器能够支持的 SSL 最高版本;
  • 长度(Length):占用两字节
  • 随机数(Random):浏览器会生成一个32字节随机数,最后用来计算出对称秘钥,需要客户端和服务端一起协商出来。后面服务端的 Server Hello 阶段也会生成一个随机数。
  • 会话ID(Session ID):这个 Session ID 是可以重用的,具体看服务端资源和支持情况。如果要复用 Session ID, SSL 服务端需要维护连接的状态和上次握手成功留下的加密信息。如果是第一次访问该网址,会话 ID 尚未创建,客户端没记录,为 0。如果客户端保存了 Session ID 的信息,下次发起 SSL 请求的时候会带上。
  • 加密套件(Cipher Suites):浏览器可以支持的密码套件列表。这些套件会根据优先级排序。每一个套件代表一个密钥规格。以 “TLS” 开头,接着是密钥交换算法,然后用 “WITH” 连接加密算法和认证算法。一个加密套件有这么几个内容:密钥交换算法、加密算法(会带有支持的最高密钥位数)、认证算法还有加密方式。最终使用什么密码套件是服务端决定的。要什么密码套件会在 Server Hello 中进行反馈。
  • 压缩算法:这里为 0,说明不支持压缩算法;
  • 扩展字段:一些扩展信息,比如 SNI 的支持,ALPN 的信息等等。

下一个编号为5399的报文是从服务端发给客户端的TCP响应报文,是对Client Hello 这个报文的响应。

Server Hello

收到 Client Hello 报文后,服务端随后发送了 Server Hello 的握手报文,报文的详细包结构如下截图:
server_hello.png
Server Hello 的包结构和 Client Hello 差不多,具体字段就不再赘述了。我们可以看看差异的部分:服务端也发送给客户端一个 Ramdom 随机数,这是第二个随机数,后面会有第三个随机数,三个随机数一起生成一个对称秘钥。Cipher Suite 字段表示服务端从客户端的秘钥套件中选择一个,用于后面的加密方案。

Certificate

从下面的抓包截图可知,发送完 Server Hello 握手报文后,服务端接着又连续发送了 Certificate、Server Key Exchange 和 Server Hello Done 三个报文。这里TCP下方有 [3 Reassembled TCP Segements] 层级并列出了三个数据帧,表示的是下方TLS数据是由三个TCP报文分段传输的,Wireshark 为了查看数据方便,将三个数据帧重组为一个方便查看。
certificate.png
Certificate 握手报文从服务端传输了一套证书链到客户端,展开 Certificates 可看到里面包含了两个证书文件,关于证书的内容会在下文详细讲到。

Server Key Exchange

server_key_exchange.png

服务端通过DH算法来协商出一个对称秘钥,具体更深入的解释改算法可以参考 Keyless SSL

Server Hello Done

server_done.png

表示服务端完成握手协议,通知客户端进行下一步操作。

Client Key Exchange

client_key_exchage.png
上面 Certificate 握手阶段,客户端获取到服务端证书并拿到服务端的公钥,然后这时客户端生成一个 Random3,并用公钥加密生成 PreMaster Key传给服务端,后面服务端通过自己的私钥解密 PreMaster Key也得到 Ramdom3,这时两端都各有 Random1 + Random2 + Random3,两端用同样的算法生成一个对称秘钥,在握手结束后就通过该秘钥进行数据加密传输。

Change Cipher Spec (Client)

change_cipher_spec.png
表示客户端接下来要切换为另一种加密方案来传输数据,即使用对称加密来传输数据。

Client Finish

客户端完成握手阶段。

Change Cipher Spec (Server)

server_change_cipher.png
表示服务端接下来使用另一个中加密方案来传输数据。

Server Finish

服务端完成握手阶段。

关于证书

前面服务端的 Certificate 握手阶段向客户端发送了证书,而客户端收到证书后就要对其进行验证,只有验证通过了才会进入下一个步骤。在解释验证过程之前,我们先了解下证书的内容,以下本次抓包目标网站的证书链内容,可以在Chrome浏览器地址输入栏前面小锁图标点击查看,如下图所示:
certificate_file.png
每一张证书都包含内容:

  • 主体信息:表示该证书的所属主体,包括主体名称、域名等;
  • 颁发者信息:表示签发这张证书的CA机构,可从截图的上部分看出证书的层级,小米的证书是由 RapidSSL机构签发的,该机构的证书又是另一个更高层级的DigiCert机构签发,而该机构一般是最权威的机构,一般每台计算机都会内置该证书,说明所有计算机都信任它。
  • 公钥:该主体的公钥,会有一个对应的私钥由主体自己保存;
  • 签名:将该证书的内容经过哈希算法计算得出一个摘要信息,再用其颁发机构的私钥加密得到的结果就是本证书的签名,由于私钥是在颁发机构内部保存的,因此证书的签名是由颁发机构生成的。

证书认证过程

我们再重新观察下 Certificate 握手报文的详细数据如下图,这里服务端发给了客户端两张证书,一张小米自己的证书和其颁发者证书,但为什么没有发送根证书DigiCert呢,可能是由于该证书足够权威,基本上客户端也已经内置了。
certifcate_catch.png
这时收到两份证书后,客户端会通过以下流程一步一步验证是否可信:

  1. 通过域名核对,找出所要访问的服务端的证书A,即小米证书;
  2. 通过证书A的Issuer找到其颁发者证书B,即中间证书RapidSSL;
  3. 通过证书B的Issuer找到根证书C,发现其已内置在本地,然后用证书C的公钥解密证书B的签名取出摘要1,再用同样的哈希算法计算出证书B的摘要2,两者比对,如果一致,就证明证书B是可信的;
  4. 用同样的方法,取证书B的公钥解密证书A的签名,比对摘要相等后也证明了证书A是可信的,这时验证过程就完成了,这时就可以拿证书A的公钥去做加密Random3进行下一步握手流程了。

以上一层层地认证过程就叫做认证链。这就像生活中的熟人生意,比如,我和马云认识,互相信任,而马云和马化腾认识,也互相信任,但我不认识马化腾,如果我和他做生意担心被坑,这时通过马云的介绍,我和马化腾也认识了,后面做生意也就放心了。

本文使用 文章同步助手 同步