写点什么

HTTPS TLS 1.2

作者:懒时小窝
  • 2022 年 9 月 12 日
    广东
  • 本文字数:19366 字

    阅读完需:约 64 分钟

HTTPS 概念

在个人过去的读书笔记中已经介绍过一次,在这一篇文章中介绍了 HTTP1.1 的缺点,以及 SSL、TLS 的历史,之后介绍了有关 SSL 加密的主要加密方案:公开密钥加密共享密钥加密,最后简单介绍了 HTTPS 的交互过程,但是书中的过程比较粗,这节我们讲细一点点。


相关文章:[[《图解 HTTP》 - HTTPS]]


本部分会简化介绍重复的部分,补充笔记中没有完善的细节。


这些内容比较八股又干又硬,建议仔细阅读消化。

如何定义“安全”

定义安全靠的是下面几点:


  • 完整性:也叫做数据一致性,指的是传输过程自出发到接受的信息是一致的。机密内容可以被黑客替换或者删除添加,一旦被接受并且核验通过,会带来大问题。

  • 机密性:对于数据保密之后,只有信任的对象可以访问,其他人哪怕拿到保密信息,也无法识别出里面的内容。

  • 身份认证:身份认证需要明确的证实对方身份,比如报警的时候要求警察出示身份证据,并且看到盖章许可文件才允许进入,不然黑客冒充的,不管怎么防都没有用。

  • 不可否认:指的是发生的事情不能进行诋毁,某一项操作必要在通信完成之后产生一定影响。否则就是类似访问一个看起来极其逼真的网站但是却是一个空壳,空壳后面直接把你的个人信息套走。

HTTPS 解决的问题

HTTPS 解决了什么问题?我们介绍 HTTP 的主要问题,以及如何解决这些问题的。


HTTP 的主要问题:


  • 信息加密:保证敏感信息不会被窃取。

  • 身份校验:数据完整性保证,数据无法篡改,篡改之后无法正常使用。

  • 身份证书:证明服务端是真实具备公信力的。


如何解决这些问题:


  • 信息加密:使用双层加密机制,连接使用非对称加密,同时在连接之后使用对称加密,双保险的混合加密保证安全。

  • 摘要算法:保证数据的完整性,TLS 协议主要推荐使用 SHA-2“集合”下面的加密算法,相当于给数据生成一个解锁指纹。

  • 身份证书:服务器公钥放入数字证书,自己再使用私钥再加密一遍进行传输,防止被人冒充。


除了上面三点之外,还有一点“不可否认“,但是严格意义上并不是 HTTPS 本身的“功劳”:


  • 不可否认:CA 证书颁发机构本身具备权威及公信力,一旦服务端被声明存在,那就是一定存在。

HTTP 和 HTTPS 的区别

  • HTTP 是明文传输,在传输一些敏感信息的时候可能存在窃取信息的情况。

  • HTTP 连接相对效率更高,因为它只需要三次握手就是完成连接操作,而 TLS/SSL 需要多加入四次握手才能完成连接。HTTPS 整体需要耗费更多的连接时间。

  • HTTP 的端口默认是 80,SSL 默认端口为 443。

  • HTTPS 客户端发送公钥需要向 CA 申请数字证书签名,保证公钥安全传输到客户端。

SSL/TLS 历史

关联:[[《图解 HTTP》 - HTTPS]] #SSL/TLS 历史


可以直接阅读笔记的“SSL/TLS 历史”部分,个人在笔记中对于 SSL/TLS 之间的关系,以及 SSL/TLS 进化历史做了一个概述,当然这些内容也可以直接去“维基百科”看相关介绍,里面有更加专业和权威的解释。

TLS 含义

TLS 由记录协议、握手协议、警告协议、变更密码规范协议、扩展协议等几个子协议组成,综合使用了对称加密、非对称加密、身份认证等许多密码学前沿技术。


浏览器建立 SSL 协议连接,实际上就是使用多个子加密协议组合,最终选择合适的加密算法进行数据安全传输,这种算法组合本身被叫做“密码套件”。


此外 TLS 的密码套件命名看起来很长,但是实际上非常规范,格式很固定。基本的形式是“密钥交换算法 + 签名算法 + 对称加密算法 + 摘要算法”。


比如:ECDHE-RSA-AES256-GCM-SHA384 所表示的含义为:


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

数字加密历史

数字加密的是在计算机出现以及专业的密码机出现之后诞生,但是实际上密码学有了上千年历史,下面我们依照《HTTP 权威指南》中 14.2 节的介绍大致回顾数字加密历史。


本部分为了解数字加密的技术和术语,如果已经了解了或者不感兴趣可以直接跳过。


数字加密的发展大致经历了下面的过程:


密码

密码通常是一套固定编解码规则的加密信息,被编码之后文本信息被叫做密文。比如我们用 AAA 代替阿拉伯数字 1,BBB 代替阿拉伯数字 2,C....这样的规则组织出一套针对阿拉伯数字的加密,在加密的时候用密文进行替换。


  • 加密前:9112955

  • 加密后:IIIAAAAAABBBIIIEEEEEE

密码机

早期的密码都是十分简单的,掌握规律之后很容易破解,而密码机是把加密规则从明文本身“剥离”的一种改进。原本针对一套文本的加密规则,后面使用了专门负责加密的密码机,负责更加复杂的加密算法处理,这些规则加解密单靠人力对抗密文已经比较难,所以安全性更高一层。

密钥加密

但是随着技术发展,人们发现使用密码机加密有一个漏洞,一旦密码机被盗或者被仿制,那么加密规则就失效了,经典案例来自二战时期的德国密码机被图灵攻破。


所以在二战之后又发明了一种可以自由改动加密规则的带有号码盘的密码机。简单来说就是给密码机本身又上了另一套加密规则。


被加锁之后的密码机,需要特殊的钥匙解锁才能正确的翻译密文,否则会被翻译乱码或者毫无规律的解密信息,密码密钥会让多个密码机看起来像是虚拟的密码机一样,每个密码机又不同的数值,他们需要配合在一起才能正常解密加密信息。


这就有点像是把一个解密的钥匙掰成很多份,每份钥匙上又有很多杂乱无章的齿,所以难以破解。


密码和密钥很容易被混为一谈,其实他们是类似“包装”的关系,密钥是对于加解密规则进行“乱序”,保护密码和加解密规则本身的手段,目的是即使被拿到加解密方法也没法正确的还原解密之后的信息。

数字密码

数字计算围绕两个主题:


  • 计算机的飞速发展,复杂的编解码规则实现。

  • 超大密钥难以破解,可以从一个加密算法产生数万亿的虚拟加密算法,组合出不同的密钥。密钥越长,随机猜测的难度越大。


通常编解码的函数为反函数,也就是说通过加密函数加密 P,再通过解密函数解密 P,会得到原始报文 P。下面是关于数字密码加密的例子:


