HTTPS原理

HTTPS概述

在互联网领域,安全永远是一个重点关注的方向。现阶段HTTPS的安全指数显然要比HTTP高很多,前者也是互联网发展的必然趋势。为了鼓励全球网站的HTTPS实现,Google甚至调整了其搜索引擎算法,提升HTTPS网站的搜索排名。
那HTTPS和HTTP到底有什么区别呢?简单而言,HTTPS可以认为是HTTP+TLS/SSL。

SSL/TLS

作用

我们都知道不使用SSL/TLS的HTTP通信,即不加密的通信。其具有以下几个潜在的风险:
> (1) 窃听风险(eavesdropping):第三方可获知通信内容。
> (2) 篡改风险(tampering):第三方可以修改通信内容。
> (3) 冒充风险(pretending):第三方可以冒充他人进行通信。

而SSL/TLS的作用就是解决上述几个潜在的风险: > (1) 所有信息都是加密传播,第三方无法窃听。
> (2) 具备校验机制,一旦被篡改,通信双方会立刻发现。
> (3) 配备身份整数,防止身份被冒充。

历史

互联网加密通信协议的历史,几乎与互联网的历史一样长。
> 1994年,NetScape公司设计了SSL协议(Secure Socket Layer)的1.0版本,但是未发布。 > 1995年,NetScape公司发布SSL 2.0版,很快发现有严重漏洞。
> 1996年,SSL 3.0版本问世,得到大规模应用。
> 1999年,互联网标准化组织ISOC接替NetScape公司,发布了SSL的升级版TLS 1.0版本。
> 2006年和2008年,TLS进行了两次升级,分别为TLS 1.1版本和TLS 1.2版本。最新的变动是2011年TLS 1.2的修订版

目前,应用最广泛的是TLS 1.0,然后是SSL 3.0。不过,主流浏览器都已经实现了对TLS 1.2的支持。
通常,TLS 1.0会被标示为SSL 3.1,TLS 1.1会被标示为TLS 1.2会被标示为SSL 3.3。

原理

SSL/TLS协议的基本思路是采用公钥加密法,即:客户端先向服务器索要公钥,然后用公钥加密信息,服务器收到密文后,使用私钥解密。
而这个过程中需要解决两个问题:

  1. 如何保证公钥不被篡改?
  • 解决方法:将公钥放在数字证书中。只要证书是可信的,公钥就是可信的。
  1. 公钥加密法作为一种非对称加密算法,计算量比对称加密算法大很多,如何减少耗费时间?
  • 解决方法:每次会话(session),客户端和服务器端都生成一个"会话密钥"(session key),用它来加密信息。这里,客户端仅用公钥加密"会话密钥",而通信过程中的大量信息则用"会话密钥"来加密,由于大量使用对称加密算法,所以可以大幅减少加密运算的时间。

因此,SSL/TLS协议的基本过程如下:
> (1) 客户端向服务器索取并验证公钥。
> (2) 双方协商生成"会话密钥"。
> (3) 双方采用"会话密钥"进行加密通信。

其中,(1)(2)又称为"握手阶段"(handshake)。

握手阶段

如上图所示,"握手阶段"包含4次通信。而"握手阶段"的所用通信都是明文的。
下面分别介绍"握手阶段"的4次通信过程。

客户端发出请求(ClientHello)

ClientHello请求: 客户端(通常是浏览器)先向服务器发出加密通信的请求。
在这一步,客户端主要向服务器提供以下信息:
> (1) 支持的协议版本,如TLS 1.0版本。
> (2) 一个客户端生成的随机数,稍后用于生成"会话密钥"。
> (3) 支持的加密方法,如RSA公钥加密。
> (4) 支持的压缩方法。

需要注意的是,客户端发送的信息之中不包括服务器的域名。即理论上服务器只能包含一个网站,否则会分不清应该向客户端提供哪一个网站的数字证书。这就是为什么通常一台服务器只能有一张数字证书的原因。

但是,这对于虚拟主机用户来说,极为不便。为此,2006年,TLS协议加入了一个Server Name Indication扩展,允许客户端向服务器提供它所请求的域名。

服务器回应(ServerHello)

ServerHello: 服务器收到客户端请求后,向客户端发出回应。
在这一步,服务器端的回应包含以下内容:
> (1) 确认使用的加密通信协议版本,比如TLS 1.0版本。如果浏览器与服务器支持的版本不一致,服务器关闭加密通信。
> (2) 一个服务器生成的随机数,稍后用于生成"会话密钥"。
> (3) 确认使用的加密方法,如RSA公钥加密。
> (4) 服务器证书。

除了以上信息,如果服务器需要确认客户端的身份,就会再包含一项请求,要求客户端提供"客户端证书"。比如,金融机构往往只允许客户连入自己的网络,就会向正式客户提供USB密钥,里面就包含了一张客户端证书。

客户端回应

客户端收到服务器回应以后,首先验证服务器证书。如果证书不是可信机构颁布、或者证书中的域名与实际域名不一致、或者证书已经过期,就会向访问者显示一个警告,由其选择是否还要继续通信。

