Https加密

129 阅读20分钟

引言

由于HTTP协议是采用明文传输的方式,因此带来了很大的数据安全隐患,所以在最近几年的时间内,大部分平台都采用了HTTPS逐渐取代了HTTP,但HTTPS并不是一种全新的协议,而是建立在HTTP协议的基础之上,为其添加了一层TLS/SSL,从而实现数据的加密传输,确保足够的安全性,区别如下:

相较于HTTP而言,HTTPS则拥有更高的安全性,例如数据加密传输、报文完整性效验、身份认证判断等。解决了HTTP协议中一直存在的安全问题,如明文传输数据会遭受窃听风险、不验证报文完整性会导致数据被篡改、不效验通信方身份会导致“他人”伪造通信对端劫持客户端等。

一、概念

1.几种算法

1.1、哈希散列加密算法

哈希函数(Hash function),又称散列函数、散列算法,它是一种不可逆的信息摘要算法,具体实现就是把任意长度的输入信息通过哈希算法变成固定长度的输出信息。

常用算法:MD5、SHA1、SHA256等。

1.2、对称加密算法

对称加密:是指加密通信的双方加/解密的方式都是相同的,类似一个天平,两边都是“对称”的。

常用算法:AES-CBC、AES-GCM、DES、3DES等。

1.3、非对称加密算法

非对称加密:对称加密算法在加/解密时采用的密钥都是相同的,而非对称加密算法则恰巧相反,非对称加密方式中存在两个密钥:公钥、私钥。
如果用公钥加密的数据,只有用对应的私钥才能解密;如果用私钥加密的数据,那只有用对应的公钥才能解密。因为加/解密使用两个不同的密钥,最终则被称为:非对称加密。

常用算法:RSA、DSA、ECC、DH等。

采用非对称加密方式的服务端,会首先生成两个密钥,将其一把作为公钥发送给所有客户端,另一把则当作私钥仅自己保存:

2.摘要,签名,数字证书

2.1、信息摘要

一段信息,经过摘要算法得到一串哈希值,就是摘要(dijest)。

常见的摘要算法有MD5、SHA1、SHA256、SHA512等。

关于摘要,有几点需要你明白的:

1、摘要算法,是把任意长度的信息,映射成一个定长的字符串。

2、摘要算法,两个不同的信息,是有可能算出同一个摘要值的。

3、摘要算法与加密算法不同,不存在解密的过程。

4、摘要算法不用于数据的保密,而是用于数据的完整性校验。

2.2、数字签名

摘要经过私钥的加密后,便有了一个新的名字 -- 数字签名。

签名 是在发送方,这是一个加密的过程。

验签 是在接收方,这是一个解密的过程。

那搞懂数字签名的意义是什么?只要回答下面两个问题即可。

第一个问题,有了信息摘要,为何还要有数字签名?

答:信息摘要,虽然也不可逆,但却容易却被伪造。所以信息摘要只用于校验完整性,而要保证信息摘要的正确性,就要依靠数字签名啦。

数字签名的签名和验签是非对称加密,其他人除非拿到私钥,不然没法伪造。

第二个问题,为什么不对内容直接加密,而是对摘要进行加密。

答:由上面我们知道了非对称加密的速度非常慢,如果传输的数据量非常大,那这个加密再解密的时间要远比网络传输的时间来得长,这样反而会得不偿失。

如果我们对传输的内容只有完整性要求,而安全性没有要求(意思是传输的内容被人知道了也没关系)。那就可以对摘要进行加密,到客户端这里解密后得到摘要明文,再用这个摘要明文与传输的数据二次计算的摘要进行比较,若一致,则说明传输的内容是完整的,没有被篡改。

2.3、数字证书

在数字签名那里,不知道你有没有发现一个问题?

数字签名是非对称加密,服务端有一个私钥,客户端一个公钥,只有这两个对上了验签。

那假如说你(客户端)拿到的公钥并不是服务端给的呢,而是黑客塞给你的呢?而你却把这个假公钥当成真的,那么当你使用这个假公钥加密一些敏感信息时,黑客就可以截取你的这段信息,由于这信息是用黑客自己的公钥加密的,这样一来,黑客拿自己的私钥就能解密得到你的敏感信息。

这就是问题所在。