给定一段明文报文 P、一个编码函数 E 和一个数字编码密钥 e,就可以生成一段经过编码的密文 C。通过解码函数 D 和解码密钥 d,可以将密文 C 解码为原始的明文 P

对称加密

密钥和密码的配合,最初形成是类似原有密码的对称加密手段。对称加密说的是所用的加密密钥和解密密钥都是同一个,比较流行的算法包裹:DES、Ttriple-DES(3DES)、RC2 和 RC4、ChaCh20、AES。


但是需要注意 RC4(RC2)、DES、3DES,这几种对称加密方法都是不安全的,通常禁止使用,所以还剩下 AES 以及 ChaCh20


  • AES: 的意思是“高级加密标准”(Advanced Encryption Standard),密钥长度可以是 128、192 或 256 或者更长。

  • ChaCha20: 是 Google 设计的另一种加密算法,密钥长度固定为 256 位,纯软件运行性能要超过 AES,在 ARMv8 引擎升级之后,AES 也飞速提升被反超。所以现在来看虽然优势不大,但是依然不错的一个算法。


因为是对称密钥加密,所以只需要双方持有相同的密钥,并且协商好密码的加解密规则,就可以完成对称加解密。


密钥长度的重要性目前大部分情况下除非完全自己写加解密算法,否则大部分的加解密的密码算法都是“透明”的,所以现在安全的反倒是密钥。通常的加密算法破解手段是利用穷举组合密钥的方式去“试”,这也意味着越长的密钥越安全,但是所需要的计算机资源相对也会更多。在密钥出现的早期,很短的密钥就可以满足加密算法的保护,但是到了现在随着超级计算机出现以及 CPU 效率的提升,密钥的长度已经来到了 SHA-256


关于密钥长度以及破解需要的代价对比,哪怕是 1995 年的数据,放到现在依然有一定的价值,因为目前 SHA-256 依然没法在短时间破解。



对称加密的最严重问题除了是密钥本身容易,还有一点是密钥共享和本身的管理问题,因为共享密钥需要传给 ABCDEFG,一旦出现更改又要重新传一遍,这导致有的人用的旧密钥,有的使用新密钥,这样做法管理起来非常麻烦。

公开密钥加密

共享密钥本身的管理问题以及安全问题,后续出现了使用非对称的加密方案,所谓非对称加密就是说加密的密钥是公开对外开放使用的(不用向共享加密一样藏着掖着),所有人都可以拿到这份公开密钥加密内容,但是加密过后的信息,除了发布者知道之外都是保密的。


公开密钥加密在共享加密的基础上做了升级,改进了密钥数量膨胀问题。公开密钥架构(Public-Key Infrastructure,PKI)标准创建工作已经开展十多年了。因为非对称的加密算法要难非常多,所以在 TLS 里面可以看到的有下面几种:


  • DH

  • DSA

  • RSA

  • ECC


在这几个加密算法当中 RSA 可能更熟悉一些,它的算法思路是“整数分解”的数学界难题,意思是说两个超大素数的乘积作为加密材料,要想通过公钥推算出私钥是非常难的。


在过去 RSA 的长度为 1024、到了现在则是 2048,因为 1024 长度已经不安全的,往后可能需要更长的长度才能确保安全。但是 RSA 到了现在实际上也已经不安全。


ECC(Elliptic Curve Cryptography)是继广泛流传的 RSA 之后的一种“椭圆曲线离散算法”的数学难题,使用特定的曲线方程和基点生成公钥和私钥,子算法 ECDHE 用于密钥交换,ECDSA 用于数字签名


ECC 目前比较常用的两个曲线是 P-256(secp256r1,在 OpenSSL 称为 prime256v1)和 x25519。P-256 是被 NIST(美国国家标准技术研究所)和 NSA(美国国家安全局)推荐使用的曲线,X25519 则是被认为是安全的、快速的曲线。


ECC 的椭圆曲线实际上并不是椭圆的,而是方程类似椭圆的周长公式,实际的形状更像是两个抛物线。


ECC 与 RSA 对比

首先,针对 RSA 的算法公认的破译难度是亚指数级别的,而 ECC 的破译难度是指数级别的。其次 ECC 所需的加密密钥长度要比 RSA 缩短好几倍,比如 1024 的 RSA 相当于 160 位的 ECC,224 位的 ECC 则相当于 2048 位的 RSA。因为密钥的长度合适,所以十分受欢迎。


需要注意虽然 ECC 很快了,但是和对称加密的几个算法比起来还是差了好几个量级,比如下面的测试报告:


aes_128_cbc enc/dec 1000 times : 0.97ms, 13.11MB/s
rsa_1024 enc/dec 1000 times : 138.59ms, 93.80KB/s
rsa_1024/aes ratio = 143.17
rsa_2048 enc/dec 1000 times : 840.35ms, 15.47KB/s
rsa_2048/aes ratio = 868.13
复制代码


通过对比可以看到,AES 加密是非常快的,只需要纳秒级别的时间,而 2048 位的 RSA 需要它的几百倍。


所以这也是为什么 TLS 需要使用对称加密和非对称加密混合使用的根本原因,如果全部按照非对称加密传输,那么页面的传输响应时间可能要凭空多出几秒,这对用户来说是无法接受的。

数字签名

数字签名是除开对于报文加解密的另一种思路,签名的目前是保证数据一致性和防篡改。同时签名可以数据的所属来源是否真实可靠。


产生数字签名的方式实际上还是 公开密钥加密,但是把思路反过来了,数据是通过私钥进行加密的,只有公钥可以解锁。


数字签名通常会在传输之前双方各持有一份,传输的内容在中间被破解并且被篡改,在收到后可以先拿公钥解密验证一下,然后再取出数字签名匹配一下,如果其中任意一方匹配不上,那就可以说明传输的数据被人篡改了,又因为私钥是保密的,黑客没法伪造签名,只能干巴巴看着到嘴的肉飞走~~



数字签名通常是使用单向加密的摘要算法,摘要算法主要负责计算内容的哈希值(HMAC),这个哈希码是唯一的,并且无法反向推导。


我们可以把摘要看作是一个指纹,在哈希算法中可以保证指纹不会被篡改,但是这里显然有一个漏洞:虽然不能改签名,但是可以换签名和内容


所以单纯的摘要算法只能保证数据完整性,但是不能保证数据安全,为此就需要加入非对称加密算法,加强双向数据的传输。


非对称加密通常需要两个钥匙,一把私钥由自己保管,公钥可以对外开放使用。密钥可以双向破解,也就是可以私钥加密,公钥解密,也可以公钥加密,私钥解密。


处理方式不同,其实现的效果也不一样:


  • 公钥加密,私钥解密(机密性):公钥加密的数据只能被私钥破解,这样保证数据的安全。

  • 私钥加密,公钥解密(完整性):私钥加密的数据只能被公钥解析,私钥加密的数据一旦被篡改或者替换,公钥解密之后可以证明数据的是否符合要求。


