网络协议之HTTPS

604 阅读23分钟

概述

SSL 即安全套接层(Secure Sockets Layer),在 OSI 模型中处于第 5 层(会话层),由网景公司于 1994 年发明,有 v2 和 v3 两个版本,而 v1 因为有严重的缺陷从未公开过。 SSL 发展到 v3 时已经证明了它自身是一个非常好的安全通信协议,于是互联网工程组 IETF 在 1999 年把它改名为 TLS(传输层安全,Transport Layer Security),正式标准化,版本号从 1.0 重新算起,所以 TLS1.0 实际上就是 SSLv3.1。 目前应用的最广泛的 TLS 是 1.2,而之前的协议(TLS1.1/1.0、SSLv3/v2)都已经被认为是不安全的,各大浏览器即将在 2020 年左右停止支持。 TLS 由记录协议、握手协议、警告协议、变更密码规范协议、扩展协议等几个子协议组成,综合使用了对称加密非对称加密身份认证等许多密码学前沿技术。

文中出现的概念

概念描述
对称密钥算法
Symmetric-key algorithm又称为对称加密,在加密和解密时使用相同的密钥,或使用两个可简单地相互推算的密钥。
常见的对称加密算法有:AES、ChaCha20、3DES、Salsa20、DES、Blowfish、IDEA、RC5、RC6、Camellia。
公开密钥密码学
Public-key cryptography因为加密解密需要两个不同的密钥,故又称非对称加密。它需要两个密钥,一个是公开密钥,另一个是私有密钥。对原文进行加密:公钥用作加密,私钥用作解密。签名:私钥加密,只有对应公钥才能解密。故能表示该密文是由公钥的所属者发出。公钥可在随意公开,但私钥绝不透过任何途径向任何人提供。常见的非对称加密算法有:RSA、ElGamal、Rabin(RSA的特例)、DSA、ECDSA。使用最广泛的是RSA算法。
加密 Encrypt以某种特殊的算法改变原有的数据
密钥 key在明文转换为密文或密文转换为明文的算法中输入的参数
解密 Decrypt使用密钥还原明文的过程

理解对称加密和非对称加密

按照密钥的使用方式,加密可以分为两大类:

  • 对称加密
  • 非对称加密

注意:对 TLS 来说,密钥是一长串的数字,约定俗成的单位是,比如通常说密钥长度是 128,表示一个 16 字节的二进制串; 密钥长度是 1024,就是 128 字节的二进制串。

对称加密

对称密钥算法(英语:Symmetric-key algorithm)又称为对称加密、私钥加密、共享密钥加密,是密码学中的一类加密算法。这类算法在加密和解密时使用相同的密钥,或是使用两个可以简单地相互推算的密钥。事实上,这组密钥成为在两个或多个成员间的共同秘密,以便维持专属的通信联系。与公开密钥加密相比,要求双方获取相同的密钥是对称密钥加密的主要缺点之一。 常见的对称加密算法有AES、ChaCha20、3DES、Salsa20、DES、Blowfish、IDEA、RC5、RC6、Camellia。 对称加密的速度比公钥加密(非对称加密)快很多,在很多场合都需要对称加密。

对称加密小结:

  1. 所有对称加密算法的核心是 XOR 运算,运算表达式为:A XOR B XOR B = A(其中B为对称密钥,A为明文)
  2. 总体而言,对称加密可为两种**:流加密块加密**。
    1. 流加密:每次只能加密一个 bit。
    2. 块加密:将待加密数据分割成块,每次可以加密多个 bit。
  3. 在实际应用中,对称加密一般配合哈希算法组成密码套件,对数据同时进行加密和哈希计算。因为对称加密数据并不能保证数据本身的完整性,所以还需要和哈希算法配合添加完整性校验能力。这个完整性校验的数据叫做 MAC(message authentication code)。此外,还存在带密钥的 MAC,称为 HMAC。
  4. 对称加密速度与非对称加密快很多,所以对传输的数据一般采用对象加密。

TLS 有非常多的对称加密算法可供选择,大致分类如下:

注意:TLS 1.3 中已经禁止使用非 AEAD 的密码学套件,AEAD 是一种范式,而非具体的加密标准,它表示同时包含了加密和完整性哈希的加密算法。比如可以由 CBC 和 SHA1组合而成,也可以直接是 GCM 这种内涵了加密算法和 MAC 算法的加密套件直接组成。

