1. HTTP存在的问题

传统的不使用SSL/TLS的HTTP协议,是不加密的通信。无论是客户端发送给服务端的请求体,还是服务端响应给客户端的响应体,都是明文传输的,这会带来几个问题:

1. 窃听 第三方劫持请求后可以获取通信内容。对于一些敏感数据,这是不被允许的。

2. 篡改 第三方劫持请求后可以篡改通信内容。例如银行系统中,张三本来要给李四转账,第三方劫持请求后篡改了请求数据,将收款方改为自己,导致用户资金流失。

3. 冒充 第三方可以冒充客户端发送数据。由于是明文传输,没有「加签/验签」操作,服务端无法保证请求来源的合法性。

正是因为这些问题,HTTP通信存在巨大的安全隐患,于是HTTPS出现了。 本文将一步步深入,看看HTTPS是如何解决这些问题的。


2. SSL/TLS

在介绍HTTPS之前,必须先了解SSL/TLS协议,因为HTTPS是构建在此基础之上的,了解了SSL/TLS基本也就清楚HTTPS的工作原理了。

SSL(Secure Sockets Layer)译为「安全套接字协议」,TLS(Transport Layer Security)译为「传输层安全性协议」。

简单回顾一下它们的发展历史吧:

  • 1994年,网景公司设计了SSL协议(Secure Sockets Layer)的1.0版,但是未发布。
  • 1995年,网景公司发布SSL 2.0版,但很快发现有严重漏洞。
  • 1996年,SSL 3.0版问世,得到大规模应用。
  • 1999年,互联网标准化组织ISOC接替网景公司,发布了SSL的升级版TLS 1.0版。
  • 2006年和2008年,TLS进行了两次升级,分别为TLS 1.1版和TLS 1.2版。

SSL/TLS协议处于「传输层」和「应用层」之间,主要作用是对网络连接进行加解密,如下图: 在这里插入图片描述

2.1 防窃听:加密

先来看看第一个问题:窃听。既然明文传输可以被第三方窃听数据,那么改为加密传输不就行了吗? 方向是对的,但是如何加密才能保证数据的安全呢?

2.1.1 对称加密

采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密,这种加密方法称为对称加密,也称为单密钥加密。

例如DES就是一种对称加密算法,甲乙双方约定一个密钥「Key」,双方发送数据前都用该密钥对数据进行加密传输,收到数据后再解密成明文即可。这种方式,只要保证密钥不被泄漏,理论上也是安全的。

在这里插入图片描述

但是这会带来一个新的问题:密钥如何保存?

对于PC端来说,浏览器页面是明文的,肯定不能存储密钥。对于iOS/Android来说,即使把密钥藏在安装包的某个位置,也很容易被第三方拆包破解。

既然客户端保存不靠谱,那么密钥只在服务端保存,客户端去向服务端拿密钥是否可行?

依然不可行,服务端要怎么把密钥给你呢?明文肯定不行,如果要加密,又要用到密钥B,密钥B的传输又要用到密钥C,如此循环,无解。

2.1.2 非对称加密

非对称加密算法需要两个密钥:公开密钥(publickey:简称公钥)和私有密钥(privatekey:简称私钥)。公钥与私钥是一对,如果用公钥对数据进行加密,只有用对应的私钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。

甲乙双方各有一套自己的密钥对,互相公开彼此的公钥,当甲方要发送数据给乙方时,用乙方公钥加密,这样密文就只有乙方自己能解开了,就算请求被劫持,第三方拿到了数据,由于没有乙方的私钥,也无法解密,这样就保证了数据被窃听。

单向非对称加密 绝大多数互联网网站对外是完全公开的,所有人都可以访问,服务端没必要验证所有客户端的合法性,只有客户端需要验证服务端的合法性。例如用户在访问电商网站时,必须确保不是钓鱼网站,以防资金损失。

这种情况下,只需要单向加密即可。服务端发送给客户端的一般不会有敏感信息,明文传输即可。但是客户端发送给服务端的就很有可能是敏感信息,例如用户修改密码,这时就必须加密传输了。 在这里插入图片描述

双向非对称加密 有时,服务端也需要验证客户端的合法性,例如银行系统。由于涉及到金钱,因此系统必须设计的足够安全。除了客户端发送给服务端的数据是加密的,服务端发送给客户端的数据也必须加密。

怎么做的呢?一般银行会给用户一个U盘,里面存储的就是一套密钥对,客户端告诉服务端自己的公钥,服务端根据公钥加密后再传输给客户端。 在这里插入图片描述

2.2 防篡改:加签

通过非对称加密的密文传输,可以防止数据被窃听,但是如果存在这种场景呢?

张三登陆银行系统,要给李四转一笔钱,数据通过服务端的公钥PubB加密传输,但是第三方劫持了这个请求,篡改了报文数据,写入的是「给王五转钱」,因为服务端的公钥是公开的,谁都能拿到,因此第三方也可以正常加密传输,服务端正常解密后进行了错误的操作,导致用户资金流失。 在这里插入图片描述

对于涉及到资金的操作,服务端必须要验证数据的合法性,确保数据没有被篡改,这就需要客户端对数据进行加签了。

非对称加密除了可以「公钥加密,私钥解密」外,还可以「私钥加签,公钥验签」。

银行给用户一个U盘,里面有一套密钥对。客户端在发送转账请求前,先对请求体加签,得到签名「sign」,然后再用服务端公钥加密,得到密文「data」,客户端将签名和密文一起发送给服务端,服务端解密后,还需要用客户端的公钥对「sign」进行验签,只有验签通过才能进行后续操作,否则就是非法请求了。 在这里插入图片描述 这样,即使请求被第三方劫持了,第三方可以篡改数据,但是签名它改不了,服务端解密后会发现数据和「sign」对不上,说明数据是被篡改过的。