数字签名实际的使用过程是这样的:【(私钥加密+ 摘要算法),公钥解密 】,需要注意私钥加密的并不是原始内容,而是被摘要算法计算过的指纹(也就是 HMAC 值)。


这样也就实现了双保险,但是这样的双保险还是存在风险,我们可以看看下面这个攻击过程:


  1. 客户端向服务端索取公钥进行通信,此时黑客从中间插手,伪造一对公钥和私钥,然后继续向服务器获取公钥。

  2. 服务器误以为是客户端发来的,所以果断加密信息然后返回公钥。此时黑客拦截,黑客压根不用管怎么解密这些内容,此时它用自己的【私钥+数字签名】伪造一份数字签名,然后发给客户端。

  3. 客户端拿到被伪造的公钥,使用公钥加密后续通信使用的对称密钥,传给服务端。

  4. 中间人截取请求,用自己的私钥解密信息, 拿到对称密钥,然后仿照客户端的请求使用真实公钥加密自己伪造的对称密钥。

  5. 服务端使用私钥解开之后,得知对称加密算法,然后开始和黑客进行正常通信。

  6. 黑客鸠占鹊巢,成功破解,这时候黑客既可以利用伪造的身份从服务器获取信息,也能伪装成服务器向客户端发送一些虚假信息,这样实在是危险。


为了简化理解,我们可以简单把上面的步骤抽取出下面几个关键点。



数字签名只解决了关于安全的两个方面问题,所以实质无法保证安全通信。所以很无奈,既然怕你们乱来,那只好设置一个授权机构,以后客户端可以找我核实对方身份,而服务端需要我这里的文书才算是真的认可。

数字证书

数字证书是无止尽加解密的最后一道关口,数字证书通常包含了某些组织或者某些公司的相关信息。数字证书也可以看作是数字签名的进步版本,也是解决无穷无尽的加密套娃的最终解决方案。


数字证书的概念在生活中比较常见,可以想象为美国电影里面搜捕公民的房间需要向上级申请搜捕令才能进入。


数字证书是目的防止 HTTPS 加密中密钥被篡改的“无限套娃”加密的问题,因为数字签名和密钥信息需要传输,中间必须要有一个足够可靠的第三方伙伴证明。


这个认证过程被称之为 CA 认证,客户端收到包含 CA 数字证书签名的服务端的请求之后(私钥加密),通过用浏览器内置的 CA 证书公钥解密,只要证书通过校验,就可以认为服务端是稳定的。


通过上面的解释我们知道,客户端和服务端的在 SSL 握手中的非对称加密方法是是公钥加密,私钥解密,数字签名的摘要作为防篡改校验。


而数字证书的用法则是把这个过程反过来,变为私钥加密、公钥解密。并且利用需要数字证书给数字签名再加个章,这样的效果相当于是一个三方校验。


所以你数字证书的授权机构怎么保证自己靠谱呢?我们从下面几个点来进行说明:


  1. CA 如何证明自己?

  2. CA 证书的格式以及标准。

  3. 证书的弱点。

  4. 传输过程中 CA 证书被篡改或者被替换,如何进行加密传输认证。

CA 如何证明自己?

CA 证书目前比较知名和权威的也就那么几家,DigiCert、VeriSign、Entrust、Let’s Encrypt 等,它们之间的区别在于可信程度。证书分为 DV、OV、EV 这几种,DV 是可信程度最低的,可以说连背后是谁都不知道,EV 是最高的,它需要接受最高法院的法律审查,可以证明网站的实际拥有者。


但是 CA 又要怎么证明自己呢?


CA 证书通过信任链证明自己,首先根证书开始,向下逐渐找到信任程度更弱的中间 CA 机构,通过层信任的方式找到最终的 CA 证书颁发机构进行验证。


无论如何认证,CA 认证最终总会走 ROOT 根证书,ROOT 也可以叫做自签名证书,这个是需要强制相信的, 否则自证明的体系是走不下去的。这种自证体系有点像是如何保证最高法院的权威性一样,CA 本身包含机器严格的保护措施。


下面这个图也可以说明,实际上根证书是最重要的,客户端和服务端绝对不能泄露根证书,否则 CA 的体系和 HTTPS 都会不攻自破。



浏览器的 Security 的 CA 证书中,也可以看到类似结构:最上层 Root 是根证书,GlobaSync 属于中间证书,最底层是具体服务器的证书。


这个层层信任是咋个信任法?其实也挺简单的,那就是上级持有下一级认证的公钥,先验根证书,然后从根证书拿到下一级证书的公钥,往下找中间证书层层认证


我们以 B 站的校验过程为例:


  • 首先待验证的网站是 bilibili.com,首先找到上级证书 GlobaSIgn RSA SSL CA 2018,再找 GlobaSIgn RSA SSL CA 2018 它的上级证书 GlobaSign Root CA - R1,这个证书是没有上级的,所以可以认为是根证书。

  • 既然 GlobaSign Root CA - R1 是根证书,那么一般情况下浏览器或者操作系统会内置证书,如果发现内置证书,比如下面就会取出 GlobaSign Root CA - R1 的公钥,验证 GlobaSIgn RSA SSL CA 2018 是否可信,如果验证通过,说明 GlobaSIgn RSA SSL CA 2018 这个中间 CA 是可以信任的。

  • 既然 GlobaSIgn RSA SSL CA 2018 是可以信任的,那么也同样取出公钥认证 bilibili.com 是否合规。


可以看到 B 站的认证体系有不少年头了。


整个 CA 认证体系最终形成一条信任链条,可以证明网站是合法的了。



从上面的图可以看出,为了验证 CA 的合法性,会从上级一路向下去验证合法性。另外,如果我们自己捏造自证证书注册到操作系统内(Linux 利用 OpenSSL 命令),用浏览器打开会发现这个证书是不会受到 Google 浏览器信任的(因为浏览器不承认),并且会提示“此网站不受信任”。

证书具体认证过程

证书认证包含两种情况,一种是客户端认证 CA 证书的流程,另一种是 CA 证书自证流程


客户端认证 CA 证书的流程这里直接放一张小林做的图,非常直观的展示了 CA 如何配合信息加密完成整个 HTTPS 加密传输。个人为了方便记忆,抽象的步骤如下:


  1. 服务器注册公钥到 CA。

  2. CA 私钥加密对于服务器公钥数字签名颁发数字证书。

  3. 客户端收到数字证书,使用 CA 公钥(浏览器内置)解密。然后使用数字签名验证是否存在篡改。

  4. 通过数字证书取到服务器公钥,使用服务器公钥进行非对称加密。



然后是服务器自证过程,前面提到 CA 证书是多层嵌套的自认证体现,为了保证 CA 证书的安全,根证书是 CA 认证的起点也是最核心的一环,以 B 站的证书为例,整个认证的体系如下:


操作系统或者浏览器认证顺序:内置证书 -> GlobalSign Root CA -> GlobalSign RSA OV SSL CA 2018 -> *.blibli.com