对称加密局限性

如何安全交换对称加密密钥是令人头疼的问题。有人说,对密钥本身再进行一次加密不就好,但问题是,如果还是使用对称加密,怎么也摆拖不了俄罗斯套娃。所以,需要寻找另一种加密方式,即非对称加密。

非对称加密

解决对称加密密钥交换问题。

公开密钥密码学(英语:Public-key cryptography)也称非对称式密码学(英语:Asymmetric cryptography)是密码学的一种算法,它需要两个密钥,一个是公开密钥,另一个是私有密钥;公钥用作加密,私钥则用作解密。使用公钥把明文加密后所得的密文,只能用相对应的私钥才能解密并得到原本的明文,最初用来加密的公钥不能用作解密。由于加密和解密需要两个不同的密钥,故被称为非对称加密;不同于加密和解密都使用同一个密钥的对称加密。公钥可以公开,可任意向外发布;私钥不可以公开,必须由用户自行严格秘密保管,绝不透过任何途径向任何人提供,也不会透露给被信任的要通信的另一方。 基于公开密钥加密的特性,它还能提供数字签名的功能,使电子文件可以得到如同在纸本文件上亲笔签署的效果。 公开密钥基础建设透过信任数字证书认证机构的根证书、及其使用公开密钥加密作数字签名核发的公开密钥认证,形成信任链架构,已在TLS实现并在万维网的HTTP以HTTPS、在电子邮件的SMTP以SMTPS或STARTTLS引入。

非对称加密小结:

  • 非对称加密有两个密钥:公钥私钥。服务器保管私钥,公钥可在网络上任意发布。
  • 单向性。公钥加密的密文只能使用私钥解密,私钥同理。
  • 缺点:非对称加密比对称加密慢很多。

非对称算法设计难度比对称算法高,在 TLS 只有很少几种:DH、DSA、RSA、ECC 等。 非对称加密算法能保证对称密钥安全交换。客户端得到服务端的公钥,使用公钥对数据加密得到密文并发给服务端,服务端接收密文并用私钥进行解密,这样就能得到数据。但是,这里面暴露几个问题:

  • 如何知道数据是否完整? 原文并未做完整性校验。
  • 客户端如何得到正确的服务端的公钥?

哈希算法(摘要算法)

实现完整性校验的手段主要是**摘要算法(Digest Algorithm)**即常说的散列函数、哈希函数。具有以下特点:

  • 单向性。不能通过摘要值反推原文。
  • 蝴蝶效应。输入的微小不同会导致输出的剧烈变化。

摘要算法能给某段数据生成独一无二的"指纹"。当接收者收到数据,也通过相同的摘要算法计算得到"指纹",比对两者是否一样,如果发现不一样,则原始数据被篡改,直接丢弃。

注意:摘要算法不具备机密性,黑客可以修改修改的时候顺带把摘要也一起改了,所以真正的完整性是需要建立在机密性之上。在混合加密系统中使用会话密钥加密消息和摘要,黑客也无法修改。术语叫 HMAC(哈希消息认证码)。

HTTPS 是如何保证数据安全的

有了前面的铺垫,学习 HTTPS 就方便许多。HTTPS 是融合对称加密和非对称加密的特点,使用混合加密保障数据传输的安全性。

混合加密

单独使用对称加密或非对称加密都不能在实际的生产应用中使用,理由如下:

加密方式最突出优点最突出缺点
对称加密加密、解密速度非常快,且有专门硬件支持密钥交换存在安全漏洞
非对称加密密钥不需要交换,也就没有被黑客调换、监听的风险加密、解密速度非常慢

从上面讨论中我们可以得到以下结果:

  1. 既然对称加密加密、解密快,那么将它用于 HTTPS 通信建立后的数据加密。
  2. 非对称加密加密、解密速度慢,那么将它用于 HTTPS 通信建连的过程中。用于双方安全进行密钥交换操作。

这样,就能在性能和安全之间寻找极致平衡。

还有问题

问题一:如何确保客户端得到的公钥就是服务端提供的?

由于服务端的公钥可以在网上任意发布,所以这就给黑客提供伪造和替换的机会。 而解决这个问题也十分好办,使用数字证书