2.3 防冒充:证书

通过加密防止数据被窃听,通过加签防止数据被篡改,现在看来好像已经很安全了,但是别忘了,有个前提是:公钥的传输是安全的。不幸的是,公钥的安全传输很难保证。

中间人攻击 假设存在这样一种场景,客户端和服务端想互换公钥,但是请求都被一个中间人劫持了,结果就是:服务端和客户端以为是和双方互换公钥了,结果是客户端和服务端都和中间人互换公钥了。 在这里插入图片描述 一旦出现这种问题就非常严重,前面讲到的加密解密、加签验签都失效了。客户端以为中间人就是服务端,服务端以为中间人就是客户端,双方以为是在和对方通信,其实都是在和中间人通信,中间人可以随意的窃听和篡改数据。

这个问题之所以会出现,就是因为公钥的传输是不安全的。客户端和服务端之间互换公钥时,如何确保公钥就是对方发出的,没有被篡改过呢???

2.3.1 数字证书与认证中心

在之前的基础上,引入一个中间角色:证书认证中心CA。当服务端要把公钥发送给客户端时,不是直接发送公钥,而是先把公钥发送给CA,CA根据公钥生成一份「证书」给到服务端,服务端将证书给客户端。客户端拿到证书后去CA验证证书的合法性,确保证书是服务端下发的。

CA就类似于「公证处」,也是一台服务器,它自己本身也有一套密钥对。它的工作就是根据服务端的公钥生成证书,然后帮助客户端来验证证书的合法性。 在这里插入图片描述

2.3.2 CA被冒充怎么办?

引入CA可以保证公钥的传输安全,但是有一个前提,客户端和服务端是信任CA的,也就是说CA必须是安全可信任的,如果CA被冒充,就又会出现上面的问题。 在这里插入图片描述 基于这个问题,就引入了「根证书」和「CA信任链」的概念。

要让客户端和服务端信任CA,其实CA也面临着同样的问题,那就是:如何保证CA的公钥是安全不被篡改的?答案也是一样的,就是给CA也颁发证书,那这个证书由谁来颁发呢?自然是CA的上一级CA了。CA的上一级CA如何保证安全?那就CA的上一级CA的上一级CA给它颁发证书了。最终就会形成一个证书信用链,如下: 在这里插入图片描述 客户端要想验证服务器的C3证书是否合法,会跑去CA2验证,要验证CA2就去CA1验证,以此类推。对于根证书,是没法验证的,只能无条件相信。因为Root CA都是国际上公认的机构,一般用户的操作系统或浏览器在发布时,就会在里面嵌入这些机构的Root证书。

如下是百度官网的证书,点击浏览器地址栏旁边的锁标识就能看到了。 在这里插入图片描述

2.4 SSL/TLS 四次握手

了解了底层的实现,加密、加签、证书等概念后,再来看SSL/TLS协议就很容易理解了。SSL/TLS需要四次握手的过程:

  1. 客户端向服务端所有证书。
  2. 服务端发送证书。
  3. 客户端验证证书,提取公钥,发送对称加密的密钥。
  4. 服务端收到密钥,响应OK。

在这里插入图片描述

3. 再看HTTPS

了解SSL/TLS,再回过头来看HTTPS就很简单了,HTTPS=HTTP+SSL/TLS。

使用HTTPS进行通信时,先是建立传输层TCP的连接,完成三次握手,然后再是SSL/TLS协议的四次握手,双方协商出对称加密的密钥,之后的通信数据会利用该密钥进行加密传输。 在这里插入图片描述 HTTP1.1开始支持长连接了,只要连接不关闭,七次握手只需要执行一次,性能损耗不会太大,而且数据传输采用的是对称加密,相比于非对称加密,性能损耗也小得多。因此HTTPS相比于HTTP,性能会有一定影响,但不会太大,相比之下,数据传输安全显得更加重要!

HTTPS使用对称加密和非对称加密结合

传输数据阶段依然使用对称加密,但是对称加密的秘钥我们采用非对称加密传输。

HTTPS加密

  • 浏览器向服务器发送client_random和加密方法列表。
  • 服务器接收到,返回server_random、加密方法以及公钥。
  • 浏览器接收,接着生成另一个随机数pre_master, 并且用公钥加密,传给服务器。(重点操作!)
  • 服务器用私钥解密这个被加密后的pre_master。

到此为止,服务器和浏览器就有了相同的 client_randomserver_randompre_master, 然后服务器和浏览器会使用这三组随机数生成对称秘钥。有了对称秘钥之后,双方就可以使用对称加密的方式来传输数据了。

CA (数字证书)

使用对称和非对称混合的方式,实现了数据的加密传输。但是这种仍然存在一个问题,服务器可能是被黑客冒充的。这样,浏览器访问的就是黑客的服务器,黑客可以在自己的服务器上实现公钥和私钥,而对浏览器来说,它并不完全知道现在访问的是这个是黑客的站点。

服务器需要证明自己的身份,需要使用权威机构颁发的证书,这个权威机构就是 CA(Certificate Authority), 颁发的证书就称为数字证书 (Digital Certificate)。

对于浏览器来说,数字证书有两个作用:

  1. 通过数字证书向浏览器证明服务器的身份
  2. 数字证书里面包含了服务器公钥

下面我们来看一下含有数字证书的HTTPS的请求流程

含有数字证书的HTTPS的请求流程

相对于不含数字证书的HTTPS请求流程,主要以下两点改动

  1. 服务器没有直接返回公钥给浏览器,而是返回了数字证书,而公钥正是包含数字证书中的;
  2. 在浏览器端多了一个证书验证的操作,验证了证书之后,才继续后序流程。