为什么非对称加密之后,还需要使用摘要算法计算出一个哈希值?

其实非对称加密足以保证安全了,加上 CA 证书基本可以万无一失,而使用摘要算法计算哈希值,实际上是考虑导效率问题,因为内容长度的匹配比较耗费性能,而哈希可以是固定长度的唯一值,哈希值匹配的效率要高出很多。

此外非对称加密可以加密的消息体长度有上限(public key length in bits / 8 - 11),否则会报错,所以必须先 hash 保证定长结果。

CA 证书的格式以及标准

CA 证书当然并不是直接给服务器私钥上套个签名就完事了,CA 的证书格式有着极其严格的规范和要求,下面是 CA 证书主要包含的信息:


• 对象的名称(人、服务器、组织等);• 过期时间;• 证书发布者(由谁为证书担保);• 来自证书发布者的数字签名。


虽然 CA 证书在刚面世的时候没有严格的全球规范标准,但是随着后续的发展目前 TLS1.2 被公认的证书格式是 X509,

X.509 v3 证书

X.509 证书字段包含下面的内容:




我们可以通过具备 HTTPS 安全连接的网站,通过 F12 的方式查看证书,比如 B 站的证书信息如下:


证书的弱点

世界上没有绝对安全的事情,CA 证书也不例外。CA 证书的弱点在于自身的可靠性,比如给不受信任网站颁发受信任的证书,或者给 CA 证书本身被伪造,那么所有的防护都是一层纸, 所有信任链也就不存在了。


这些事情都是过去真实发生过的,感兴趣可以上网查找相关资料。比如很多年前 MCS 集团用 CNNIC 签发的中级证书,发行了多个冒充成 Google 的假证书。于是在 2015 年 4 月份,chrome、firefox 都宣布不再信任 CNNIC 的证书,这件事情的影响十分恶劣,后续证书已经被 CNNIC 整顿并且被替换为合法的网站。


那么 CA 机构是如何解决这签错网站和本身受到污染这两个问题的?


  • “签错”网站:利用 CRL(证书吊销列表,Certificate revocation list)和 OCSP(在线证书状态协议,Online Certificate Status Protocol),及时废止有问题的证书。

  • CA 本身被污染:所有 CA 全部停止工作,浏览器把被攻克 CA 拉入黑名单。CA 本身被入侵的可能性很低。

传输过程中 CA 证书被篡改或者被替换,如何进行加密传输认证?

被替换和被篡改 CA 证书是经常被提到的两个问题,我们来一一解答:


篡改证书


假设证书在传输过程被黑客篡改,黑客是没有 CA 的公钥的,,因为 CA 公钥一般再客户端的浏览器内置,自然无法破解签名,如果把数字签名改掉,浏览器收到请求通过验签手段对比解密之后的签名,发现原文不一致,也就自然发现了问题。


证书替换


证书替换还要分为两种情况,一种是自己伪造的证书,另一种是真的骗过 CA 搞了一份真的证书。


伪造证书这个事情,黑客能干,其实用户自己也能随时干。但是毫无疑问在浏览器以及操作系统,自证的证书的是不受到认可,所以通常情况下客户端收到这些伪造证书都会立马判断出证书被人篡改过的事实。


那如果黑客煞费苦心,真的用合法的另一个网站拿到一份 CA 认可的证书,直接把证书替换了怎么办?


这时候客户端收到的证书确实是真的证书,也确实会拿到错误的公钥,但是不要忘了数字证书还有被颁发者的其他信息,比如域名是造不了假的,比对一下就出现问题了。


这里可能又会问,CA 自己“黑吃黑”,本身被污染了怎么办?不能怎么办,这时候浏览器会把 CA 拉黑,CA 所有的服务也会停止。在国内这么干是找死,而在国外.....你得有本拉登的逃命实力。


CA 证书被黑客入侵本身就是互联网地震,这种时候坐着吃瓜就好了、


证书内容


在 RFC 的 TLS1.2 的原文当中,有这么一句话:


The certificate type MUST be X.509v3, unless explicitly negotiated


这个 X.509 v3 证书是啥?X509V3 是用于 TLS1.2 加密的公认标准,它提供了一种标准的方式, 将证书信息规范至一些可解析字段中。虽然有的证书机构会有个别字段不一样,但是整体上还是使用 X509V3 格式。


这里引用一段维基百科的介绍:


X.509 是密码学里公钥证书的格式标准。X.509 证书已应用在包括 TLS/SSL 在内的众多网络协议里,同时它也用在很多非在线应用场景里,比如电子签名服务。X.509 证书里含有公钥、身份信息(比如网络主机名,组织的名称或个体名称等)和签名信息(可以是证书签发机构 CA 的签名,也可以是自签名)

HTTPS 的主要改进

关于 HTTPS 的改进我们再次简单回顾之前的内容:


  • 编解码的过程时在 SSL 层完成的,HTTP 层不需要做出过多的改变,就可以完美兼容 HTTPS。

  • 传输由原来的直接通过 HTTP 传输给 TCP,到建立安全连接之后,从 HTTP 先传输到 SSL 层进行编码,然后传输到 TCP 层。

  • 使用双重加密:对称加密算法、非对称加密算法以及通过数字证书保证,防止中间人攻击。

  • 摘要算法:使用 SHA-256 等长密钥的加密方式,对于数据的完整性保护,一旦被篡改,数据无法通过校验。


HTTPS 简单来说就是在不改动 TCP/IP 模型的情况下,在应用层和安全层中间加入了一层安全层。



下面时针对 HTTP 和 HTTPS 的传输过程对比图:



下面我们深入到 HTTPS 1.2 的细节,了解 TLS1.2 的建立过程。

RSA 和 ECDHE 算法区别

现代互联网都是使用 ECDHE 进行密钥交换算法,这里补充和 RSA 交换算法的两个关键差别点。


第一个,因为用到了密钥交换算法,所以传输过程中 ECDHE 会多出Server Key Exchange这个步骤。


第二个,因为使用了 ECDHE,客户端可以不用等到服务器发回“Finished”确认握手完毕,立即就发出 HTTP 报文,省去了一个消息往返的时间浪费。这个叫“TLS False Start”,意思就是“抢跑”,和“TCP Fast Open”有点像,都是不等连接完全建立就提前发应用数据,提高传输的效率。


TCP Fast Open 是加速打开两个端点之间连续 TCP 连接的扩展。它通过使用 TFO cookie(一个 TCP 选项)工作,TFO cookies 是存储在客户端上的,并在与服务器初始连接时设置的加密 cookie。换句话说,TFO 是 TCP 中的一种可选机制,它可以让过去创建完整 TCP 连接的端点取消握手步骤的往返,并立即发送数据。主要提高了接续通信的速度,主要是针对首字节时间高延迟网络特别有益。

HTTPS 1.2 建立连接

HTTPS 的核心是 TLS 协议,下面就结合 TLS 协议了解一下协议的组成了。