数字证书

公开密钥认证(英语:Public key certificate),又称数字证书(digital certificate)或身份证书(identity certificate)。是用于公开密钥基础建设的电子文件,用来证明公开密钥拥有者的身份。此文件包含了公钥信息、拥有者身份信息(主体)、以及数字证书认证机构(发行者)对这份文件的数字签名,以保证这个文件的整体内容正确无误。拥有者凭着此文件,可向电脑系统或其他用户表明身份,从而对方获得信任并授权访问或使用某些敏感的电脑服务。电脑系统或其他用户可以透过一定的程序核实证书上的内容,包括证书有否过期、数字签名是否有效,如果你信任签发的机构,就可以信任证书上的密钥,凭公钥加密与拥有者进行可靠的通信。 简而言之,认证机构用自己的私钥对需要认证的人(或组织机构)的公钥施加数字签名并生成证书,即证书的本质就是对公钥施加数字签名。 人们透过信任数字证书认证机构的根证书、及其使用公开密钥加密作数字签名核发的公开密钥认证,形成信任链架构,已在TLS实现并在万维网的 HTTPS、在电子邮件的 SMTPS 和 STARTTLS 广泛应用。业界现行的标准是国际电信联盟电信标准化部门制定的 X.509,并由IETF发行的 RFC 5280详细述明。而在不少国家/地区,都已立法承认使用数字证书所作的数字签名拥有等同亲笔签名的法律效力(如欧洲联盟、香港、台湾、美国、加拿大)。

数字证书小结:

  • 数字证书用于解决公钥认证。
  • 认证机构使用自己的私钥对需要认证的人或机构的公钥施加数字签名并生成的证书。

数字证书和CA

上面所说的信任数字证书认证机构,我们称为 CA(Certificate Authority)。他们专门对人或机构的公钥进行签名,用自身的信誉保证公钥是无法伪造的,可信任的。 CA 对公钥的签名也是有格式的,需要包含序列号、用途、颁发者、有效时间等等,把这些打成一个包再签名,完整地证明公钥关联的各种信息,形成数字证书(Certificate)小的 CA 可让 大 CA 签名认证,到了 Root CA,则只能自己证明自己,这称为自签名证书根证书。CA 证书签发步骤如下: CA签发数字证书.png 但有了 CA 并不能说 100% 安全,历史上发生了 CA 被黑客攻陷的事件,所以还需要做一些额外的操作弥补这些漏洞,比如 CRL 证书吊销列表和 OCSP 在线证书状态协议,目的是及时废止有问题的证书。

验签

客户端收到服务端发过来的证书,需要验证证书的合法性,这一步称为验签。操作系统和浏览器内置了各大 CA 的根证书,上网的时候只要服务器发过来它的证书,就可以验证证书里的签名,顺着证书链(Certificate Chain)一层层验证,直到找到根证书,就能确定证书是可信的,从而里面的公钥也是可信的。

自签名证书

自签名证书(self-signed certificate)是用自己的私钥签署的数字证书。是可用的与无成本的。自签证书和CA签名证书一样可以用来加密数据,但是由于该证书不属于公开密钥基础建设签发证书,其他没信任该该证书的 HTTPS 访问者的网页浏览器会显示一个警告,说这个证书不被他们的计算机或浏览器信任。因此,只有当不需要向用户证明服务身份时,才可以使用自签名证书,如非公开的网页服务器。非浏览器客户可以连接到 HTTPS 服务器并明确信任自签名证书,以创建客户与服务器的安全通信。

问题二:如何防止签名证书被调包?

实际上任何站点都可以向第三方权威机构申请证书,中间人也不例外。那么中间人可以通过拦截签名证书并替换成自己的签名证书么? 答案是否定的,因为签名证书除了包含公钥之外,还包含申请人的域名等校验信息,中间人虽然可以调包签名证书,但客户端解析时发现域名不一致就会认定为证书非法。

HTTPS 握手流程

RAS 握手流程

理解了上面的这些概念之后,我们就进入 HTTPS 握手流程的讲解了。首先,我们先了解 RSA 握手流程: RAS握手流程.png

  1. 运输层 TCP 通过三次握手建立连接。下面开始进行 TLS 握手流程。
  2. 第一步,客户端率先"发难",通过 Client Hello 握手协议向服务端发送以下内容:
    1. 客户端支持的 TSL 版本号。
    2. 客户端产生的随机数(Client Random)。
    3. 客户端支持的密钥套件列表。
    4. 扩展列表

