为什么要用 HTTPS
要回答这个问题,我们要先来看一下,在 HTTPS 之前我们用的 HTTP
HTTP 超文本传输协议(Hypertext Transfer Protocol)
HTTP 是一种超文本传输协议(Hypertext Transfer Protocol),它是一个在计算机世界里专门在两点之间传输文字、图片、视频等超文本数据的协议规范。
但是它存在几个问题:
- HTTP 天生明文传输,在 HTTP 的传输过程中,任何人都可能截获、修改或者伪造请求发送,所以可以认为 HTTP 是不安全的。
- HTTP 在传输过程中不会验证通信双方的身份,任何人都可以伪装成通信的一方,也就是没有用户验证。
- HTTP 在传输过程中,通信双方也不会验证报文的完整性。
为了解决上述问题,HTTPS 应运而生。
HTTPS 超文本安全传输协议(Hypertext Transfer Protocol Secure)
HTTPS 是 HTTP 的一种拓展,其本身并不保证数据传输的安全性。HTTPS 除了协议名和默认端口号443(HTTP 默认端口80)和 HTTP 不一样,其他的都一样,HTTP 有的,HTTPS 也全都有。能实现安全性,关键在于最后的 S ,也就是通过 TLS(传输层安全性)或 SSL(安全套接字层)对通讯协议进行加密来保证安全性。可以说 HTTPS = HTTP + (SSL || TLS)。
TLS
TLS,由 IETF(互联网工程组)在 1999 年将 SSL 进一步标准化然后改名而来。目前最广泛使用的是 1.2 版本,下面探讨的都是基于 1.2 版本。
TLS 为两个通讯应用程序之间提供保密性和保证数据的完整性。
TLS 由记录协议、握手协议、警告协议、变更密码规范协议、扩展协议等几个子协议组成。综合使用了对称加密、非对称加密、身份认证等许多密码学的前沿技术。
TLS 命名规范,[密钥交换算法]-[签名算法]-[对成加密算法]-[分组模式]-[摘要算法]
ECDHE-ECDSA-AES256-GCM-SHA384 // eg
TLS 是使用对称加密和非对称加密的混合方式来实现机密性。
HTTPS 工作流程
- 用户在浏览器发起 HTTPS 请求(如 juejin.im/,默认使用服务端的443端口进行连接;
- HTTPS 需要使用一套 CA数字证书,证书内会附带一个公钥 Pub,而与之对应的私钥 Private 保留在服务端不公开;
- 服务端收到请求,返回配置好的包含公钥 Pub 的证书给客户端;
- 客户端收到证书,校验合法性,主要包括是否在有效期内、证书的域名与请求的域名是否匹配,上一级证书是否有效(递归判断,直到判断到系统内置或浏览器配置好的根证书),如果不通过,则显示HTTPS警告信息,如果通过则继续;
- 客户端生成一个用于对称加密的随机 Key(对称密钥),并用证书内的公钥 Pub 进行加密,发送给服务端;
- 服务端收到随机 Key 的密文,使用与公钥 Pub 配对的私钥 Private 进行解密,得到客户端真正想发送的随机 Key;
- 服务端使用客户端发送过来的随机 Key 对要传输的 HTTP 数据进行对称加密,将密文返回客户端;
- 客户端使用随机 Key 对称解密密文,得到 HTTP 数据明文;
- 后续 HTTPS 请求使用之前交换好的随机 Key 进行对称加解密。
加密
对称加密 Symmetrical Encryption
加密和解密时使用的密钥都是同样的密钥,只要保证了密钥的安全性,也就保证了整个通信过程的机密性。
TLS 里面由比较多的加密算法可供使用,比如 DES、3DES、AES、ChaCha20、TDEA、Blowfish、RC2、RC4、RC5、IDEA、SKIPJACK 等。目前最常用的是 AES-128、AES-192、AES-256 和 ChaCha20。
其中 AES,Advanced Encryption Standard(高级加密标准),它是 DES 算法的替代者,安全性更高,性能也更好,是应用最广泛的对称加密算法。AES-128, AES-192 和 AES-256 都是属于 AES 。
对称加密的双方都是用同一个密钥,也就是加密方需要在加密完原始数据后,将密钥再传输交给解密方进行解密,而在传输过程中一旦密钥被截获,那么通信数据就暴露了。所以,对称加密是存在风险的。
加密分组
对于对称加密算法来说,它有一个加密分组的概念。以前的分组模式都被发现存在漏洞,所以基本不实用了。最新的分组模式被称为 AEAD(Authenticated Encryption with Associated Data),在加密的同时增加了认证的功能,常用的是 GCM、CCM 和 Poly1305。
对于 GCM 分组模式,只有和 AES,CAMELLIA 和 ARIA 搭配使用,而 AES 是最受欢迎和部署最广泛的选择,他可以让算法用固定长度的密钥加密任意长度的明文。
非对称加密 Asymmetrical Encryption
在非对称加密中,两个密钥相互对应成一组,一个是公钥,一个是私钥,公钥进行加密后,只有这个对应的私钥才能解密得到加密前的内容。
常见的非对称加密算法有 DH、DSA、RSA、ECC等。
其中 RSA 加密算法是最重要也是最出名的一个。它的安全性基于整数分解,使用两个超大的素数的乘积作为生成密钥的材料,想要从公钥推算出私钥是非常困难的。
但在通信过程中只用一组公钥私钥是存在安全问题的,只能保证单程信息的保密。
在 HTTPS 的传输场景下,在传输过程中服务端会将公钥传给客户端,私钥不进行传输只有自己知道。当客户端用公钥加密信息发送给服务端,服务端可以用私钥进行解密,这个过程因为私钥没有暴露,所以信息的保密的。但是当服务端要返回数据给客户端的时候,不能用公钥进行加密,因为客户端没有私钥可以解密,服务端只能用私钥进行加密,然后客户端用公钥进行解密,但是这个公钥在最开始进行传输过,那就有可能被截获,导致泄密。
注意,严格来说,私钥不能用于加密,只能用于生成签名,然后可用对应的公钥进行解签。
那一组不行,用两组总可以吧?来看下面的过程:
- 服务端有非对称加密的公钥 A1,私钥 A2。
- 客户端有非对称加密的公钥 B1,私钥 B2。
- 客户端向服务端发起请求,服务端将公钥 A1 返回给客户端。
- 浏览器收到公钥 A1,将自己保存的公钥 B1 发送给服务端。
- 之后服务端所有向客户端发送的数据,使用公钥 B1 加密,客户端可以使用私钥 B2 解密。
- 客户端所有向服务端发送的数据,使用公钥 A1 加密,服务端可以使用私钥 A2 解密。
此时两个方向都经过了非对称加密,双向的信息都是保密的。但是由于非对称加密运行较慢,远不如对称加密快,所以使用上述方案会造成性能问题,影响用户体验。
混合加密
加密过程中使用对称加密和非对称加密的加密方式称为混合加密。
非对称加密运行速度较慢,对称加密运行速度较快,所以用对称密钥对较大的明文进行加密得到密文,然后用公钥给对称密钥进行加密得到会话密钥,以此保证性能,然后传递密文和会话密钥。我们来看一下请求过程:
- 服务端有公钥 A1 和私钥 A2。
- 客户端发起请求时服务端将公钥 A1 发送给客户端。
- 客户端随机生成一个对称密钥 S,然后用公钥 A1 对密钥 S 进行加密得到会话密钥 S2。
- 客户端将 S2 发送给服务端,服务端通过私钥 A2 对 S2 进行解密得到对称密钥 S,这样,双方就实现了对称密钥 S 的安全交换,解决了单数使用对称加密时,对称密钥可能在传输过程中被截获的问题。
- 之后双方通信就都使用密钥 S 进行对称加解密。
就算在传输中被截获了密钥,那也是经过公钥加密的会话密钥,没有私钥无法解密,也就无法获得明文内容。
至此,就使用混合加密完成了传输的机密性。
看起来已经兼顾了安全和性能,但对于通信的安全性来讲,还不够,我们还要加上完整性和身份验证的特性,其中实现完整性的主要手段是摘要算法,身份验证主要靠 CA 机构颁发的证书。
摘要算法
摘要算法,可以将它理解为一种特殊的压缩加密算法,它能够把任意长度的输入压缩成一种固定长度的输出。通过摘要算法,用来保证传输数据的完整性或者说一致性。
常用的摘要算法有 MD5、SHA-1、SHA-2。
MD5
MD5 是属于密码哈希算法的一种,对于工作较久的同学们来说应该是比较熟悉的了。MD5 可以从任意长度的字符串得到一个几乎唯一的 128 位代码,称为 MD5 校验码,这个过程几乎不可逆。
其次,得到的这段校验码具有高度的离散型,只要原信息发生了一点点变化,都会导致校验码发生巨大变化。
最后,由于这个校验码有 128 位,所以任意信息经 MD5 算法之后得到的校验码相同的可能性非常低,通常被认为是不可能的。所以一般认为 MD5 校验码可以唯一地代表原信息的特征。通常用于密码的加密存储、数字签名、数据的完整性验证等。
但是如果用于密码加密的话,那么 MD5 并不安全,因为如果密码简单,通过反向查询或者找一个 MD5 解密网站,都很容易破解密码。所以一般会在使用 MD5 的时候通过加盐来提高安全性。
SHA-1 及其它
SHA-1
SHA-1 也是一种常用但不安全的加密算法,在 TLS 中被禁止使用。目前 TLS 推荐使用的是 SHA-2。
SHA-2
SHA-2 全称 Secure Hash Algorithm 2,SHA-2 系列包含六个哈希函数,其摘要(哈希值)分别为 224、256、384 和 512 位(SHA-224、SHA-256、SHA-384、SHA-512)。分别能够生成 28 字节、32 字节、48 字节、64 字节的摘要。
有了 SHA-2 的保护,就能够实现数据的完整性,因为只要数据有一点变化,生成的摘要文件都会不同。不过 SHA-2 是仅基于明文的加密方式,还是不够安全,这时候就要请 HMAC 出场了。
HMAC
MAC(Message Authentication Code,消息认证码),它是消息经过密钥加密再通过 MAC 算法进行摘要得出的代码,MAC 的值会根据消息内容发生更改而更改,根据 MAC 的值是否发生变化来判断原消息内容是否被篡改,从而保证消息内容的完整性。
HMAC 是特定类型的消息认证码,在 MAC 算法的基础上加入了哈希算法。任何哈希函数都可用于计算 HMAC,由此产生的 MAC 算法称为 HMAC-X,其中 X 就是使用的哈希函数(例如: HMAC-SHA256)。
AC 证书颁发机构
在 HTTPS 中依然考虑中间人攻击的情况,情况如下:
- 当服务端向客户端返回公钥 A1 的时候,中间人将其截获并替换成了自己的公钥 B1
- 客户端并不知情,还是用这个拿到的公钥 B1 去加密随机生成的对称密钥 S 发送给服务端
- 中间又被中间人截获,用自己的私钥 B2 解密得到 S,此时之后用于通信的对称密钥 S 就暴露了
- 中间人再用之前截获到的公钥 A1 进行加密发送给服务端
- 服务端用自己的私钥 A2 解密也能得到 S,后续再用这个已经被暴露的 S 进行通信的加解密
- 整个通讯链路已经通了,但中间人可以通过这个暴露的密钥 S 进行传输数据的解密还有修改,而服务端和客户端均不可知
上面这个情况的问题就出现在第一步服务端向客户端返回公钥的时候,客户端无法确定这到底是不是服务端传过来的,也就是无法验证服务端的身份。为了解决这个问题,就引入了一个公信机构,CA。
CA 会向申请人颁发一份数字证书,数字证书中包含有证书持有者、证书有效期、公钥等信息。服务端将证书也一起发送给客户端,客户端在校验证书内容和要访问的网站身份一致时,才进行后续的加密操作,这个步骤就是身份验证。
但是中间人如果只修改证书的公钥,客户端依旧不能确定证书是否被篡改,这个时候我们就需要用到一个防伪技术了,那就是数字签名。操作过程如下:
- CA 机构有自己的公钥 CA1 和私钥 CA2
- CA 机构在颁发证书时用证书里声明的哈希算法对证书信息进行哈希 Hash1
- 将得到的哈希值用自己的私钥进行加签(私钥加签、公钥解签),得到数字签名 Sign
这个时候,服务端将证书内容和数字签名 Sign 一起发给客户端。客户端此时操作如下:
- 客户端拿到证书内容和数字签名 Sign
- 客户端用 CA 的公钥 CA1(由于 CA 是公信机构,浏览器会内置 CA 机构的公钥)对 Sign 进行解签得到哈希值 Hash1
- 客户端再用证书中声明的哈希算法对证书内容进行哈希得到 Hash2
- 当自己解签得到的 Hash1 和 Hash2 一致时,表明证书没有被篡改
由于数字签名 Sign 是由 CA 机构的私钥 CA2 生成的,而中间人无法拿到这个私钥,如果中间人修改了证书内容,那么 Hash2 就肯定和 Hash1 不同,这样就保证了证书的内容没有被篡改,是可信的。
从中也可以知道 CA 机构的私钥是绝对私密的信息,如果 CA 机构的私钥一旦泄露,它将不再具有公信力。CA 机构有很多,也是有层级链的,这个感兴趣就请自行探索。
总结
HTTPS 的出现,主要是为了解决 HTTP 因为明文传输导致的信息被截取或篡改的问题。
HTTPS 使用混合加密方案加密明文,通过摘要算法保证信息完整性,引入证书解决身份验证问题。
文章参考: