万字长文带图,从密码学到TCP握手:HTTPS如何保证安全?

深究HTTP系列

八千字长文详细图解:从输入URL到浏览器显示页面到底发生了什么?


HTTPS为什么安全?


前言

我们每天上网都使用http协议,我们每天编程也使用http协议,Spring Cloud的微服务使用Http template实现RPC调用,到处都是HTTP这四个字……
作为一名天天接触HTTP协议的程序员,不管是前端还是后端,怎能不了解HTTP协议呢?就连校招面试,HTTP协议也作为考官必点的一道开胃菜进行提问!
不管是面试还是开发,学好http协议都是必要的~
上期我详细讲解了HTTP协议的流程,这期我们来聊下一个话题,那就是HTTPs协议,为什么HTTPS协议能保证通讯的安全,他与HTTP协议的不同在哪里?这其中到底发生了什么呢,泡杯咖啡,听我给你讲~。


一、HTTPS是什么?

我们先看看百度百科怎么讲的。

HTTPS (全称:Hyper Text Transfer Protocol over SecureSocket Layer),是以安全为目标的 HTTP 通道,在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性 [1] 。HTTPS 在HTTP 的基础下加入SSL,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL。 HTTPS 存在不同于 HTTP 的默认端口及一个加密/身份验证层(在 HTTP与 八千字长文详细图解:从输入URL到浏览器显示页面到底发生了什么?

1.http与https在协议栈结构上的不同

下图是HTTP和https在协议栈结构上的不同,为了兼容http协议,https协议在进行tcp链接通讯的时候,引入了SSL(也叫TLS)协议,在TCP握手的时候,通过SSL协议的规范进行了一些报文交换,进而让双方的通讯能够保证安全。到底是怎样的操作,让他几个报文交换就能保证通讯安全呢?首先我们需要一些密码学的知识。
万字长文带图,从密码学到TCP握手:HTTPS如何保证安全?

SSL(Secure Socket Layer,安全套接字层):1994年为 Netscape 所研发,SSL 协议位于 TCP/IP 协议与各种应用层协议之间,为数据通讯提供安全支持。

TLS(Transport Layer Security,传输层安全):其前身是 SSL,它最初的几个版本(SSL 1.0、SSL 2.0、SSL 3.0)由网景公司开发,1999年从 3.1 开始被 IETF 标准化并改名,发展至今已经有 TLS 1.0、TLS 1.1、TLS 1.2 三个版本。SSL3.0和TLS1.0由于存在安全漏洞,已经很少被使用到。TLS 1.3 改动会比较大,目前还在草案阶段,目前使用最广泛的是TLS 1.1、TLS 1.2。

2.加密算法

什么样的信息传输才叫安全?我们可以拆分为四个目标。

  1. 保密性:传输的信息不能被截获者破译,保证只有接收者可以看懂。
  2. 端点鉴别:确定接收者是可靠的,而不是黑客不获取信息,直接攻击服务器,服务器坏掉了,何谈加密传输呢?

为了使我们的数据安全送达对方手中,我们需要保证数据的安全,如何保证安全呢?我们可以使用一些加密手段,对数据进行编码、加密,让数据变成别人看不懂的乱码。但是接收方却知道解密的手段,这样第三者获取不到我们的数据,只有对方才能进行解密,获取数据。
如何进行数据加密?我们需要了解一下基本的数据加密模型。

数据加密模型

明文 X X X:我们要发送的数据
密文 Y Y Y:经过加密的数据
加密秘钥 K K K:比特串,通过秘钥,明文可以被加密为密文。
解密秘钥 K K K:比特串,通过秘钥,密文可以被解密为明文。
加密和解密秘钥可以一样,也可以不一样,取决于加密算法的不同。
在这里,加密和解密秘钥都是K,表示加密解密秘钥一样。
加密行为: Y = E k ( X ) Y=E_{k}{(X)} Y=Ek(X)
E是Encrypt,即加密的英文缩写。通过这个表示,我们很容易就明白,X通过加密算法E、秘钥K,加密得到密文Y。这个过程也可以叫编码。
解密行为: D k ( Y ) = D k ( E k ( X ) ) = X D_{k}(Y)=D_{k}(E_{k}(X))=X Dk(Y)=Dk(Ek(X))=X
D是Decrypt,即解密的英文缩写。通过这个表示,很容易看出,Y通过秘钥、解密算法进行解密,就可以还原出X来,解密相当于加密的一种逆运算。这个过程也可以叫解码。这样的话,就可以达成较为安全的通讯了。

除了秘钥解密,有没有其他办法呢?有,我们可以穷举秘钥或者通过复杂的数学技巧来破解密文,但是前者需要庞大到不可能实现的算力,后者需要天才的数学天赋。这样破解的难度就变的极大,因此就达到了我们加密的目的。但是如果中间人截获了秘钥,那他不仅可以伪装发送者,还可以伪装接收者,神不知鬼不觉的发动攻击,获取机密信息。

理解了基本加密的思路,让我们再来了解一下两类密码体制。

两类密码体制

对称秘钥密码体制

所谓对称密钥密码体制,即加密密钥与解密密钥是使用相同的密码体制。如图所示,通信的双方使用的就是对称密钥。刚才我们讲解的加密模型,就是对称秘钥密码体制。
万字长文带图,从密码学到TCP握手:HTTPS如何保证安全?
使用对称秘钥密码体制的算法,双方就可以凭借秘钥(相同的)进行加密和解码啦。比如经典的DES加密算法,就可以进行加密和解密运算。

数据加密标准 DES(Data Encryption Standard)
DES全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法,1977年被美国联邦政府的国家标准局确定为联邦资料处理标准(FIPS),并授权在非密级政府通信中使用,随后该算法在国际上广泛流传开来。需要注意的是,在某些文献中,作为算法的DES称为数据加密算法(Data Encryption Algorithm,DEA),已与作为标准的DES区分开来。

通常,我们不需要自己发明算法,也不需要深究原理,这由密码学家和数学家负责,但是我们需要了解加密算法和加密的基本原理,以备不时之需,比如和第三方系统对接接口,又比如面试官让你聊聊常用的加密算法等场景,必须给他说道说道。

公钥密码体制

所谓公钥密码体制,即加密密钥与解密密钥不同的密码体制。
公钥密码体制的加密模型,可以这样表示:
加密秘钥Public Key:向公众公开,简称PK
解密秘钥Secret Key:自己保留,简称SK
加密算法E,解密算法D也是向公众公开的。
下面加密开始

  1. 生成秘钥对
    接收者B使用秘钥对产生器,可以产生一对秘钥PK与SK,SK给接收者保管,而发送者A需要拥有接收者B的PK(公开的)。
  2. 加密密文
    发送者A用接收者B给你的PK进行密文加密,然后发送
    Y = E P K B ( X ) Y=E_{PK_{B}}{(X)} Y=EPKB(X)
    接收者B使用自己的SK进行解密,恢复出明文
    X = D S K B ( Y ) = D S K B ( E P K B ( Y ) ) X=D_{SK_{B}}(Y)=D_{SK_{B}}(E_{PK_{B}}(Y)) X=DSKB(Y)=DSKB(EPKB(Y))

这样就完成了一次秘密通信,除非秘钥SK泄露,否则这样的交流很难被破解。
PK和SK的加密解密可以视为一种逆运算,虽然例子是公钥加密私钥解密,但是私钥加密也可以用公钥解密。
但是公钥加密后不能用公钥解密,必须用私钥解密,这就保证了数据的安全性。
我们可以看到,这一对秘钥,只能让A->B进行多对一单向通讯,不能双向一对一通讯。、
A可以是多个人,因为公钥是公开的。但是B只有一个,因为私钥是保密的。
当然,我们可以让他们双向通讯,只要A也生成一对秘钥,然后依照上述流程再走一遍,就可以实现双向的通讯了。
缺陷:比起对称公钥体系,这种体系更安全,只能获取一方的秘钥单向通讯,但是加密解密计算开销较大,在某些场景下,并不适合使用。
除此之外,如果入侵者代理B发布了自己的公钥,则A使用入侵者的公钥进行加密,入侵者使用自己的私钥解密,获得明文,就可以实现中间人攻击了。仅靠A和B两方并不能保证绝对的安全,我们需要一个公正方来证明B的真实性。B首先需要向CA申请证书,并携带证书进行通信,证明自己合法性,公证方称为CA,此时就可以保证通信安全了。

数字签名

在现实当中,为了证明合同的真实性,我们使用盖章的方法来保证合同是真实的,在数字世界当中,如何保证在网络中数据的真实性呢?我们需要使用一种数字签名,来保证数据的真实性,实现报文鉴别
数字签名可以达成三个目标:

  1. 接收者能够核实发送者对报文的签名。(报文鉴别)
  2. 接收者能确定数据没有被篡改过。(报文完整性)
  3. 发送者时候不能抵赖对报文的签名。(不可否认)

如何实现数字签名?方法有很多种。使用公钥密码体系就可以做到。

数字签名流程

A想发送明文X,并对X进行数字签名。要进行签名,需要使用A的私钥进行加密。
X 签 名 = E S K A ( X ) X_{签名}=E_{SK_{A}}(X) X=ESKA(X)
然后报文发送到接收者B手中。B使用A的公钥进行解密。
X = D P K A ( X 签 名 ) X=D_{PK_{A}}(X_{签名}) X=DPKA(X)

由于私钥不会被A以外的人知道,因此,我们可以核实签名
由于私钥不会被A以外的人知道,因此,除了A以外的人不可能有机会篡改报文
由于私钥不会被A以外的人知道,但是PKA可以公布,因此可以邀请第三者进行公证。A不可抵赖
当然,A不能是黑客,否则这就是中间人攻击。要解决这个问题,需要引入CA机构,对A颁发一个证书,证明A不是黑客,是合法的,然后A携带证书信息发送到B,B就可以通过证书(CA机构的背书)明白,A是合法的。

数字签名+秘密通信

如果在数字签名基础上还想要进行秘密通讯,很简单,只需使用公钥密码体制的加密方法,再给签名套上一层秘密通讯的加密解密(公钥体系)流程,就可以秘密通讯了。

缺陷

使用非对称加密算法,是非常消耗计算机性能的,若明文X长度非常长,那么一次加密就要耗费很多的CPU时间,这在某些情况下是不可接受的,必须寻找其他的报文鉴别方法

哈希算法

使用哈希算法,可以实现高效的报文鉴别

哈希函数

哈希算法,使用密码散列函数来对数据进行编码。该函数具有如下特点:

  1. 输入长度可以不固定,但是输出长度是固定的,而且很短。 输出长度被称为散列值。
  2. 不同的散列值肯定对应不同的输入,但是不同的输入可能得出相同的散列值。(几率很小)
  3. 不可能从输出计算出输入,通常认为这在理论上是不可能的。
    因此,只要我们发送的数据中,包含哈希输入与散列值,就可以基本保证哈希输入与散列值的一一对应性。过程如下:
    X : 明 文 , H : 散 列 函 数 X:明文,H:散列函数 XH:,可以发送
    M e s s a g e = ( X , H ( X ) ) Message=(X,H(X)) Message=(X,H(X))
    对于每个Message,可以确保X与H(X)是对应的。

对于这种东西,一般只能采用暴力法破解,如暴力破解、彩虹表、字典攻击、词表重整攻击、概率上下文无关文法。但是只要多次加盐加密,这些方法都很难破解哈希算法加密。

使用哈希函数来进行报文鉴别

为了确保没有中间人通过伪造X、使用相同的H计算出H(X)来伪造Message信息,需要对H(X)进行加密。由于H(X)长度恒定且不长,这时候,加密的效率就是可以保证的了!

加密流程

设秘钥为K,这里使用对称加密算法,K的安全性问题可以另外解决(比如使用公钥体系加密方法),此时假设是可以保证的。

  1. 发送者构造报文 M e s s a g e = ( X , E k ( H ( X ) ) ) Message=(X,E_{k}(H(X))) Message=(X,Ek(H(X))),加密过的散列值被称为报文鉴别码MAC
  2. 发送报文。经过互联网传输,
  3. 接收者分离报文X,加密过的散列值 E k ( H ( X ) ) E_{k}(H(X)) Ek(H(X))
  4. 使用秘钥解密, H ( X ) = D k ( E k ( H ( X ) ) ) H(X)=D_k(E_{k}(H(X))) H(X)=Dk(Ek(H(X)))
  5. 对X使用散列算法,得到H(X),与解密的值进行比较,相同则鉴别成功。
为什么安全

只要保证了入侵者不知道秘钥K,就没有办法伪造出报文鉴别码MAC,接收者解密后就无法得到正确的散列值,因此比较失败,报文鉴别成功。

三、HTTPS通信流程

层级关系

HTTPS的通信流程,就是在HTTP基础上,加上了TLS层进行安全认证。
层级关系可以参考下图。TLS可以说是运输层协议,但是其实在应用层的程序也会集成一部分TLS的内容用于接口调用和通讯。
万字长文带图,从密码学到TCP握手:HTTPS如何保证安全?
HTTP服务器与TLS之间有一个TLS 套接字通道,用来传递数据给TLS层。TLS层对数据进行包装加密等操作,并负责连接TCP进行报文交换(TLS层与目标端口(443)也有一个套接字通道,该通道为TCP真正交流端口,就像HTTP的端口80一样)。

安全保证

TLS协议提供以下三个安全保障,利用之前我们学习的前置知识,很容易理解这几个保证到底是怎么实现的。

  • 信息加密:HTTP 交互信息是被加密的,第三方就无法被窃取;
  • 校验机制:校验信息传输过程中是否有被第三方篡改过,如果被篡改过,则会有警告提示;
  • 身份证书:保证Server端的真实性;

具体过程

这里过程参考了几幅图拿下 HTTPS,感谢作者的抓包和解读。

TCP三次握手

TLS是基于TCP协议的,进行TLS之前,首先进行日常的三次握手协议。这里内容参考上一篇文章。

TLS4次握手

万字长文带图,从密码学到TCP握手:HTTPS如何保证安全?
其中每一个「框」都是一个记录(record)。记录是 TLS 收发数据的基本单位,类似于 TCP 里的 segment。
多个记录可以组合成一个 TCP 包发送,所以通常经过「四个消息」就可以完成 TLS 握手,也就是需要 2个 RTT 的时延,然后就可以在安全的通信环境里发送 HTTP 报文,实现 HTTPS 协议。
万字长文带图,从密码学到TCP握手:HTTPS如何保证安全?

密钥获取原理

首先,为了安全,我们需要密钥加密。兼顾效率和安全,TLS使用公钥体系与对称密钥体系混合的方法进行密钥的获取。首先使用公钥体系的方法,非对称加密获取一个对称的密钥,之后双方使用对称密钥进行交流。这样保证了对称密钥不会被入侵者利用,也保证加密解密效率足够高。
这个对称密钥,在握手中称为会话密钥

TLS第一次握手

客户端首先会发一个「Client Hello」消息,和服务器打招呼。具体内容如下。
万字长文带图,从密码学到TCP握手:HTTPS如何保证安全?

消息里面有客户端使用的 TLS 版本号、支持的密码套件列表,以及生成的随机数(Client Random)**,这个随机数会被服务端保留,它是生成对称加密密钥的材料之一。

TLS 第二次握手

当服务端收到客户端的「Client Hello」消息后,会确认 TLS 版本号是否支持,和从密码套件列表中选择一个密码套件,以及生成随机数(Server Random)。接着,返回「Server Hello」消息,消息里面有服务器确认的 TLS 版本号,也给出了随机数(Server Random),然后从客户端的密码套件列表选择了一个合适的密码套件
万字长文带图,从密码学到TCP握手:HTTPS如何保证安全?
可以看到,服务端选择的密码套件是 “Cipher Suite: TLS_RSA_WITH_AES_128_GCM_SHA256”。这个密码套件看起来真让人头晕,好一大串,但是其实它是有固定格式和规范的。基本的形式是「密钥交换算法 + 签名算法 + 对称加密算法 + 摘要算法」, 一般 WITH 单词前面有两个单词,第一个单词是约定密钥交换的算法,第二个单词是约定证书的验证算法。比如刚才的密码套件的意思就是:

  • 由于 WITH 单词只有一个 RSA,则说明握手时密钥交换算法和签名算法都是使用 RSA;
  • 握手后的通信使用 AES 对称算法,密钥长度 128 位,分组模式是 GCM;
  • 摘要算法 SHA256 用于消息认证和产生随机数;

就前面这两个客户端和服务端相互「打招呼」的过程,客户端和服务端就已确认了 TLS 版本和使用的密码套件,而且你可能发现客户端和服务端都会各自生成一个随机数,并且还会把随机数传递给对方。那这个随机数有啥用呢?其实这两个随机数是后续作为生成「会话密钥」的条件,所谓的会话密钥就是数据传输时,所使用的对称加密密钥。然后,服务端为了证明自己的身份,会发送「Server Certificate」给客户端,这个消息里含有数字证书
这证书里,就含有我们需要的公钥。

数字证书和 CA 机构

一个数字证书通常包含了:

  • 公钥;
  • 持有者信息;
  • 证书认证机构(CA)的信息;
  • CA 对这份文件的数字签名及使用的算法;
  • 证书有效期;
  • 还有一些其他额外信息;

数字证书的作用,是用来认证公钥持有者的身份,以防止第三方进行冒充。说简单些,为了让服务端的公钥被大家信任,服务端的证书都是由 CA (Certificate Authority,证书认证机构)签名的,CA 就是网络世界里的公安局、公证中心,具有极高的可信度,所以由它来给各个公钥签名,信任的一方签发的证书,那必然证书也是被信任的。之所以要签名,是因为签名的作用可以避免中间人在获取证书时对证书内容的篡改。

证书签发流程

万字长文带图,从密码学到TCP握手:HTTPS如何保证安全?
如图

  • 先是对数字证书的相关信息来一个hash运算,得到散列值。
  • 然后CA自己的私钥加密散列值,这个操作我们之前讲过,是CA进行了数字签名。
  • 然后把签名附加在文件证书上,这样就形成了数字证书。

客户端需要验证数字证书,确保CA机构的合格性。这是验证的常规操作,我们之前也讲了。

  • 首先客户端会使用同样的 Hash 算法获取该证书的 Hash 值 H1;
  • 通常浏览器和操作系统中集成了 CA 的公钥信息,浏览器收到证书后可以使用 CA 的公钥解密Certificate Signature 内容,得到一个 Hash 值 H2 ;
  • 最后比较 H1 和 H2,如果值相同,则为可信赖的证书,否则则认为证书不可信。

证书链

万字长文带图,从密码学到TCP握手:HTTPS如何保证安全?
如图。我们申请的证书,一般是中间证书签发的。比如百度。但是浏览器通常只信任根证书。因此浏览器会发起申请,验证百度证书的可信性。然后继续重复直到根证书。

  • 客户端收到 baidu.com 的证书后,发现这个证书的签发者不是根证书,就无法根据本地已有的根证书中的公钥去验证 baidu.com 证书是否可信。于是,客户端根据 baidu.com 证书中的签发者,找到该证书的颁发机构是 “GlobalSign Organization Validation CA - SHA256 - G2”,然后向 CA 请求该中间证书。
  • 请求到证书后发现 “GlobalSign Organization Validation CA - SHA256 - G2” 证书是由 “GlobalSign Root CA” 签发的,由于 “GlobalSign Root CA” 没有再上级签发机构,说明它是根证书,也就是自签证书。应用软件会检查此证书有否已预载于根证书清单上,如果有,则可以利用根证书中的公钥去验证 “GlobalSign Organization Validation CA - SHA256 - G2” 证书,如果发现验证通过,就认为该中间证书是可信的。
  • “GlobalSign Organization Validation CA - SHA256 - G2” 证书被信任后,可以使用 “GlobalSign Organization Validation CA - SHA256 - G2” 证书中的公钥去验证 baidu.com 证书的可信性,如果验证通过,就可以信任 baidu.com 证书。
    根证书一般内置于操作系统或者浏览器中,我们也可以手动添加证书。
    通过这种链条一样的方式,最终浏览器就可以成功进行证书的认证了。

证书报文:
万字长文带图,从密码学到TCP握手:HTTPS如何保证安全?
随后,服务端发了「Server Hello Done」消息,目的是告诉客户端,我已经把该给你的东西都给你了,本次打招呼完毕。
万字长文带图,从密码学到TCP握手:HTTPS如何保证安全?

TLS第三次握手

客户端验证完证书后,认为可信则继续往下走。接着,客户端就会生成一个新的随机数 (pre-master),用服务器的 RSA 公钥加密该随机数,通过「Change Cipher Key Exchange」消息传给服务端。

万字长文带图,从密码学到TCP握手:HTTPS如何保证安全?
服务端收到后,用 RSA 私钥解密,得到客户端发来的随机数 (pre-master)。至此,客户端和服务端双方都共享了三个随机数,分别是 Client Random、Server Random、pre-master。于是,双方根据已经得到的三个随机数,生成会话密钥(Master Secret),它是对称密钥,用于对后续的 HTTP 请求/响应的数据加解密。生成完会话密钥后,然后客户端发一个「Change Cipher Spec」,告诉服务端开始使用加密方式发送消息
万字长文带图,从密码学到TCP握手:HTTPS如何保证安全?
然后,客户端再发一个「Encrypted Handshake Message(Finishd)」消息,把之前所有发送的数据做个摘要再用会话密钥(master secret)加密一下,让服务器做个验证,验证加密通信是否可用和之前握手信息是否有被中途篡改过。

万字长文带图,从密码学到TCP握手:HTTPS如何保证安全?

可以发现,「Change Cipher Spec」之前传输的 TLS 握手数据都是明文,之后都是对称密钥加密的密文。

TLS 第四次握手

服务器也是同样的操作,发「Change Cipher Spec」和「Encrypted Handshake Message」消息,如果双方都验证加密和解密没问题,那么握手正式完成。
最后,就用「会话密钥」加解密 HTTP 请求和响应了。

可以看到,通过在CA证书里集成公钥,我们解决了中间人攻击的问题。
私钥我们默认服务器应该安全的保管,责任在接收方,因此是安全的。
若入侵者破解了私钥,过去被第三方截获的所有 TLS 通讯密文都会被破解。因此RSA也不是百分百安全的,为了避免这个问题,可以使用 安全的DH 密钥协商算法、效率更好的ECDHE 密钥协商算法(现在一般都用这个),但是在这里就不展开讲了。可以自己百度看看。

这里的过程比较繁杂,可以搭配下面的流程图,配合抓包内容进行学习。
万字长文带图,从密码学到TCP握手:HTTPS如何保证安全?

至此,HTTPS的通讯学习到这里了,本篇文章从最基础的密码学知识开始,逐步深入讲解至CA机构数字签名、TLS四次握手,手把手教你理解密码学如何保障了我们的Web安全,深入探索了TLS四次握手的具体内容和方法机制,如果你对HTTP协议还不是非常了解,那么欢迎你浏览我的深入了解HTTP原理系列的第一部:

八千字长文详细图解:从输入URL到浏览器显示页面到底发生了什么?

版权声明:玥玥 发表于 2021-04-17 7:16:31。
转载请注明:万字长文带图,从密码学到TCP握手:HTTPS如何保证安全? | 女黑客导航