RSA_Client_Hello.png

  1. 第二步:服务端响应。服务端通过 Server Hello 向客户端发送以下内容:
    1. TSL 版本号。
    2. 服务端随机数。
    3. 确认的密码套件。
    4. 扩展列表。
    5. Server Certificate
      1. 然后向客户端发送Server Certificate数字证书,里含有自己的公钥。
    6. Server Hello Done
      1. 随后,服务端发了 Server Hello Done 消息,目的是告诉客户端,我已经把该给你的东西都给你了,本次打招呼完毕。

RSA_Server_hello.png

  1. 第三步:客户端响应。客户端收到服务端的 Server Hello 握手协议后,会先进行验签操作:通过浏览器和系统内置的 CA 公钥确认从服务端接收到的签名证书的合法性。验证通过,取出服务端的公钥,后续会使用它来加密客户端生成的 pre-master 随机数。
    1. Client Key Exchange:使用服务端公钥加密 pre-master。
    2. Change Cipher Spec:之后改用会话密钥加密通信。
    3. Encrypted HandShake Message(Finished):把之前所有发送的数据做个摘要,并用会话密钥加密,服务端通过此摘要验证双方进行 TLS 的过程中的数据是否被篡改过。

Client_key_exchange.png

为什么还需要 pre-master 随机数? 这就必须说 TLS 的设计者考虑得非常周到了,他们不信任客户端或服务器伪随机数的可靠性,为了保证真正的“完全随机”“不可预测”,把三个不可靠的随机数混合起来,那么“随机”的程度就非常高了,足够让黑客难以猜测。 而且,客户端生成的随机数是通过服务端的公钥加密过的,只有对应私钥才能解密。

  1. 第四步:服务端最后响应。
    1. Change Cipher Spec:之后改用会话密钥加密通信。
    2. Encrypted HandShake Message(Finished):把之前所有发送的数据做个摘要,并用会话密钥加密,服务端通过此摘要验证双方进行 TLS 的过程中的数据是否被篡改过。

Server_final_answer.png

RSA 握手流程小结

  • RSA 握手需要 2个RTT 时延。
  • TSL 包含几个子协议,常见的有记录协议(Record Protocol)、报警协议(Alert Protocol)、握手协议(Handshake Protocol)和变更密码规范协议(Change Cipher Spec Protocol)等。TLS 相关报文协议如下图所示:

TLS报文协议.png

  • RSA 握手是传统的 TLS,并非当今世界的主流握手。如今主流握手是使用 ECDHE 替代 RAS 实现的。

密钥套件

浏览器和服务器在使用 TLS 建立连接时需要选择一组恰当的加密算法来实现安全通信,这些算法的组合被称为密码套件(cipher suite,也叫加密套件)。 命名规范如下:

密钥交换算法 + 签名算法 + 对称加密算法 + 摘要算法
比如 ECDHE-RSA-AES256-GCM-SHA384 理解如下:
- 握手时使用 ECDHE 算法进行密钥交换,
- 用 RSA 签名和身份认证,
- 握手后的通信使用 AES 对称算法,密钥长度 256 位,
- 分组模式是 GCM,
- 摘要算法 SHA384 用于消息认证和产生随机数

ECDHE

RSA 是传统的密钥交换算法,它有如下缺点:

  • 不能"快跑"。也就是说只有当经过 2*RTT 时延后,才允许发送应用数据。
  • 不具备前向安全性。只要被黑客破解一次,前面所发送的数据都可以被破解。

而 ECDHE 算法是目前广泛使用,它能解决上述的两个问题。

DH 密钥协商算法