TLS1.2 协议组成

我们从 TLS1.2 协议组成说起:他的协议号是 RFC5246。网址为:https://www.ietf.org/rfc/rfc5246.txt


   Four protocols that use the record protocol are described in this document: the handshake protocol, the alert protocol, the change cipher spec protocol, and the application data protocol.
复制代码


从官方介绍来看,TLS1.2 主要由四个协议组成,也就是说一共有四份子协议:


  • 记录协议(Record Protocol)

  • 警报协议(Alert Protocol)

  • 握手协议(Handshake Protocol)

  • 变更密码规范协议(Change Cipher Spec Protocol)


记录协议(Record Protocol)


记录协议规定了 TLS 传输的基本单位是记录(record),record 可能包含长度,描述和内容,有点类似 TCP 的 Segament 的概念,通用是可以进行分块传输的。同样 record 具备分块、压缩、编码、解压缩、重组等等和 TCP 分块类似功能。


和 TCP 不同的是,TLS 可以把多个记录一次性放到 TCP 里面进行传输,并且不需要返回 ACK。


此外,这个协议还规定了安全通信的能力:


  • 可靠连接。使用 MAC(Message Authentication Code,消息验证码,TLS 目前使用的 HMAC 也属于 MAC 的一种)为数据提供完整性校验。同样,在握手阶段也可以不使用该功能。

  • 私有连接:比如对称加密使用的 AES CHACHA20(协议中列举的几个后续被证明不安全),对称加密的密钥是不固定的,但是需要注意 Record 协议也可以提供不加密的封装,比如在握手阶段的 Hello 报文。


意味着整个连接过程是“可定制化”的,很多参数都是可选的,这些内容将会在下文介绍。


警报协议(Alert Protocol)


警报协议通常在传输出现问题的时候起到警示作用,警报协议用于终止一些存在危险隐患的请求,有点类似 HTTP 状态码,我们可以举几个例子方便理解:


  • bad_record_mac:错误的 MAC 地址

  • decode_error:解码异常

  • protocol_version:表示旧版本不受支持


握手协议(Handshake Protocol)


用于协商会话的安全属性,通常被封装在一个或者多个 TLSPlaintext 的结构中,简单来说主要是指定当前会话状态。


   struct {       ContentType type;       ProtocolVersion version;       uint16 length;       opaque fragment[TLSPlaintext.length];   } TLSPlaintext;
复制代码


握手协议是整个 TLS 里面最复杂也是最为核心的部分,当然也是真正天天都在用的协议,在这里定义了 TLS 握手协议,随机数以及密码套件等等信息,规定了整个 TLS 握手的细节。


握手协议的主要内容可以分为下面三点:


  • 身份认证:指的是利用 CA 端进行身份认证,身份认证的过程会用到非对称加密算法,比如 RSA 算法,注意 HTTPS 支持客户端和服务端双向认证,默认是服务单单向认证,客户端认证是可选的。

  • 安全参数协商:安全参数认证指的是保证被认证数据的机密性,需要用到比如哈希算法、密钥、加密算法等算法,对于数据加密处理。

  • 可靠协商:可靠协商指的是防止数据传输过程中被篡改。


握手协议定义了这些命令:ClientHelloSeverHelloCertificateServerKeyExchangeCertificateRequestServerHelloDoneClientKeyExchangeCertificateVerifyChangeCipherSpecFinished


变更密码规范协议(Change Cipher Spec Protocol)


主要用在握手阶段的协议,通知对方在出现这个标识之后,所有的内容都将会使用密文进行传输。接下来来看看整个握手的流程,RFC 用极简风格演示了整个 TLS 握手协议,丑是丑了点,但意外的特别好懂。



Application Data 协议


除开上面四个主要协议之外,还有Application Data 协议。


Application Data 协议用在通信阶段,封装了应用层的数据,通过 Record 协议封装之后,再通过 TCP 协议转发出去。


此协议用于握手连接完成之后的数据传输规范,实际上可以看作是 SSL 和 TCP 的协议的对接。

TLS1.2 协议握手流程

#HTTPS 通信步骤


这里有必要强调是 TLS1.2 协议握手流程,因为 TLS1.3 协议对于很多细节和内容进行了简化,这些内容将在后续内容继续介绍。


这里我们填一下在[[《图解 HTTP》 - HTTPS]]的读书笔记中埋下的坑,在这本书中仅仅对于 HTTPS 传输做了大致的介绍,并没有深入到各个步骤的细节内容,下面就根据每一步来解释更加详细的传输步骤。


首先我们应该明白,HTTPS 需要四次握手,一共需要在客户端和服务端之间来回两次,才能确定一个 HTTPS 的连接是安全的。


这部分内容建议结合 WireShark 介绍 TLS1.2 加密的实验,目前网络上大部分的资料介绍的都是 TLS1.2 的加密过程。


之前从数字加密的历史以及 HTTP 到 HTTPS 的历史以及 SSL/TLS 的历史梳理了大概。现在我们从 RFC 协议的规范层面,来看看 HTTPS 连接是如何定义的。


首先给出 RFC 中的流程定义,官方给了两个版本,第一个版本包含完整的请求,而第二个版本则是交互步骤中必须经过的过程。



master_secret = PRF(pre_master_secret, "master secret",ClientHello.random + ServerHello.random)[0..47];


  • 表示可选发送的可选消息或取决于情况而必须 消息。


简化之后的版本如下:



接着我们再画一个整个 HTTPS 的交互流程图,这是本次内容的重点



补充:截图完发现 4-START 第四次握手这里是开始,不是结束 =-=。


整个流程还是有点点复杂的,但是拆分成四次握手,记住一些核心步骤并不难理解。

TCP 三次握手

TCP 三次握手的流程图这里还是用的之前已经画过的:



  • 第一步:客户端主动打开 TCB 端口,服务器被动打开 TCB 端口。客户端作为发起方携带一个 SYN 标志,并且携带一个 ISN 序号 Seq=x,但是需要注意的是第一步的过程这个 ISN 序号是隐藏传递的(因为没有传递数据),因为如果请求不存在数据的交换则不会被显示。客户端发送 SYN 命令之后进入设置 SYN=1,并且设置自己的状态为 SYN-SENT(同步-已发送状态)

  • 第二步:服务器收到客户端 TCP 报文之后,也将 SYN=1,并且回送一个新的 ISN 序号 ack=x+1,并且将 ACK=1 表示自己收到了,然后在返回参数回送自己新的序列号表示自己的确认请求 Seq=y,将状态设置为 SYN-RCVD(同步收到)状态,(表示希望收到的序号为 xxxx1522),最后也是指定 MSS。

  • 第三步:客户端收到服务器的确认报文之后,还需要向服务端返回确认报文,确认报文的 ACK=1,并且回传服务器传递的 ISN 序号+1(ack = y+1),以及自己的 ISN 序号+1(Seq = x+1),此时 TCP 连接进入已连接状态。注意 ACK 是可以携带数据的,但是如果不携带数据则不消耗序列号。

  • 最后一步:当服务器收到客户端的确认,也进入已连接状态。