要解决这个问题,其实只要保证『公钥』是可信的。只有服务端发给你的公钥你才能拿,而坏人给你的公钥,你要懂得识别并丢弃它。

数字证书就应运而生了。

要理解数字证书,同样只要搞懂两个问题即可。

  1. 数字证书是什么东西?其实它就是一个 .crt 文件
  2. 数字证书是谁颁发的?由权威证书认证机构颁发,一般我们简称为 CA 机构
  3. 数字证书如何申请的?或者说如何颁发的?

1、在自己的服务器上生成一对公钥和私钥。然后将域名、申请者、公钥(注意不是私钥,私钥是无论如何也不能泄露的)等其他信息整合在一起,生成.csr 文件。

2、将这个 .csr 文件发给 CA 机构,CA 机构收到申请后,会通过各种手段验证申请者的组织信息和个人信息,如无异常(组织存在,企业合法,确实是域名的拥有者),CA 就会使用散列算法对.csr里的明文信息先做一个HASH,得到一个信息摘要,再用 CA 自己的私钥对这个信息摘要进行加密,生成一串密文,密文即是所说的 签名。签名 + .csr 明文信息,即是 证书。CA 把这个证书返回给申请人。

二、SSL与TLS加密层

在HTTPS中最关键的是数据安全传输,而负责这块的则是SSL/TLS层,而该层中的功能实现主要依赖于三类加密算法:哈希散列加密、对称加密及非对称加密算法,其中常用的算法如下:

  • 哈希散列加密算法:MD5、SHA1、SHA256等。

  • 对称加密算法:AES-CBC、AES-GCM、DES、3DES等。

  • 非对称加密算法:RSA、DSA、ECC、DH等。

上述简单了解了一些SSL/TLS基本内容后,再一步步的从0开始推导HTTP→HTTPS的演变过程。

在之前的HTTP协议中,数据都是明文传输的,如下:

前面提及过,这种明文传输的方式安全性很低,因此如果要提高安全性,最简单有效的方式就是对传输的数据进行加密,如HTTPS中的传输方式:

在这个模型中,双方采用相同的密钥、加/解密算法处理数据,这种方式则被称为对称加密

对称加密:是指加密通信的双方加/解密的方式都是相同的,类似一个天平,两边都是“对称”的。

1.用对称加密可行吗?

如果通信双方都各自持有同一个密钥,且没有别人知道,这两方的通信安全当然是可以被保证的(除非密钥被破解)。

然而最大的问题就是这个密钥怎么让传输的双方知晓,同时不被别人知道。如果由服务器生成一个密钥并传输给浏览器,那在这个传输过程中密钥被别人劫持到手了怎么办?之后他就能用密钥解开双方传输的任何内容了,所以这么做当然不行。

换种思路?试想一下,如果浏览器内部就预存了网站A的密钥,且可以确保除了浏览器和网站A,不会有任何外人知道该密钥,那理论上用对称加密是可以的,这样浏览器只要预存好世界上所有HTTPS网站的密钥就行了!这么做显然不现实。
怎么办?所以我们就需要非对称加密 。

2.用非对称加密可行吗?

鉴于非对称加密的机制,我们可能会有这种思路:服务器先把公钥以明文方式传输给浏览器,之后浏览器向服务器传数据前都先用这个公钥加密好再传,这条数据的安全似乎可以保障了!因为只有服务器有相应的私钥能解开公钥加密的数据

但其实非对称加密也存在一个经典的问题,也就是依旧无法避免“第三者”介入,先上图:

先仔细观察上图中的步骤,万一“第三者”将服务端返回的“真公钥”替换成了自己的“假公钥”,从而最终导致了数据的泄露又该怎么办呢?

3.如何证明浏览器收到的公钥一定是该网站的公钥?

其实所有证明的源头都是一条或多条不证自明的“公理”(可以回想一下数学上公理),由它推导出一切。比如现实生活中,若想证明某身份证号一定是小明的,可以看他身份证,而身份证是由政府作证的,这里的“公理”就是“政府机构可信”,这也是社会正常运作的前提。

那能不能类似地有个机构充当互联网世界的“公理”呢?让它作为一切证明的源头,给网站颁发一个“身份证”?
它就是CA机构,它是如今互联网世界正常运作的前提,而CA机构颁发的“身份证”就是数字证书

4.流程