ECDHE 密钥协商算法是由 DH 算法演进来的,所以我们先从 DH 算法说起。

  • Diffie-He llman 算法,简称DH 算法,是 Whitfield Diffie 和 Martin Hellman 在1976 年公布的一个公开密钥算法,它的历史比RSA 公开密钥算法更悠久。
  • DH 实现的是密钥交换或密钥协商。使用 DH 算法在进行密钥协商时,通信双方的任何一方无法独自计算出一个会话密钥,通信双方各自保留一部分关键信息,再将另一部分信息告诉对方,对方有了全部信息才能共同计算出相同的会话密钥。
  • 数据基础:对于一个整数 bb 和质数 pp的一个原根 aa,可以找到一个唯一的指数 ii ,使得 aimodp=ba^i mod p = b 成立,那么指数 ii 称为 bb 的以 aa 为底数的模 pp 的离散对数。
    • 底数 aa 和模数 pp 是离散对数的公共参数,即被公开的。bb 是真数,ii 是对数,知道了对数 ii,就可以利用上面的公式计算得到真数 bb,但反过来,知道真数 bb 却很验推算出对数 ii。特别当模数 pp 是一个很大的质数,即便知道底数 aa 和真数 bb,在现有的计算机计算水平几乎无法算出离散对数的。

假设 AB 双方使用 DH 密钥协商算法交换密钥,则步骤简单描述如下:

  1. A 选择一个素数 p=509p=509,底数 a=5a=5,生成随机数 ic=123i_c=123,通过离散对数公式 Yc=aicmodp=5123mod509=215Y_c=a^{i_c} mod p = 5^{123} mod509=215。然后 A 向 B 发送 a=5,p=509,Yc=215a=5,p=509,Y_c=215
  2. B 收到后,也生成随机数 is=456i_s=456,然后计算 Ys=5ismodp=5456mod509=181Y_s=5^{i_s} mod p = 5^{456} mod509=181,同时还计算SecretKeys=Ycismodp=215456mod509=121SecretKey_s=Y_c^{i_s} mod p = 215^{456} mod509=121。将Ys=181Y_s=181作为服务端公钥传递给 A。
  3. A 收到 Ys=181Y_s=181,计算 SecretKeyc=Ysicmodp=181123mod509=121SecretKey_c=Y_s^{i_c} mod p = 181^{123} mod509=121得到的结果和 B 计算的相同。

从上面计算过程可知,只要 A 和 B 各自分别生成的随机数 ic=123i_c=123 和 is=456i_s=456 不暴露,黑客知道其他参数是无法暴力破解的。 缺点:静态 DH 算法 a 和 p 两个参数永远是固定的,且服务器的公钥 YsY_s也是固定的,随着时间延长,黑客通过分析海量数据也能暴力破解,也就不能提供前向安全。静态 DH 算法优势是避免在初始化连接时服务器频繁生成 a 和 p 两个参数,因为该过程非常消耗 CPU 资源。

DHE 密钥协商算法

字母 E 表示 ephemeral(临时性的)。既然静态 DH 有被破解的可能,那我就每次进行密钥协商时都随机生成临时的 a 和 p。这样即便破解了某一次通信过程的私钥,其他通信过程的还是安全的。

ECDHE 密钥协商算法

DHE 算法由于计算性能不佳,因为需要做大量乘法,为了提供 DHE 算法的性能,于是出现了现在广泛使用的 ECDHE 算法。

椭圆曲线迪菲-赫尔曼密钥交换(英语:Elliptic Curve Diffie–Hellman key exchange,缩写为ECDH),是一种匿名的密钥合意协议(Key-agreement protocol),这是迪菲-赫尔曼密钥交换的变种,采用椭圆曲线密码学来加强性能与安全性。在这个协定下,双方利用由椭圆曲线密码学建立的公钥与私钥对,在一个不安全的通道中,建立起安全的共有加密资料。临时ECDH(ECDH Ephemeral,ECDHE)能够提供前向安全性。

ECDHE 算法是在 DHE 算法的基础上利用了 ECC 椭圆曲线特性,可以用更少的计算量得到公钥以及最终的会话密钥。双方使用 ECDHE 密钥协商算法过程简述如下:

  1. 双方事先确定好使用哪种椭圆曲线和曲线上的基点GG,这两个参数是公开的。
  2. 双方各自随机生成一个随机数作为私钥 dd,并与基点 GG 相乘得到公钥Q(Q=dG)Q(Q=dG),此时客户端和服务端公钥和私钥分别为(Qc,dc)(Q_c,d_c)(Qs,ds)(Q_s,d_s)
  3. 双方各自交换公钥,客户端计算点(Xc,Yc)=dcQs(X_c,Y_c)=d_c*Q_s,服务端计算点(Xs,Ys)=dsQc(X_s,Y_s)=d_s*Q_c。由于椭圆曲线上是可以满足乘法交换律结合律,所以有推导公式:dcQs=dcdsG<==>dsQc=dsdcGd_c*Q_s=d_c*d_s*G<==>d_s*Q_c=d_s*d_c*G,因此,双方的XX坐标是一样的,XX 并非最终的会话密钥,而是一个预主密钥。

