因为疫情期间在外当志愿者,晚上回家无聊翻翻网络知识,权当记录了。
初始动笔:2019-02-28
修改时间:2019-04-06
人们最初设计互联网的时候,很少考虑到安全。这样造成一个问题:核心通信协议本质上是不安全的,只能依靠所有参与方的诚信。这显然有些理想主义了。
之后,随着安全需求的增加,我们提出了安全通信的共识,一般来说,具有下列特性:
- 机密性
仅有发送方和接收方能够理解传输数据的内容。 - 信息完整性
通信双方自然是想让通信的内容是完整的。 - 身份鉴别
确定通信双方是正确的。
基本上所有的安全措施,都是为了维护以上几点而设计的。
TCP 和 IP 是互联网的建立基础,它们本身就是非常容易受到攻击的;当然,不止它们,其他协议,比如 DNS 和 BGP 也是同样容易受到攻击。
为了更加浅显易懂,我们虚构三个人物,通信双方 Alice 和 Bob,以及一个想要窃听的坏人 Eve。
对称加密,又称之为私钥加密,是一种混淆算法。加密和解密使用相同的密钥。
Alice 使用密钥给信息进行了加密,然后 Bob 在接收到信息的时候使用相同的密钥进行解密,Eve 虽然可以截获信息,但是没有密钥,无法解读。
比较典型的对称加密算法有 DES 和 AES 算法。
-
优点:计算量小、加密速度快、加密效率高。
-
缺点:
交易双方都使用同样密钥,安全性得不到保证; 每次使用对称加密算法时,都需要使用其他人不知道的惟一密钥,这会使得发收信息双方所拥有的钥匙数量呈几何级数增长,密钥管理成为负担; 如果传递密钥是一个问题。
非对称加密,又称双钥加密,加密和解密使用公钥和私钥。用公钥加密的内容必须用私钥才能解开。
Alice 将公钥发给 Bob,然后 Bob 用公钥将信息加密发给 Alice;Alice 在收到信息后,使用私钥进行解密。
最有名的非对称加密算法就是 RSA 算法.
- 优点:
密钥的安全性大大提升 - 缺点:
计算速度会慢许多; 无法保证公钥的合法性。
为了保障消息完整性,推出了消息摘要算法。本身是一种哈希函数,函数的返回值,可以被称之为消息摘要或者指纹。
这种函数是不可逆的,无法通过消息摘要反推出消息,所以又被称之为单向哈希函数。
比较常见的有 MD5函数,SHA函数。
为了进行身份鉴别,产生了一种消息认证码技术(Message Authentication Code,简称MAC)。它可以被简单的认为是一种带有密钥的哈希函数。
它的运行机制简单描述如下:
- Alice 把消息发送给 Bob 之前,先将一个密钥发给 Bob;
- Alice 将要发送的消息通过密钥计算出 MAC 值,和消息一起发给 Bob;
- Bob 接收消息和 MAC 值,然后通过密钥,计算出 MAC 值,进行对比;
- 如果 MAC 值相同,那么就说明消息是 Alice 发送的。
- 优点:
保证消息完整性和真实性 - 缺点: 不能防止 Alice 抵赖,否认发送消息。
数字签名相当于现实世界中的盖章、签名的功能在计算机世界中进行实现的技术。它有连个特点:
- 数字签名可以证明是作者编写了这条消息。因为只有作者才会有最机密的私有秘钥。
- 数字签名可以防止报文被篡改。
在数字签名中,有 2 种行为:
- 生成消息签名的行为
- 验证消息签名的行为
生成消息签名的人是由消息发送者完成的,也称为“对消息签名”。生成签名就是根据消息内容计算数字签名的值。
验证数字签名的人是第三方。第三方验证消息的来源是否属于发送者。验证结果可以是成功,也可以是失败。
数字签名对签名密钥和验证密钥进行了区分,使用验证密钥是无法生成签名的。签名密钥只能由签名人持有,而验证密钥则是任何需要验证签名的人都可以持有。
数字证书可以说是 ID 卡,用来验证身份。一般来说有三种方法:
- 手工指定证书 这种一般是用于银行等机构,之前使用 12306 买火车票的时候,也是使用的是自己的证书;
- 证书颁发机构颁发
CA(Certificate Authority,证书颁发机构),可认为是大多数共同信任的第三方; - 浏览器或操作系统自带
浏览器和操作系统很多时候会内置一个证书颁发机构的名单,直接可以去信任。
一般来说,我们所说的都是第二类。一般的流程如下(实际上流程会有差别):
- Alice 生成一对公钥和私钥,将公钥发送给 CA;
- CA 通过审查确认公钥是 Alice 本人的;
- CA 生成自己的密钥对,使用私钥对 Alice 的公钥进行数字签名,生成数字证书;
- Bob 从 CA 获取到 Alice 的证书;
- Bob 使用 CA 的公钥对证书进行验证,证明是否来自 Alice;
- Bob 使用证书中的 Alice 的公钥进行加密,发送给 Alice;
- Alice 接收到消息之后用私钥解密。
TLS 是一个密码学协议,用于保证通信双方之间的会话安全。在 HTTP 之下,TCP之上。
TLS是一个非常复杂且博大的协议,对于一般开发者来说只需要理解其工作原理即可,如果对它非常感兴趣,可以查阅RFC5246。
TLS 的握手是整个协议中最精密复杂的部分,在这个过程中,通信双方协商连接参数,并且完成身份验证。
由于使用的功能的不同,一般分为三种握手:
- 完整的握手,对服务器进行身份验证;
- 恢复之前的会话采用的简短握手;
- 对客户端和服务器都进行身份验证的握手。
主要分为以下四个步骤(TLS/1.2):
- 交换各自支持的功能,对需要的连接参数达成一致;
- 验证出示的证书,或使用其他方式进行身份验证;
- 对将用于保护会话的共享主密钥达成一致;
- 验证握手消息并未被第三方团体修改。
客户端向服务端发送 Client Hello 消息,其中携带客户端支持的协议版本、加密算法、压缩算法以及客户端生成的随机数;
服务端收到客户端支持的协议版本、加密算法等信息后;
- 向客户端发送 Server Hello 消息,并携带选择特定的协议版本、加密方法、会话 ID 以及服务端生成的随机数;
- 向客户端发送 Certificate 消息,即服务端的证书链,其中包含证书支持的域名、发行方和有效期等信息;
- 向客户端发送 Server Key Exchange 消息,传递公钥以及签名等信息;
- 向客户端发送 Server Hello Done 消息,通知服务端已经发送了全部的相关信息;
- (可选)向客户端发送可选的消息 CertificateRequest,验证客户端的证书;
客户端收到服务端的协议版本、加密方法、会话 ID 以及证书等信息后,验证服务端的证书;
- 向服务端发送 Client Key Exchange 消息,包含使用服务端公钥加密后的随机字符串,即预主密钥(Pre Master Secret);
- 向服务端发送 Change Cipher Spec 消息,通知服务端后面的数据段会加密传输;
- 向服务端发送 Finished 消息,其中包含加密后的握手信息;
服务端收到 Change Cipher Spec 和 Finished 消息后;
- 向客户端发送 Change Cipher Spec 消息,通知客户端后面的数据段会加密传输;
- 向客户端发送 Finished 消息,验证客户端的 Finished 消息并完成 TLS 握手;
完整的 TLS 握手会带来额外的延迟和计算量,这个是非常大的性能损失。为了节约性能,TLS 提供了一个恢复功能,即在多个连接之间共享安全密钥。
在客户端,会保持之前会话的 ID 信息,并可以将其包含在会话的 “ClientHello” 消息中,从而提醒服务器自己带有上次握手的加密套件和密钥。服务器如果在自己的缓存中找到之前的会话 ID 参数,那么久可以直接进行简短的握手。如下图所示。
客户端向服务端发送 Client Hello 消息,其中携带客户端支持的协议版本、加密算法、压缩算法以及客户端生成的随机数;
服务端收到客户端支持的协议版本、加密算法等信息后;
- 向客户端发送 Server Hello 消息,并携带选择特定的协议版本、加密方法、会话 ID 以及服务端生成的随机数;
- 向客户端发送 Certificate 消息,即服务端的证书链,其中包含证书支持的域名、发行方和有效期等信息;
- 向客户端发送 Server Hello Done 消息,通知服务端已经发送了全部的相关信息;
客户端收到服务端的协议版本、加密方法、会话 ID 以及证书等信息后,验证服务端的证书;
- 向服务端发送 Client Key Exchange 消息,包含使用服务端公钥加密后的随机字符串,即预主密钥(Pre Master Secret);
- 向服务端发送 Change Cipher Spec 消息,通知服务端后面的数据段会加密传输;
- 向服务端发送 Finished 消息,其中包含加密后的握手信息;
TLS 的握手是四次握手,需要耗费 2 RTT,这是一个很大的消耗了,要知道 TCP 也才耗费 1.5 RTT,所以,之后版本的 TLS 把提升性能放到了重点。
关于 TLS 1.3 的资料,可以阅读此文
为了提升 TLS 的性能和安全性,TLS 1.3 登场。它主要是有以下几个方向的提升:
- 相比于 TLS 1.2 的 2 RTT,TLS 可以做到 1 RTT,甚至 0 RTT;
- 引入了新的密钥协商机制 — PSK;
- ServerHello 之后的所有握手消息采取了加密操作,可见明文大大减少;
- DSA 证书不再允许在 TLS 1.3 中使用。
而为了做这些提升,TLS 1.3 几乎和 TLS 1.2 完全不一样了,不像 HTTP/1.x 和 HTTP/2 互相兼容。握手过程如下图所示:
客户端发送 ClientHello 消息,该消息主要包括客户端支持的协议版本、DH密钥交换参数列表 KeyShare ;
服务端回复 ServerHello ,包含选定的加密套件;发送证书给客户端;使用证书对应的私钥对握手消息签名,将结果发送给客户端;选用客户端提供的参数生成 ECDH 临时公钥,结合选定的 DH 参数计算出用于加密 HTTP 消息的共享密钥;服务端生成的临时公钥通过 KeyShare 消息发送给客户端;
客户端接收到 KeyShare 消息后,使用证书公钥进行签名验证,获取服务器端的 ECDH 临时公钥,生成会话所需要的共享密钥; 双方使用生成的共享密钥对消息加密传输,保证消息安全。
我们可以发现,虽然看起来是有第三次握手,但是第三次实际上是带着数据一起传送过去,也就是相当于两次握手了。
PSK( pre_shared_key )是一种新的密钥交换暨身份认证机制,主要用于减少时延。在实现 0-RTT 的过程中,PSK 起到重要的作用。
在一次 TLS 握手之后,服务器可以发送一个 NST(new_session_ticket)报文给客户端,在报文中记录 PSK 的值、名字和有效期等信息,双方下一次建立连接的时候,可以使用该 PSK 值作为初始密钥材料。
因为实际上 PSK 是有前一次安全通信中获取到的,只要能证明双方持有相同的 PSK,就可以不再需要开启新的证书认证程序,直接证明双方的身份。
如果双方持有未过有效期的PSK键值对,则可以使用PSK进行密钥协商。双方传递一个结构体 PSK_entry。该结构体包括的内容有:PSK 对应名字(PSK_name)、用该 PSK 对之前的握手报文进行的 HMAC 计算结果(PSK_identity)。
HMAC(Hash-based Message Authentication Code),哈希运算消息认证码,一种基于Hash函数和密钥进行消息认证的方法。
具体的实施过程如下:
- 客户端在CH报文的pre_key_share扩展中传递一个PSK_entry的数组,包含所有自己持有的PSK信息。
- 服务端接收到该数组后,首先根据 PSK_name 选择一个想要使用的PSK,再使用自己持有的该 PSK 值计算 HMAC(Hash-based Message Authentication Code) 值,若与 PSK_identity 一致,则说明双方持有的 PSK 一致,否则服务器报错。
- 服务端将选定的 PSK_entry 结构体在 Server Hello 中的 pre_key_share 扩展中返还给客户端。协商完成,得到初始密钥 PSK。
如果使用了 PSK ,则客户端可以向服务端发送 early_data,客户端会选择发送的 PSK_entry 数组中的第一个 PSK 计算 early_trffic_key,因此,服务端也必须选择第一个 PSK,如果服务端拒绝接受 early data ,则返回其他的 PSK_entry,客户端丢弃已发送的 ED 报文。 使用 PSK 密钥协商,已经对双方的身份做了一定的认证,不得再使用公钥证书的认证方式。
《HTTPS 权威指南》
The Transport Layer Security (TLS) Protocol Version 1.3:draft-ietf-tls-tls13-latest