经过 TCP 三次握手连接建立,直到断开连接之前都可以传递数据,TCP 构建之后,则开始进行 SSL 握手。

HTTPS 第一次握手


首先,客户端会发送一个 ClientHello 的请求,同时传递 SSL 握手需要的一些必要参数,主要的字段参数如下:


  • client_version:客户端支持的 TLS 版本号

  • client_random:客户端生成的随机数,是后续对称加密密钥的必要参数之一。

  • session_id:如果客户端想要重用 HTTPS 会话,则在连接的时候需要携带此参数,否则为空。

  • cipher_suites:列举客户端支持的加密套件,也是让服务端选择加密方式的参考。如果 session_id 字段不为空(暗示恢复会话请求),则这个字段必须携带。

  • compression_methods:客户端支持的压缩会话列表,如果 session_id 字段不为空(暗示恢复会话请求),则这个字段必须携带。

  • extensions:扩展字段,为了方便以后扩展新字段,或者协议对接方需要自行扩展协议使用。也就是所谓的留后门。extensions 字段 TLS1.3 重要兼容字段


扩展字段需要着重记忆,因为 TLS1.3 的核心部分。


第一次握手以客户端质询服务端是否支持 HTTPS 为开端,给出一些自己可以提供的参数作为参考,大致的意思是“你好,我想要进行 HTTPS 连接,请问您这边可以支持么”。


ClientHello 属于子协议 handshake 的一部分。


另外附带 RFC 协议的结构体定义,比文字描述来的直白很多:


struct {          ProtocolVersion client_version;          Random random;          SessionID session_id;          CipherSuite cipher_suites<2..2^16-2>;          CompressionMethod compression_methods<1..2^8-1>;          select (extensions_present) {              case false:                  struct {};              case true:                  Extension extensions<0..2^16-1>;          };      } ClientHello;
复制代码


服务器收到 ClientHello 请求,如果它可以支持则会回送 ServerHello 响应内容,同样需要回送相关字段,表示自己认识这些内容:


  • server_version:为了向后兼容,服务端会根据客户端的 client_version 选择合适的以协议 SSL 通信。

  • server_random:服务端独立于client_random 独自生成。也是加密密钥的关键参数。

  • cipher_suite:默认从cipher_suites选择合适的加密套件。

  • compression_method:从客户端传递的压缩算法列表,同样从中选择合适算法。

  • extensions:扩展内容


ServerHello 也属于子协议 handshake 的一部分。同样是结构体定义,比较直观:


struct {          ProtocolVersion server_version;          Random random;          SessionID session_id;          CipherSuite cipher_suite;          CompressionMethod compression_method;          select (extensions_present) {              case false:                  struct {};              case true:                  Extension extensions<0..2^16-1>;          };      } ServerHello;
复制代码


服务器收到请求之后会进行相关答复,他对客户端说“你好,我支持 XX 协议,我看到了你给我的信息,经过考虑我将使用 XX 加密算法,XX 压缩算法.....”


第一次握手是试探性的问候一些双方是否可以支持 HTTPS,是一种高效验证手段。

HTTPS 第二次握手


第二次握手是服务端开始的,ServerHello 发送完成之后接着他需要传递 Certificate(非对称加密公钥) +数字证书给客户端进行 CA 认证。


CA 认证


在 CA 认证的步骤中,首先是服务端如何组织证书,这里又回到X509 V3的证书格式,可以大致总结出数字证书的关键字段:


  • Version:X509 证书版本,目前大部分都是 3 这个数字;

  • Serial Number:每个 CA 生成的数字证书都需要有一个唯一序列号。这个序列号的意义在于一旦某个数字证书被破解,也无法破解同类型的数字证书,另一方面是方便标识证书;

  • Issuer:表示证书的颁发者。遵循 X509 格式;

  • Validity:证书的有效开始时间和截止时间。过期需要续费;

  • Subject:证书的描述的实体,比如 B 站是上海幻电;

  • Subject Public Key Info:CA 证书的公钥加密算法;


你可能会问这些信息你咋知道的呀,其实也是浏览器的 CA 证书里面看的,没什么神奇的:



有了证书之后,接着是是对上面的数字证书内容做摘要算法生成一个数字签名,然后 CA 再用自己的私钥给数字证书的摘要套一层私钥加密,最后再交个客户端。


下面是整个数字证书和签名认证的图例:



Certificate 在图中所属的位置是数字签名,实际上 Certificate 还需要加到数字证书上进行传输才算是完整的。


注意:随着 密钥交换方式的加强,Certificate 在算法中还会再套一层“迷彩服”,这些内容会随着密钥交换方式的变化而出现很大的差别。


数字证书传递之后,接下来是关键的一步,也就是密钥交换算法的协商,密钥交换的算法实际上是对于会话密钥(对称加密方法)选择,也就是如何安全的把实际交互用的对称密钥告知服务器。


这里再补充一点,因为客户端通常缺乏客户端证书认证,所以客户端如何把后续要对称加密传输的密钥告知服务器是一件麻烦事情,因为黑客一旦窃取到这个信息前面的交互都前功尽弃了。非对称加密对于加密密钥的保护是一种方案,比如传统的 RSA,但是 RSA 存在很大漏洞,这一点在后续的内容进行解释。


密钥交换算法是指如何安全的进行密钥传输,之前介绍 HTTPS 利用非对称加密进行数据传输,非对称加密本身也不是百分百安全的,因为 私钥是有可能被破除的,为了更加安全的传输服务器的公钥,密钥交换的手段实际上也在不断改进。


加密套件


介绍下一步之前,这里要补充一下【加密套件】的内容,加密套件涉及了下面几种内容的加密:


  • 摘要算法

  • 会话密钥加密算法

  • 密钥交换算法(服务端非对称密钥加密)

  • 签名算法(CA 的非对称加密)



以上面的内容为例,加密套件使用的是 ECDHE_RSA With P-256 and AES_128GCM,指的是:


  • 密钥协商算法使用 ECDHE;

  • 签名算法使用 RSA;

  • 握手后的通信使用 AES 对称算法,密钥长度 128 位,分组模式是 GCM;

  • 摘要算法使用 P-256;


通常情况下握手时密钥交换算法和签名算法都是使用 RSA,但是随着互联网发展,其实 RSA 存在很大的安全隐患。也就是所谓的前向安全性 问题。


前向安全简单理解是,如果有黑客不断的窃取密钥交换的信息,RSA 一旦被破除加密出公钥的私钥公式,那么他可以用这个私钥破除之前所有的消息,获取所有的内容。


也就意味着,如果黑客破开某个大型网站的服务器私钥,那么可以借此私钥对于网站所有其他用户信息进行窃取,这种情况后果不堪设想。