ECDHE握手流程

讲了这么多,现在回到 ECDHE 握手流程,如下图所示: ECDHE_握手示意图.png

  1. 运输层 TCP 通过三次握手建立连接。下面开始进行 TLS 握手流程。
  2. 第一步,客户端率先"发难",通过 Client Hello 握手协议向服务端发送以下内容:
    1. 客户端支持的 TSL 版本号。
    2. 客户端产生的随机数(Client Random)。
    3. 客户端支持的密钥套件列表。
    4. 扩展列表

ECDHE_Client.png

  1. 第二步,服务端收到 Client Hello 后,会返回 Server Hello 消息。里面内容如下:
    1. TSL 版本号。
    2. 服务端随机数。
    3. 确认的密码套件。
    4. 扩展列表。
    5. Server Certificate
      1. 然后向客户端发送 Server Certificate 数字证书,里含有自己的公钥。
    6. Server Key Exchange
      1. 由于服务端选择了 ECDHE 算法,所以会附带这一条消息。里面是椭圆曲线的公钥(Server Params),用来实现密钥交换算法。
    7. Server Hello Done
      1. 随后,服务端发了 Server Hello Done 消息,目的是告诉客户端,我已经把该给你的东西都给你了,本次打招呼完毕。

ECDHE_Server_hello.png

  1. 第三步,客户端响应。客户端收到服务端的 Server Hello 握手协议后,会先进行验签操作:通过浏览器和系统内置的 CA 公钥确认从服务端接收到的签名证书的合法性。验证通过,取出服务端的公钥,后续会使用它来加密客户端生成的 Client Params 椭圆曲线公钥。
    1. Client Key Exchange
      1. 客户端按照服务端所选定的密码套件也生成一个椭圆曲线的公钥(Client Params)。
    2. Change Cipher Spec:之后改用会话密钥加密通信。
    3. Encrypted HandShake Message(Finished):把之前所有发送的数据做个摘要,并用会话密钥加密,服务端通过此摘要验证双方进行 TLS 的过程中的数据是否被篡改过。

ECDHE_CLient_key_exchange.png

  1. 第四步,此时,客户端已经拥有生成会话密钥所有预备数据:客户端随机数、服务端随机数、服务端椭圆曲线公钥 Server Params。客户端椭圆曲线公钥 Client Params。
    1. 通过 Server Params + Client Params 生成 pre-master 随机数。
    2. 再通过客户端随机数 + 服务端随机数 + pre-master 生成主密钥,也就是会话密钥。由于不需要交换 pre-master,所以减少了 0.5 RTT 的等待。
    3. 此时,客户端可以使用会话密钥加密数据并向服务端发送了。
  2. 第五步,服务端最后响应。
    1. Change Cipher Spec:之后改用会话密钥加密通信。
    2. Encrypted HandShake Message(Finished):把之前所有发送的数据做个摘要,并用会话密钥加密,服务端通过此摘要验证双方进行 TLS 的过程中的数据是否被篡改过。

RAS 和 ECDHE 区别

  • RAS 不支持前向保密,ECDHE 支持前向保密(多了 E)。
  • RAS 不支持** False Start(抢跑)**,而 ECDHE 支持。可以在第四步之后、第五步之前发送加密的应用数据,以此将 TLS 握手的消息往返由 2*RTT 减少到 1 * RTT。

优化 HTTPS

重放攻击

假设中间人通过某种方式,截获了客户端使用会话重用技术的 POST 请求,通常 POST 请求是会改变数据库的数据,然后中间人就可以把截获的这个报文发送给服务器,服务器收到后,也认为是合法的,于是就恢复会话,致使数据库的数据又被更改,但是此时用户是不知情的。 避免重放攻击的方式就是需要对会话密钥设定一个合理的过期时间。

参考

https原理--ECDHE密钥协商算法