客户端一般在加密通信前,会先向服务端获取公钥,服务器则会将「数字证书」返回给客户端,客户端拿到证书后,会首先通过CA机构的公钥解密证书中的「数字签名」,能够解密成功则代表该证书来自于值得信赖的权威机构,最终就得到了CA哈希后的“信息摘要”,然后客户端会使用与CA机构相同的Hash算法对「数字证书」中的「申请信息、服务器公钥」再次生成一份“摘要”,最后拿着生成的“信息摘要”与解密后的“信息摘要”对比,如果一致则代表数据未被篡改过,最终客户端就可以使用证书中的公钥进行加密通信,流程如下:

注意:客户端OS与浏览器中都会提前预装CA机构的根证书,这些根证书中已包含了CA公钥、当前CA机构使用的Hash算法等。

由于数字签名是采用单向哈希算法,生成的“信息摘要”是不可逆的,当服务器返回的证书内容被篡改后,客户端在生成摘要比对时,结果肯定不匹配,因此客户端会拒绝连接。但仅这样也无法避免公钥被掉包,也就是“第三者”也去CA机构申请证书,然后在中间直接将整个证书替换成自己的,最终客户端获取的依旧是“第三者”的公钥,所以为了解决这个问题,CA机构颁发的数字证书中,还会涵盖网站信息(如域名、所有者等),当证书被掉包后,客户端发现返回的证书与请求的网站信息并不同,那么依旧会拒绝连接。

为什么会有第三者呢?因为网络传输数据的通信链路是不可预计的,因此数据会经过很多节点的中转,同时在实际开发过程中也有不少请求需要走代理,也包括会存在网络攻击者,因此多方面的原因都有可能导致“第三者”介入。

经过上述一系列手段后,解决了非对称加密传输公钥时的不安全问题,但非对称加密方式,由于加/解密过程复杂,因此性能会比对称加密要低不少,因此在HTTPS中是非对称加密与对称加密混合使用的模式,其中数据是对称加密方式传输的,而对称加密的密钥是通过非对称加密方式传输的。

三、HTTPS工作原理

上面叭叭一大堆,各位看到这里难免有些头大,所以接下来结合完整的HTTPS流程梳理一下,先上图:

  • ①客户端先向服务端请求公钥,其实就是与服务端443端口建立连接的过程。
  • ②服务端接收到请求后,会将数字证书返回给客户端。
  • ③客户端收到证书后,会经过图中的几步效验操作,确认证书合法后,会先生成一个对称密钥,然后通过证书中的公钥对其加密,并发给服务端。
  • ④服务端收到公钥加密后的对称密钥后,通过自己的私钥对其解密。
  • ⑤最终客户端、服务端都拥有了一把对称密钥,接下来则通过对称密钥传输数据。

整个HTTPS的大体逻辑如上,但实际生成对称密钥的过程却并非如此,在HTTPS中是需要经过RSA握手的步骤。

四、TLS层的握手过程

前面谈及的过程其实简化了很多,主要是为了便于理解HTTPS的整体流程,但实际HTTPS远比前面所赘述的流程复杂很多,接下来则详细阐述一下其中的TLS握手过程。

TLS/1.2之前的版本都是采用RSA算法进行密钥交换,但TLS/1.2及之后的版本中主要采用ECDHE算法实现。

一般而言,TLS层在交换密钥时都会经历多个步骤,其中可分为11个小阶段,4次握手阶段,如下:

下面我们通过Wireshark抓包工具实际分析一下具体过程。

2.3.1、TLS第一次握手

①客户端:Client Hello

在TLS一次全新的握手流程中,客户端会首先发出一条Client Hello的信息,并会附带传递一些客户端的信息,如下:

Handshake Protocol: Client Hello 
  Handshake Type: Client Hello (1) 
  Length: 223 
  Version: TLS 1.2 (0x0303) 
  Random: bh21b273g32de8b0e4f13de22d33f24e6a671e62f82hgc2fdh1f2hbabe4326 
  Session ID Length: 0 
  Cipher Suites Length: 92 
  Cipher Suites (46 suites) 
    Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA256 (0xc030) 
    Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02c) 
    Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc028) 
    ... 
  • Length:报文长度。
  • Version:客户端支持的最佳TLS版本号。
  • Random:随机数,后续用于生成对称密钥,为了区分则称为client-random。
  • Session ID:第一次握手时该值为空,后续请求中会有会话ID(用于恢复)。
  • Cipher Suites:客户端支持的密码套件,优先级从高到低排序。