随着量子计算机的发展和不断成熟,传统的加密手段在不断更新换代,密码安全也在遭遇前所未有的挑战。


为了破除 RSA 的魔咒,目前 HTTPS 传输的密钥交换算法采用了 ECDHE,ECDHE 对 DH 算法进行封装和改进,DH 算法解决了密钥在双方不直接传递密钥的情况下完成密钥交换,这个神奇的交换原理完全由数学理论支持,至于怎么支持的,个人也并不是很清楚,就不误人子弟了,可以自行上网查找相关资料。


Server Key Exchange


ECDHE 的交换方案我们可以简答理解为:(随机私钥+ 数学推导公式 = 随机公钥 + 非对称加密)。


通过签名的内容我们知道,只要是在网络上传输真实公钥,就是存在安全隐患的,所以现在的密钥交换通常使用 ECDHE,HTTPS 中 Server Key Exchange 中选择 RSA 加密还是 ECDHE 加密差别是很大的,比如 RSA 密钥交换算法不会多出 Server Key Exchange 这个步骤,而是服务端直接用 RSA 加密对称密钥,然后传给客户端。


这一篇文章以现在流行的 ECDHE 加密为主,RSA 加密的部分已经落伍就不再介绍了。


由于 ECDHE 本身的复杂性,Server Key Exchange 首先会随机生成一个椭圆曲线的私钥以及随机公钥,这个公钥叫做椭圆函数曲线公钥


意思是说我选的这个算法很复杂,再给你一个公钥,这个公钥在后面的对称加密密钥获取是有帮助的,但是为了防止这个公钥被拿到,我在公钥上面再用 RSA 私钥再加密一遍,你拿到后用服务器的公钥解开。


到这里 Certificate 本身的含义就发生了很大变化了, 原本对于 RSA 算法来说,只需要把这个值设置为 RSA 加密后的随机数即可,到这里 RSA 实际上掩盖的是被数学公式运算过的椭圆曲线公钥(Server Pararms),也就是说 RSA 加密的是可以被当作是一个随机生成的公钥,这个公钥就可以保证哪怕真的被破解出私钥,也是具备前向安全性的。


这里不好理解,我简化一下:简单理解是狸猫换太子,服务器给客户端的 RSA 公钥,解开来是加密算法的公钥,但是不能用这个公钥加密,这个公钥只是一个算法的“媒介”。


当然客户端需要小心保管这个算法“媒介”,但是黑客哪怕真的拿到这个媒介,实际上也是没啥用的,这一点同样下文介绍。


ECDHE 我们可以理解为,算法在服务器和客户端这两边各给了半片钥匙,要凑齐一个钥匙,需要都有这两个半片钥匙,再搞点特殊的粘合剂粘在一起,才是真正的“公钥”。


哪怕有了数字证书,加密手段还一套又一套。如果想了解这个公式的计算可以看看3.4 HTTPS ECDHE 握手解析 | 小林coding (xiaolincoding.com)。我数学差就不带大家看了。


CertificateRequest*


在发送 Server Done 之前,如果本次 HTTPS 是双向认证,那么客户端此时可以通过 CertificateRequest* 索要客户端证书,保证双方向的信息安全。


客户端证书使用较少,个人也没有实验环境,这里不做过多解释,PASS。


Server Done


把上面一套事情做完之后,服务器发送 Server Done 作为第二次握手的结束标志。接下来就是等待服务器是否认可。

HTTPS 第三次握手


第三次握手首先会收到服务端的证书信息以及 Certificate, Certificate 经过了 ECDHE 加入的魔法已经很复杂了,所以我们放松一下,先看看服务端证书校验部分。



证书校验过程签名实际前文提到过了,这里简单概括几个关键步骤:


  • 根证书自上到下验证,进一步加强 CA 证书的可靠性和安全性。

  • 使用 CA 的公钥解密出证书,然后按照通用的签名算法,对于数字证书做加签比对,任意一方不对等都可以认为请求是否问题的,此时客户端可以拒绝 HTTPS 通信。

  • 证书信任链,信任链从根证书取出公钥验证下一级证书,直到拿到服务器证书为止。

  • 浏览器内置 CA 公钥,不经过网路传输,会导致黑客没法做数字证书的手脚。

  • 数字证书认证分为两层,第一层是 CA 非对称加解密认证,第二层是数字签名形成的“指纹”验证,如果证书有任何改动,指纹都是匹配不上的,如果私钥加密信息被篡改,解开的信息会是客户端无法识别的乱码。



证书验证没问题的情况下,如果服务端上要求 Certificate*,客户端也要按照基本要求发送客户端证书+数字签名+客户端公钥,但是这里可以发现有个漏洞,客户端无法证明自己就是自己,为什么会这么说,先别急,我们先看看单向认证如何处理。


我们接着说 ECDHE 这个复杂的要死的算法,拿数字证书里面的服务端 Certificate,取出服务端的随机公钥,注意这里拿到的是非对称加密的公钥,不是密钥交换算法的公钥


公钥、公钥,非对称加密公钥,椭圆函数曲线公钥,数字证书公钥,客户端证书公钥,哪来那么多公钥!


服务器接着也按照服务端(实际上是 ECDHE)的要求,也自己生成一套椭圆曲线的公钥(Client Params),然后用非对称加密的公钥给他加密一遍确保安全,同样发送 ClientKeyExchange 传给服务端。


到这一步,客户端此时把两个“半片”钥匙都拿到了,接着就看看服务器能不能知道自己的“暗号”了。


CertificateVerify (客户端认证)*


还记得签名说的服务端的客户端认证么,发送完 ClientKeyExchange 之后,如果有客户端证书校验,还需要加一步 CertificateVerify 操作,里面包含了之前交互的所有报文+签名。


这里可能会有疑问,客户端不是有证书么?为啥还要自己再发个指令证明一遍自己是自己,为什么不能像服务器一样放到 ClientKeyExchange 里面发给服务器减少交互步骤?


这个问题老外很多年前就提到过,具体看看下面的帖子。这里我把下面的文章回答内容大概看了下,然后按照自己的思路理解一遍:


https://security.stackexchange.com/questions/110087/why-is-certificateverify-message-necessary-why-isnt-client-authentication-don


第一个问题:能够给材料做私钥加密不能证明客户端有对应的证书的私钥。


这里个人举个例子解释一下,比如你在大学上选修课,你上课上到一半想要逃课回寝室打游戏,但是又不能让位置空着,于是你从别的班花钱请了个小弟帮你顶包骗过老师。


这时候老师要怎么证明这个学生看上去是不是不对劲呢?最简单的办法是把这个同学叫起来,问一问他这节课之前讲了哪些内容呀,这种被顶包上去的,一问心里慌了把你供出来了,老师很生气直接说“我的课你也敢逃,那你以后都不用来了,期末成绩直接不及格!”,你心里后悔,要是把之前讲过的课和顶包同学解释一遍,就不会出问题了。