如果证书没有问题,客户端就会从证书中取出服务器的公钥。然后,向服务器发送下面三项信息。
> (1) 一个随机数。该随机数用服务器公钥加密,防止被窃听。
> (2) 编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送。
> (3) 客户端握手结束通知,表示客户端的握手阶段已经结束。本项的值为前面发送的所有内容的hash值,用于服务器校验,以防被篡改。

此过程中出现的随机数是整个握手阶段出现的第三个随机数,又称"premaster secret"。经过这个过程之后,服务器端和客户端就同时拥有了三个随机数,接着双方就用事先商定的加密方法,各自生成本次会话所用的同一把"会话密钥"。

但是为什么一定要用三个随机数来生成"会话密钥"呢?CSDN的dog250给出如下解释:
> "不管是客户端还是服务器,都需要随机数,这样生成的密钥才不会每次都一样。由于SSL协议中证书是静态的,因此十分有必要引入随机因素来保证协商出来的密钥的随机性。
> 对于RSA密钥交换算法来说,premaster secret本身就是一个随机数,再加上hello消息中的随机数,三个随机数通过一个密钥导出器最终导出一个对称密钥。
> Premaster secret的存在在于SSL协议不信任每个主机都能产生完全随机的随机数,如果随机数不随机,那么premaster secret就有可能被才出来,那么仅适用premaster secret作为密钥就不合适了,因此必须引入新的随机因素,那么客户端和服务器加上premaster secret三个随机数一同生成的密钥就不容易被猜出了,一个伪随机数可能完全不随机,可是三个伪随机数就十分接近随机了。"

此外,如果前一步,服务器要求客户端提供证书,客户端会在这一步发送证书及其相关信息。

服务器回应

服务器收到客户端的第三个随机数premaster secret之后,计算本次会话所需的"会话密钥"。
然后,向客户端发送以下信息:
> (1) 编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送。
> (2) 服务器握手结束通知,表示服务器的握手阶段已经结束。本项的值为前面发送的所有内容的hash值,用于服务器校验,以防被篡改。

至此,整个握手阶段全部结束。 接下来,客户端与服务器进入加密通信,就完全是使用普通的HTTP协议,只不过用"会话密钥"加密内容。

数字签名和数字证书

我们回顾一下SSL/TLS握手阶段的整个过程的一些关键点,来看看其中是否还有潜在的风险。
> (1) 客户端产生一个随机数A,以明文方式发给服务器。
> (2) 服务器产生一个随机数B,以明文方式发给客户端。此外,服务器还将公钥放入证书中发送给客户端。
> (3) 此时客户端拥有随机数A,B以及证书(公钥)。服务器拥有随机数A,B以及其私钥。
> (4) 客户端产生一个随机数C,使用公钥加密,发送给服务器,服务器以私钥解密,得到随机数C。此过程使用公钥加密法(非对称加密)。
> (5) 此时客户端和服务器使用三个随机数A,B,C,生成相同的成对的"会话密钥"。
> (6) 此后,客户端和服务器端进行通信采用"会话密钥"进行加密通信(对称加密),可以减少加解密时间,提高通信速度。

那么问题来了,步骤(2)中的证书是如何防止被窃听和篡改的呢?这个过程中似乎没有采用任何算法对其进行加密保护。我们知道随机数A,B作为明文可以被窃听,而如果证书也被篡改,恶意的第三方甚至就可以向用户提供自己的证书(公钥),将自己伪装成客户端想要通信的对象。最终可以获取用户的信息,达到其进一步的目的。

因此,客户端需要一种机制来确认其请求的服务器是否伪造的。而数字证书就像身份证一样可以证明服务器的真伪。

数字证书

数字证书由专门的机构"证书中心"(Certificate authority,简称CA)颁发。证书中心用自己的私钥,将服务器的公钥及其相关信息进行加密,生成"数字证书"(Digital Certificate)。

客户端(浏览器)的"证书管理器",有"受信任的根证书颁发机构"列表。客户端会根据这张列表,查看解开数字证书的公钥是否在列表之内。
如果数字证书记载的网址,与你正在浏览的网址不一致,就说明这张证书可能被冒用,浏览器会发出警告。
如果这张数字证书不是由受信任的机构颁发,浏览器会发出另一种警告。

如果数字证书是可靠的,客户端就可以使用证书中的服务器公钥,从而进行后续的通信加密相关操作。

数字签名

除了数字证书以外,我们经常还能看到的"数字签名"(Digital signature)又是什么呢?

数字签名是将公钥密码反过来使用。签名者将信息用私钥加密(这是一种反用,因为通常私钥是用于解密);验证者使用公钥解密信息。也就是说,客户端向服务器端发送消息是一种正向的公钥加密法(公钥加密,私钥解密);而服务器端向客户端发送消息则是一种公钥加密法的反向实现(私钥加密,公钥解密)。

数字签名的目的是为了防止通信内容被修改。
通信过程中,信息发送方对通信内容进行hash,并将产生hash值作为通信内容的摘要(digest)。
然后,使用私钥将摘要进行加密,得到数字签名。而接收端使用公钥即可解密得到摘要。
最终,客户端将通信内容进行hash,并与解密后得到的摘要进行比对,如果一致则表示内容未被篡改。

(完)

参考 [1] SSL/TLS协议运行机制的概述
[2] SSL协议中的DH算法的pre-master-secret
[3] 数字签名是什么?
[4] 数字签名
[5] 图解SSL/TLS