https
http三大缺点:无状态,明文,不安全。
http不安全,那么什么样的通信过程才是安全的呢?
- 机密性。是指对数据的“保密”,只能由可信的人访问,对其他人是不可见的“秘密”。
- 完整性。是指数据在传输过程中没有被篡改,不多也不少,“完完整整”地保持着原状。
- 身份认证。是指确认对方的真实身份,也就是“证明你真的是你”,保证消息只能发送给可信的人。
- 不可否认。也叫不可抵赖,意思是不能否认已经发生过的行为,不能“说话不算数”“耍赖皮”。 https就是满足上面的四点,并且改变的协议名和端口号(443), HTTPS 协议在语法、语义上和 HTTP 完全一样。即https = http + tls
它把 HTTP 下层的传输协议由 TCP/IP 换成了 SSL/TLS,由“HTTP over TCP/IP”变成了“HTTP over SSL/TLS”,让 HTTP 运行在了安全的 SSL/TLS 协议上,收发报文不再使用 Socket API,而是调用专门的安全接口。
SSL
SSL 即安全套接层(Secure Sockets Layer),在 OSI 模型中处于第 5 层(会话层)。
TLS 由记录协议、握手协议、警告协议、变更密码规范协议、扩展协议等几个子协议组成,综合使用了对称加密、非对称加密、身份认证等许多密码学前沿技术。
浏览器和服务器在使用 TLS 建立连接时需要选择一组恰当的加密算法来实现安全通信,这些算法的组合被称为“密码套件”(cipher suite,也叫加密套件)。
密码套件的命名格式:密钥交换算法 + 签名算法 + 对称加密算法 + 摘要算法。
对称加密与非对称加密
加密:把消息用某种方式转换成谁也看不懂的乱码,只有掌握特殊“钥匙”的人才能再转换出原始文本。
使用密钥还原明文的过程叫“解密”(decrypt),是加密的反操作,加密解密的操作过程就是“加密算法”。
所有的加密算法都是公开的,任何人都可以去分析研究,而算法使用的“密钥”则必须保密。就好比,每个人都知道怎么开锁,但是你需要正确的钥匙。
秘钥是什么呢?
由于 HTTPS、TLS 都运行在计算机上,所以密钥就是一长串的数字,单位是位(bit)。
对称加密
“对称加密”很好理解,就是指加密和解密时使用的密钥都是同一个。
TLS 里有非常多的对称加密算法可供选择,比如 RC4、DES、3DES、AES、ChaCha20 等,但前三种算法都被认为是不安全的,通常都禁止使用,目前常用的只有 AES 和 ChaCha20。
AES 的意思是“高级加密标准”(Advanced Encryption Standard),密钥长度可以是 128、192 或 256。它是 DES 算法的替代者,安全强度很高,性能也很好,而且有的硬件还会做特殊优化,所以非常流行,是应用最广泛的对称加密算法。
ChaCha20 是 Google 设计的另一种加密算法,密钥长度固定为 256 位,纯软件运行性能要超过 AES,曾经在移动客户端上比较流行,但 ARMv8 之后也加入了 AES 硬件优化,所以现在不再具有明显的优势,但仍然算得上是一个不错的算法。
对称算法还有一个“分组模式”的概念,它可以让算法用固定长度的密钥加密任意长度的明文,把小秘密(即密钥)转化为大秘密(即密文)。明文的长度不固定,而密钥一次只能处理特定长度的一块数据,这就需要进行迭代,以便将一段很长的明文全部加密,而迭代的方法就是分组模式。
最新的分组模式被称为 AEAD(Authenticated Encryption with Associated Data),在加密的同时增加了认证的功能,常用的是 GCM、CCM 和 Poly1305。
下面我们来看看加密的过程
- 浏览器发送它所支持的加密套件列表和一个随机数 client-random,这里的加密套件是指加密的方法,加密套件列表就是指浏览器能支持多少种加密方法列表。
- 服务器会从加密套件列表中选取一个加密套件,然后还会生成一个随机数 service-random,并将 service-random 和加密套件列表返回给浏览器。
- 最后浏览器和服务器分别返回确认消息。 这样浏览器端和服务器端都有相同的 client-random 和 service-random 了,然后它们再使用相同的方法将 client-random 和 service-random 混合起来生成一个密钥 master secret,有了密钥 master secret 和加密套件之后,双方就可以进行数据的加密传输了。
涉及到的安全问题: 其中传输 client-random 和 service-random 的过程却是明文的,这意味着黑客也可以拿到协商的加密套件和双方的随机数,由于利用随机数合成密钥的算法是公开的,所以黑客拿到随机数之后,也可以合成密钥,这样数据依然可以被破解,那么黑客也就可以使用密钥来伪造或篡改数据了。
非对称加密
因为在发送数据的同时,也需要把秘钥发送给双发,那么在传输过程中可能被黑客窃取,那么他将可以使用这个秘钥来对数据解密。
所以就出现了非对称加密算法。他有两个秘钥,一个叫公钥,一个叫私钥。前者可以公开给任何人使用,但是后者必须严格保密。
公钥和私钥有个特别的“单向”性,虽然都可以用来加密解密,但公钥加密后只能用私钥解密,反过来,私钥加密后也只能用公钥解密。
在 HTTPS 中,服务器会将其中的一个密钥通过明文的形式发送给浏览器,我们把这个密钥称为公钥,服务器自己留下的那个密钥称为私钥。 所以公钥是每个人都可以获取到的,但是私钥只有服务器才能知道。
非对称加密算法一般有一些几种。DH、DSA、RSA、ECC 等。
下面我们来看一下非对称加密的过程:
- 首先浏览器还是发送加密套件列表给服务器。
- 然后服务器会选择一个加密套件,不过和对称加密不同的是,使用非对称加密时服务器上需要有用于浏览器加密的公钥和服务器解密 HTTP 数据的私钥,由于公钥是给浏览器加密使用的,因此服务器会将加密套件和公钥一道发送给浏览器。
- 最后就是浏览器和服务器返回确认消息。 这样浏览器端就有了服务器的公钥,在浏览器端向服务器端发送数据时,就可以使用该公钥来加密数据。由于公钥加密的数据只有私钥才能解密,所以即便黑客截获了数据和公钥,他也是无法使用公钥来解密数据的。
因此采用非对称加密,就能保证浏览器发送给服务器的数据是安全的了。
但是非对称加密有以下安全问题:
- 因为非对称加密都是基于复杂的数据难题计算出来的,所以效率很低。 这会严重影响到加解密数据的速度,进而影响到用户打开页面的速度。
- 因为公钥是公开的,所以无法保证服务器发送给浏览器的数据安全。 虽然浏览器端可以使用公钥来加密,但是服务器端只能采用私钥来加密,私钥加密只有公钥能解密,但黑客也是可以获取得到公钥的,这样就不能保证服务器端数据的安全了
混合加密
由于对称加密,它需要交换秘钥,容易被窃取。非对称加密,算法都是基于复杂的数学难题,计算速度非常慢,且公钥是公开的。所以就有了混合加密。将二者结合起来。
在通信刚开始的时候使用非对称算法,比如 RSA、ECDHE,首先解决密钥交换的问题。
然后用随机数产生对称算法使用的“会话密钥”(session key),再用公钥加密。因为会话密钥很短,通常只有 16 字节或 32 字节,所以慢一点也无所谓。
对方拿到密文后用私钥解密,取出会话密钥。这样,双方就实现了对称密钥的安全交换,后续就不再使用非对称加密,全都使用对称加密。
下面我们来看一下混合加密的过程:
- 首先浏览器向服务器发送
对称加密套件列表
、非对称加密套件列表
和随机数 client-random
;
- 服务器保存随机数 client-random,选择对称加密和非对称加密的套件,然后生成随机数 service-random,向浏览器发送选择的
对称加密套件
、service-random
和公钥
;
- 浏览器保存公钥,并生成随机数 pre-master(这里就借助了浏览器生成的数据加密后不能被黑客解密),然后利用公钥对 pre-master 加密,并向服务器发送加密后的pre-master;
- 最后服务器拿出自己的私钥,解密出 pre-master 数据,并返回确认消息。
到此为止,服务器和浏览器就有了共同的 client-random、service-random 和 pre-master,然后服务器和浏览器会使用这三组随机数生成对称密钥,因为服务器和浏览器使用同一套方法来生成密钥,所以最终生成的密钥也是相同的。(这里生成的秘钥就是对称加密的秘钥) 然后数据加密就可以这样安全的发送了。
数字签名与证书
使用私钥再加上摘要算法,就能够实现“数字签名”,同时实现“身份认证”和“不可否认”。
数字签名的原理其实很简单,就是把公钥私钥的用法反过来,之前是公钥加密、私钥解密,现在是私钥加密、公钥解密。
那么这里的公钥如何得到认证呢? 证书认证机构(CA)。CA 对公钥的签名认证也是有格式的,不是简单地把公钥绑定在持有者身份上就完事了,还要包含序列号、用途、颁发者、有效时间等等,把这些打成一个包再签名,完整地证明公钥关联的各种信息,形成“数字证书”(Certificate)。
数字签名的过程:首先 CA 使用 Hash 函数来计算申请者提交的明文信息,并得出信息摘要;然后 CA 再使用它的私钥对信息摘要进行加密,加密后的密文就是 CA 颁给申请者的数字签名。
操作系统和浏览器都内置了各大 CA 的根证书,上网的时候只要服务器发过来它的证书,就可以验证证书里的签名,顺着证书链(Certificate Chain)一层层地验证,直到找到根证书,就能够确定证书是可信的,从而里面的公钥也是可信的。
对于浏览器来说,数字证书有两个作用:一个是通过数字证书向浏览器证明服务器的身份,另一个是数字证书里面包含了服务器公钥。
下面我们来看一下包含数字证书的加密请求流程:
相较于混合加密,他有两点变化:
- 服务器没有直接返回公钥给浏览器,而是返回了数字证书,而公钥正是包含在数字证书中的。
- 在浏览器端多了一个证书验证的操作,验证了证书之后,才继续后续流程。
通过引入数字证书,我们就实现了服务器的身份认证功能,这样即便黑客伪造了服务器(可以通过DNS劫持将目标服务器的ip地址换成自己的ip地址),但是由于证书是没有办法伪造的,所以依然无法欺骗用户。
CA如何办法数字证书和数字签名
- 首先申请者(服务器)需要准备一套私钥和公钥,私钥留着自己使用;
- 然后申请者向 CA 机构提交公钥、公司、站点等信息并等待认证,这个认证过程可能是收费的;
- CA 通过线上、线下等多种渠道来验证申请者所提供信息的真实性,如公司是否存在、企业是否合法、域名是否归属该企业等;
- 如信息审核通过,CA 会向申请者签发认证的数字证书,包含了极客时间的公钥、组织信息、CA 的信息、有效时间、证书序列号等,这些信息都是明文的,同时包含一个 CA 生成的签名。
数字签名的生成:
- 首先 CA 使用 Hash 函数来计算申请者提交的明文信息,并得出信息摘要;
- 然后 CA 再使用它的私钥对信息摘要进行加密,加密后的密文就是 CA 颁给申请者的数字签名。
浏览器如何验证证书的合法性
浏览器需要验证证书的有效期、证书是否被 CA 吊销、证书是否是合法的 CA 机构颁发的。
验证证书的有效期。只需要查看当前时间是否在证书的有效期内就行。
验证数字证书是否被吊销了。通常有两种方式,一种是下载吊销证书列表 -CRL (Certificate Revocation Lists),第二种是在线验证方式 -OCSP (Online Certificate Status Protocol) 。
验证证书的合法性
- 首先浏览器读取证书中相关的明文信息,采用 CA 签名时相同的 Hash 函数来计算并得到信息摘要 A;
- 然后再利用对应 CA 的公钥解密签名数据,得到信息摘要 B;
- 对比信息摘要 A 和信息摘要 B,如果一致,则可以确认证书是合法的。 上面我们提到了利用CA的公钥来解密签名,那浏览器是如何获取到CA公钥的呢?
通常,当你部署 HTTP 服务器的时候,除了部署当前的数字证书之外,还需要部署 CA 机构的数字证书,CA 机构的数字证书包括了 CA 的公钥,以及 CA 机构的一些基础信息。
有了CA的公钥,那我们怎么知道这个共要是安全的呢?不是恶意的CA机构颁发的呢?
这里就是无限套娃的验证了。直到查找到根CA证书(目前通过 WebTrust 认证的根 CA 有 Comodo、geotrust、rapidssl、symantec、thawte、digicert 等),然后比对操作系统中是否内置的有这个根CA,如果有,浏览器就会认为使用者的证书是合法的。
TLS1.2连接过程解析
在 HTTP 协议里,建立连接后,浏览器会立即发送请求报文。但现在是 HTTPS 协议,它需要再用另外一个“握手”过程,在 TCP 上建立安全连接,之后才是收发 HTTP 报文。
TLS 协议的组成在
TLS 握手之前,我先简单介绍一下 TLS 协议的组成。
TLS 包含几个子协议,你也可以理解为它是由几个不同职责的模块组成,比较常用的有记录协议、警报协议、握手协议、变更密码规范协议等。
- 记录协议(Record Protocol)规定了 TLS 收发数据的基本单位:记录(record)。它有点像是 TCP 里的 segment,所有的其他子协议都需要通过记录协议发出。但多个记录数据可以在一个 TCP 包里一次性发出,也并不需要像 TCP 那样返回 ACK。
- 警报协议(Alert Protocol)的职责是向对方发出警报信息,有点像是 HTTP 协议里的状态码。比如,protocol_version 就是不支持旧版本,bad_certificate 就是证书有问题,收到警报后另一方可以选择继续,也可以立即终止连接。
- 握手协议(Handshake Protocol) 是 TLS 里最复杂的子协议,要比 TCP 的 SYN/ACK 复杂的多,浏览器和服务器会在握手过程中协商 TLS 版本号、随机数、密码套件等信息,然后交换证书和密钥参数,最终双方协商得到会话密钥,用于后续的混合加密系统。
- 变更密码规范协议(Change Cipher Spec Protocol),它非常简单,就是一个“通知”,告诉对方,后续的数据都将使用加密保护。那么反过来,在它之前,数据都是明文的。
每一个“框”都是一个记录,多个记录组合成一个 TCP 包发送。 所以,最多经过两次消息往返(4 个消息)就可以完成握手,然后就可以在安全的通信环境里发送 HTTP 报文,实现 HTTPS 协议。
下面是详细的TLS握手过程
在服务器发送随机数之后,就会发送数字证书给客户端,让其验证。然后才是协商生成会话秘钥。
ECDHE和RSA加密算法的不同在于生成pre-master的方式不同
- ECDHE:他是服务器生成椭圆曲线公钥(Server Params),实现秘钥交换算法。通过发送"server key exchange"消息来将server params传递给客户端。然后客户端验证完数字证书后,按照协商后的密码套件也生成一个椭圆曲线的公钥(client params)通过发送"client key exchange"消息将其发送给服务器。然后客户端和服务器都有了server params, client params,然后通过ECDHE算法算出一个pre-master随机数。然后开始了后面的通过对称加密算法生成会话秘钥。
- RSA则比较简单,客户端直接通过服务器生成的公钥,然后加密一个随机数得出pre-master,然后发送给服务器,让其解密。这样二者就有了相同的pre-master。就可以协商出会话秘钥了。
握手结束:
客户端发一个“Change Cipher Spec”,然后再发一个“Finished”消息,把之前所有发送的数据做个摘要,再加密一下,让服务器做个验证。意思就是告诉服务器:“后面都改用对称算法加密通信了啊,用的就是打招呼时说的 AES,加密对不对还得你测一下。”
服务器也是同样的操作,发“Change Cipher Spec”和“Finished”消息,双方都验证加密解密 OK,握手正式结束,后面就收发被加密的 HTTP 请求和响应了。
总结
- HTTPS 协议会先与服务器执行 TCP 握手,然后执行 TLS 握手,才能建立安全连接;
- 握手的目标是安全地交换对称密钥,需要三个随机数,第三个随机数“Pre-Master”必须加密传输,绝对不能让黑客破解;
- “Hello”消息交换随机数,“Key Exchange”消息交换“Pre-Master”;
- “Change Cipher Spec”之前传输的都是明文,之后都是对称密钥加密的密文。
TLS1.3特性解析
TLS1.3 在2018 年发布,再次确立了信息安全领域的新标准。
TLS1.3 的三个主要改进目标:兼容、安全与性能。
兼容
怎么区分 1.2 和 1.3 呢?
用到一个新的扩展协议(Extension Protocol),它有点“补充条款”的意思,通过在记录末尾添加一系列的“扩展字段”来增加新的功能,老版本的 TLS 不认识它可以直接忽略,这就实现了“后向兼容”。
在记录头的 Version 字段被兼容性“固定”的情况下,只要是 TLS1.3 协议,握手的“Hello”消息后面就必须有“supported_versions”扩展,它标记了 TLS 的版本号,使用它就能区分新旧协议。
安全
TLS1.2中发现了很多的漏洞和加密算法的弱点,所以 TLS1.3 就在协议里修补了这些不安全因素。
- 伪随机数函数由 PRF 升级为 HKDF(HMAC-based Extract-and-Expand Key Derivation Function);
- 明确禁止在记录协议里使用压缩;废除了 RC4、DES 对称加密算法;
- 废除了 ECB、CBC 等传统分组模式;
- 废除了 MD5、SHA1、SHA-224 摘要算法;
- 废除了 RSA、DH 密钥交换算法和许多命名曲线。 TLS1.3 里只保留了 AES、ChaCha20 对称加密算法,分组模式只能用 AEAD 的 GCM、CCM 和 Poly1305,摘要算法只能用 SHA256、SHA384,密钥交换算法只有 ECDHE 和 DHE,椭圆曲线也被“砍”到只剩 P-256 和 x25519 等 5 种。
为什么浏览器默认会使用ECDHE而不是RAS做秘钥交换?
假设有这么一个很有耐心的黑客,一直在长期收集混合加密系统收发的所有报文。如果加密系统使用服务器证书里的 RSA 做密钥交换,一旦私钥泄露或被破解(使用社会工程学或者巨型计算机),那么黑客就能够使用私钥解密出之前所有报文的“Pre-Master”,再算出会话密钥,破解所有密文。这样就不能保证向前安全了
而 ECDHE 算法在每次握手时都会生成一对临时的公钥和私钥,每次通信的密钥对都是不同的,也就是“一次一密”,即使黑客花大力气破解了这一次的会话密钥,也只是这次通信被攻击,之前的历史消息不会受到影响,仍然是安全的。
性能
TLS1.3 压缩了以前的“Hello”协商过程,删除了“Key Exchange”消息,把握手时间减少到了“1-RTT”,效率提高了一倍。这就需要在记录头中加上一些扩展的字段了。不如:“supported_groups”是支持的曲线,“key_share”是曲线对应的参数。
下面来看一下TLS1.3的握手过程
在算出主密钥后,服务器立刻发出“Change Cipher Spec”消息,比 TLS1.2 提早进入加密通信,后面的证书等就都是加密的了,减少了握手时的明文信息泄露。
这里 TLS1.3 还有一个安全强化措施,多了个“Certificate Verify”消息,用服务器的私钥把前面的曲线、套件、参数等握手数据加了签名,作用和“Finished”消息差不多。但由于是私钥签名,所以强化了身份认证和和防窜改。
这两个“Hello”消息之后,客户端验证服务器证书,再发“Finished”消息,就正式完成了握手,开始收发 HTTP 报文。
一些思考题
- 非对称加密的缺点? 他是基于大量的运算。比如大素数,椭圆曲线。 并且相对于对称加密,他需要更多的位数。
- 对称加密为啥会有密钥交换的过程,对称加密就一个密钥,客户端服务端各保存一份就可以了,为啥要传输交换呢?我的理解就是,客户端发送报文通过秘钥加密,但是服务器又不知道,所以需要发送过去,当报文到达服务器,服务器拿这个秘钥解密。服务器也是一样的。
关键是“如何各保存一份”,两边加密通信必须要使用相同的密钥才行,不交换如何才能保持一致呢?
而且简单的一对一还好说,现实情况是网站要面对成千上万的用户,如何与这么多的客户端保持一致?
还有,如果总使用一个密钥,就很容易被破解,风险高,需要定期更换,最好是一次一密。
所以,为了安全起见,每次通信前双方都要交换密钥,这样就实现了“各保存一份”,用完就扔掉,下次重新交换。
- TLS1.3 里的密码套件没有指定密钥交换算法和签名算法,那么在握手的时候会不会有问题呢? TLS1.3精简了加密算法,通过support_groups、key_share、signature_algorithms这些参数就能判断出密钥交换算法和签名算法,不用在cipher suite中协商了
- 结合上一讲的 RSA 握手过程,解释一下为什么 RSA 密钥交换不具有“前向安全”。 RSA握手时,client key exchage会使用RSA公钥加密pre master后传给服务端,一旦私钥被破解,那么之前的信息都会被破译,根本原因还是在于RSA的这一对公钥私钥并不是临时的。
- TLS1.3 的握手过程与 TLS1.2 的“False Start”有什么异同? 相同点:都在未收到Finished确认消息时就已经向对方发送加密信息了,不同点:TLS1.3将change cipher spec合并到了hello中
这里真的需要感谢李兵老师的浏览器原理与实践专栏。time.geekbang.org/column/arti…