大概就是这么个道理,应该比较形象了吧,嗯。


第二个问题:客户端认证是可选的,和单向认证的相关内容放到一起实际上不太合适,万一哪一天客户端认证火起来就更难办了。


为了不要有过多的双向认证干扰,客户端认证就介绍到这,更多内容可以自行上网搜索。


Change Cipher Spec


做完 ECDHE 传输之后,我们可以看到目前的情况是这样的,客户端和服务端各自持有 (Client Params) 以及 (Server Params) 这两个公钥,于是它们会开始计算真实的会话密钥。


计算会话密钥之前,有一步随机数生成操作,因为 TLS 设计者不信任客户端和服务端任意一方,所以他会要求双方拿着 (Client Params) 以及 (Server Params) 这两个公钥+一顿复杂算法生成出一个随机数,叫做 PreMaster


PreMaster 实际上依然不是会话密钥,这时候还需要拿到第一次握手传递的 Client Random Server Random 在加上 PreMaster 做 PRF(伪随机数函数) 运算,生成最终的 MasterKey,也就是会话密钥。


所以会话密钥的最终计算公式如下:


master_secret = PRF(pre_master_secret, "master secret",ClientHello.random + ServerHello.random)
复制代码


是不是很复杂,很复杂对了,不复杂黑客就闯进来了。这样的会话密钥黑客基本上是破不开的,因为 PreMaster 不走网络传输,都是双方内部用固定算法算出来的。


这个工作方式实际上比较像我们前面介绍的密码机,也就是说哪怕拿到密码也破不开,只有密码机认识这一串密码,而生成密码机的机器在客户端和服务端两边放着。


master_secret 叫做主密钥,在 RFC 中规定是一位固定 48 Bit 的随机数。此外,为再一次确保 master_secret 安全性(有完没完!!!),master secret 还不是最终密钥(放过我=-=),还需要再次加上加密套件的 摘要算法,比如这里用的是 AES_128GCM,这样就避免了会话密钥被重复计算的隐患。


双方都有了 master_secret 和派生的会话密钥,客户端就可以发一个 Change Cipher Spec,告诉服务端我的会话密钥生成了,接下来用“那个”做对称加密吧。


Finished


Change Cipher Spec 发送完了,然后再发一个“Finished”消息(Encrypted Handshake Message,所以数据摘要),把之前所有发送的数据做个摘要,这时候再用会话密钥加密一下,让服务器做个验证。


为啥还要在做摘要再验一遍,这里应该比较好理解了,因为按照 ECDHE 密钥交换算法,最后这个摘要肯定是只有服务端解得开的,中间被窃取是不可能被破解的。


同样的,这个指令也是一个“测试”,如果对方解不开,肯定也是存在猫腻的,无形中又多了层安全网。


这时候你是黑客,你一定是???你们咋就会话加密了?你们的算法呢?你们的交流呢?咋就开始密文传输呢?

HTTPS 第四次握手

走过万里长征,最后的交互就简单了。服务器收到客户端的回应,注意这时候传过来的已经全是外人看不懂的密文了,我们抓包看到的也是一堆乱码,这时候服务端通过自己生成的会话密钥解一下密文,然后也按照客户端的 Change Cipher Spec Finished 来一套,让客户端也确认一下。


两边都核实无误,第四次握手就完成了,可以看到第四次握手是很简单的,简单的确认操作。


最终 HTTPS 连接构建完成,客户端开开信息上网,服务端安安心心传数据,黑客无可乘之机。

小结

我们遍历了整个 HTTPS TLS1.2 的历史发展和设计,可以看到 HTTPS 本身虽然细节很多,但是掌握大体内容之后并不是特别难,重点部分在于理清对称密钥加密是如何计算,也就是目前主流 ECDHE 密钥交换算法的一些大概流程,还有 CA 数字认证的这一个关键过程。


需要注意的是整个 HTTPS 的交互过程是非常灵活的,除非某些关键步骤之外,其他的子协议是类似“插件”一般可选的,虽然我们传统意义上认为 HTTPS 就该是有 CA 认证,就该有非对称加密和算法,实际上设计上而言这些东西都无关紧要。


从官方给的案例来看就是下的情况:



上面这张图的简化流程可以给大伙比喻成一段话:Hello,你好,请使用密文传输,Over,好的,使用密文传输,Over,哔哔哔哔哔.....,哔哔哔哔哔.......。实际上 HTTPS 就是通过这一段话不断扩展出来更多细节的。


之所以设置的这么灵活,个人认为是设计者不想把流程设计的那么死,另一方面是由于子协议自身模块化的思想决定了不能把所步骤当成一个整体来看待。


不过话说回来,现实情况是 TLS 协议本意是灵活扩展,但是 TLS1.2 经过长达数十年互联网膨胀,已经牵一发而动全身,TLS1.3 的升级也因为历史发展问题,不得不对 TLS1.2 做出让步和妥协。


值得一提的是,这一节 HTTPS 建立连接的过程没有以 RSA 作为密钥交换算法介绍,而是介绍现在真正主流的 ECDHE因为 RSA 在 TLS1.3 宣布禁止使用 RSA 算法),这算法很复杂,要真正完全理解需要比较强的数学功底,但是我们跳过数学的部分,重点介绍了在 HTTPS 中的作用,个人把它形象理解为两个半片钥匙,通过魔法合成魔法门,这三个内容搭配成随机摘要算法的“根”,最后再用“根”生成出强随机和安全性的会话密钥。


还有令我感到亮眼的地方是,密钥交换算法 ECDHE 在双方各有“暗号”的情况下,会根据暗号生成一个新的难以破解的暗号,这进一步加强了会话密钥的安全。


ECDHE 最大功劳是真正会话密钥的交换不需要网络传输,而是通过数学公式推导算出来的,这最大程度保证安全性。当然是在量子计算机还没到来之前。


从软件设计思想来看,协议制定和软件更新换代通用面临向后兼容问题,没有完美的标准,只有不算完美的前后兼容


以上便是我对 HTTPS 整个握手流程的看法。理论性很强,但是对于后面的实战十分重要。每个人看到的细节不一样,所以有疑问一定要多提问,多思考和反思,越是复杂的东西,越是要打破砂锅问到底


比如个人不太懂 ECDHE 算法的公钥上再加入 RSA 算法是如何识别的,最后绕进去发现自己把非对称加密密钥和椭圆曲线函数公钥搞混了。


以上就是 HTTPS TLS1.2 的概念部分,内容很长,感谢耐心观看,如有描述错误或者语句错误的地方欢迎指出。

用户头像

懒时小窝

关注

赐他一块白石,石头上写着新名 2020.09.23 加入

如果我们想要知道自己想要做什么,必须先找到自己的白色石头。欢迎关注个人公众号“懒时小窝”,不传播焦虑,只分享和思考有价值的内容。

评论

发布
暂无评论
HTTPS TLS 1.2_https_懒时小窝_InfoQ写作社区