解读密码套件:

套件由密钥交换算法+签名算法+对称加密算法+摘要生成算法四部分组成,其中:

  • ECDHE为密钥交换算法,用于TLS握手阶段。
  • RSA为签名算法,用于效验数字证书阶段时的身份验证。
  • AES为对称加密算法,长度及为256位,分组模式为GCM,用于数据传输阶段。
  • SHA256为摘要生成算法,用于消息认证及产生随机数(稍后分析)。

2.3.2、TLS第二次握手

②服务端:Server Hello

服务端收到客户端的Client Hello信息后,会给予一个Server Hello的信息响应:

Handshake Protocol: Server Hello 
    Handshake Type: Server Hello (2) 
    Length: 89 
    Version: TLS 1.2 (0x0303) 
    Random: 21ds544sda21vcsqaaa124dsac2za2bc6472c45b54c0a21c666d2sda2q14514d555f6f 
    Session ID Length: 32 
    Session ID: 676fb1435152124ef4ce41af4cb77s5w13aa1c2e6w7c3e5c45da16cdf414f22c2 
    Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02c) 

在服务端响应的Server Hello信息中,主要会确认自己是否支持TLS版本、从客户端支持的密码套件中选择一套以及也会生成一个随机数server-random。

③服务端:Certificate

在响应了客户端信息后,紧接着服务端会将自己的数字证书发给客户端:

Handshake Protocol: Certificate 
    Handshake Type: Certificate (11) 
    Length: 2781 
    Certificates Length: 2778 
    Certificates (2778 bytes) 
        Certificate Length: 1407 
        Certificate: 证书1....
        Certificate Length: 1365 
        Certificate: 证书2....
        .......

客户端收到服务端的这个响应后,会先去验证证书的证实有效性,如果有效则继续,如果证书无效则会发出警告信息并中断TCP连接,例如www.baidu.com的证书如下:

④服务端:Server Key Exchange

向客户端发送了数字证书后,紧接着服务端会通过一条Server Key Exchange消息,将密钥交换算法需要用到的数据/参数携带上去,并向客户端发送:

Handshake Protocol: Server Key Exchange 
    Handshake Type: Server Key Exchange (12) 
    Length: 329 
    EC Diffie-Hellman Server Params 
        Curve Type: named_curve (0x03) 
        Named Curve: secp256r1 (0x0017) 
        Pubkey Length: 65 
        Pubkey: 6615dc2a1a2a4d482efc777cf1d804d...
        Signature Algorithm: rsa_pkcs1_sha512 (0x0601) 
            Signature Hash Algorithm Hash: SHA512 (6) 
            Signature Hash Algorithm Signature: RSA (1) 
        Signature Length: 256 
        Signature: 5a1dc12ds152b4a7445t2....

上面即是ECDHE密钥交换算法的消息内容,不同的密钥交换算法,其具体的内容也会不同,这些内容发送给客户端的主要目的是:提供给客户端计算主密钥需要的另一个值:“预主密钥( premaster secret )”

⑤服务端:Certificate Request

Certificate Request这个消息是服务端要求客户端上报证书,这一步是可选的,因为HTTPS可以选择双向验证,对于安全性要求高的场景会用到,默认是不发送这条信息的。

⑥服务端:Server Hello Done

在传输完上述中的所有信息后,服务端最后会发送一条Server Hello Done的信息,通知客户端Server Hello阶段结束,即告知客户端“第二次握手”完成。

2.3.3、TLS第三次握手

⑦客户端:Client Key Exchange

在第二次握手阶段,客户端根据服务端发来的信息:公钥、算法、参数等生成了第三个随机数premaster secret(预主密钥),Client Key Exchange这条信息就是将该值通过公钥加密,然后传给服务端:

Handshake Protocol: Client Key Exchange 
    Handshake Type: Client Key Exchange (16) 
    Length: 66 
    EC Diffie-Hellman Client Params 
        Pubkey Length: 65 
        Pubkey: o1deca231a1x123eeq12c6bb786.....

服务端收到该消息后,会通过自己的私钥解密,然后得到第三个随机数,到此刻为止,客户端和服务端之间都各自拥有了三个随机数:client-random、server-random、premaster secret,两边再根据相同的算法计算,就可以生成一个密钥,后续的应用层的数据传输就是通过该密钥作为对称密钥进行加密传输。

⑧客户端:Change Cipher Spec

Change Cipher Spec这条消息是一条事件消息:

TLSv1.2 Record Layer: Change Cipher Spec Protocol: Change Cipher Spec 
    Content Type: Change Cipher Spec (20) 
    Version: TLS 1.2 (0x0303) 
    Length: 1 
    Change Cipher Spec Message

表示通知服务端密钥已经计算出来了,后续的数据传输都会通过前面协商出的密钥进行加密传输,代表后续切换到对称加密模式。

⑨客户端:Encrypted Handshake Message

Encrypted Handshake Message这条消息作用是:用于测试对称密钥是否能够正常工作

TLSv1.2 Record Layer: Handshake Protocol: Encrypted Handshake Message 
    Content Type: Handshake (22) 
    Version: TLS 1.2 (0x0303) 
    Length: 60 
    Handshake Protocol: Encrypted Handshake Message

这是客户端第一条通过对称密钥加密传输的信息,如果服务端接受后,也能够通过计算出的密钥解开,即代表前面协商计算出的对称密钥没有问题。

2.3.4、TLS第四次握手

⑩服务端:Change Cipher Spec

和客户端的Change Cipher Spec消息作用相同:

TLSv1.2 Record Layer: Change Cipher Spec Protocol: Change Cipher Spec 
    Content Type: Change Cipher Spec (20) 
    Version: TLS 1.2 (0x0303) 
    Length: 1 

用于通知客户端:我已计算出对称密钥,后续通信采用加密模式。

⑪服务端:Encrypted Handshake Message

服务端的第一条加密信息,用于测试客户端计算出的密钥是否可以解开加密数据:

TLSv1.2 Record Layer: Handshake Protocol: Encrypted Handshake Message 
    Content Type: Handshake (22) 
    Version: TLS 1.2 (0x0303) 
    Length: 40 
    Handshake Protocol: Encrypted Handshake Message 

至此,客户端和服务端双方能够正常加密通信,TLS握手阶段结束。

2.3.5、TLS1.2之前及TLS1.3中的握手区别

其实TLS/1.2版本对比之前的TLS版本,握手过程中唯一不同点在于:采用的密钥交换算法不同,在之前的版本中都采用RSA算法生成对称密钥,而1.2版本中用的是ECDHE算法。

在TLS/1.3版本中,主要是缩减了TLS握手的次数,从原本的“四次握手”缩减到了三次握手,同时也减少了整个握手流程中的步骤,如下:

从图中可以明显看出,客户端计算出第三个随机数后,并未将其传回给服务端,服务端这边也是自己通过已有的参数计算得到的,然后双方之间再根据三个随机数计算出最终的对称密钥,最后再发一条测试信息,能够正常加解密则代表密钥可用,从而完成了整个握手流程。

2.3.6、HTTPS中对于TLS握手的优化

由于TLS握手过程比较繁杂,因此在HTTPS中也有一些优化策略,如会话复用,而会话复用即恢复会话,主要有两种方式,一种是Session-ID,另一种则是Session Ticket,先聊聊Session-ID。

在TLS握手的第一步Client Hello中,会附带session id值,如果是新的客户端第一次建立连接时,该值为空,但如果是之前建立过安全连接的客户端,那么在这个信息中会附带上次的ID,如果上次在服务端中存储的Session还未过期,那么则会直接复用上次的会话,并不需要再次经过复杂的握手步骤建立连接。

但这种方式的缺陷也很明显,一方面是对服务端会造成比较大的存储压力,第二方面则是如果服务端做了负载均衡,那么还需要解决session一致性的问题。

因此在这种方式之外,TLS/1.3版本中,出现了另外一种策略:Session Ticket。这种方式的原理时,在握手完成并建立加密通信成功后,会将当前的通信对称密钥、加密方法等会话信息,通过SessionTicket发送给客户端保存。通过这种方式,因为会话信息是存储在客户端,所以不管请求被分发给哪台机器,当服务器将其解密后,如果会话未过期的情况下,那最终都能够获取上次会话的信息,这样就无需重新生成密钥了,而且还能大大减轻服务器的存储压力。