Https工作原理

365 阅读14分钟

前言

大家都知道,http和https相比,https更加安全。 为什么会更加安全呢?

  • HTTP本身是明文传输的,没有经过任何安全处理。在HTTP协议下,中间者可以随意嗅探用户搜索内容,窃取隐私甚至篡改网页。
  • HTTPS == HTTP+TLS/SSL,即HTTP下加入TLS/SSL层。 通常,http直接和TCP通信。使用SSL之后,就演变成先和SSL通信,再由SSL和TCP通信。 HTTPS的安全基础就是TLS/SSL。服务端和客户端的信息传输都会通过TLS/SSL进行加密,所以传输的数据都是加密之后的数据。

说到加密,我们可能会有这样的疑问:https怎么加密的?整个工作流程又是怎样的?接下来的内容回答了这俩问题哦!耐心往下看吧~

加密——解决内容可能被窃听的问题

对称加密

又叫共享密钥加密。指加密和解密使用相同密钥的加密算法。常见的对称加密算法有:DES, AES, RC4, IDEA。

单独使用对称加密,不谈浏览器和服务器是如何拥有秘钥A的,步骤可能是这样的: image.png **弊端:**持有密钥才能进行加密解密,如何安全地转交?在互联网上转发密钥时,中间人也许会拿到密钥。

非对称加密

什么是非对称加密

有两把钥匙,一把公钥,一把私钥。私有密钥不能让其他任何人知道,而公开密钥则可以随意发布,任何人都可以获得。用公钥加密的内容必须用私钥才能解开,同样,私钥加密的内容只有公钥能解开。利用这种方式,不需要发送私钥,也不必担心私钥被攻击者窃听而盗走。

非对称加密的弊端

  • 公钥是公开的,所以针对私钥加密的信息,黑客截获后可以使用公钥进行解密,获取其中的内容;
  • 公钥并不包含服务器的信息,使用非对称加密算法无法确保服务器身份的合法性,存在中间人攻击的风险,服务器发送给客户端的公钥可能在传送过程中被中间人截获并篡改;
  • 使用非对称加密在数据加密解密过程需要消耗一定时间,降低了数据传输效率;

使用非对称加密的两个方案

我们思考一下,如果我们去设计https,会使用什么方案来加密呢?也许会想到以下的两种方案:

非对称加密方案

鉴于非对称加密的机制,我们可能会有这种思路: image.png

  • 服务器先把公钥直接明文传输给浏览器;
  • 浏览器向服务器传数据前都先用这个公钥加密好再传。

这条数据的安全似乎可以保障了!因为只有服务器有相应的私钥能解开这条数据。但是,依然存在**问题:**如何保证服务器到浏览器这条路的安全性?

改良的非对称加密方案

我们已经理解通过一组公钥私钥,已经可以保证单个方向传输的安全性,那用两组公钥私钥,是不是就能保证双向传输都安全了?请看下面的过程: image.png

  1. 某网站服务器拥有用于非对称加密的公钥A、私钥A;浏览器拥有用于非对称加密的公钥B、私钥B
  2. 浏览器像网站服务器请求,服务器把公钥A明文给传输浏览器。
  3. 浏览器把公钥B明文传输给服务器。
  4. 之后浏览器向服务器传输的所有东西都用公钥A加密,服务器收到后用私钥A解密。由于只有服务器拥有这个私钥A可以解密,所以能保证这条数据的安全。
  5. 服务器向浏览器传输的所有东西都用公钥B加密,浏览器收到后用私钥B解密。同上也可以保证这条数据的安全。

为什么https没有用此方案:首先,这个方案的确可以!抛开这里面仍有的漏洞不谈(中间人攻击,下文会讲),最主要的原因是非对称加密算法非常耗时,特别是加密解密一些较大数据的时候有些力不从心,而对称加密快很多。

对称加密+非对称加密(HTTPS使用)

非对称加密非常耗时,而对称加密快很多,所以HTTPS采用了这种方式。请看下面的过程: image.png

  1. 某网站服务器拥有用于非对称加密的公钥A私钥A
  2. 浏览器向网站服务器发送请求;
  3. 服务器将公钥A明文传输给浏览器;
  4. 浏览器随机生成一个用于对称加密的密钥X,使用公钥A加密后传给服务器;
  5. 服务器使用私钥A解密后得到密钥X
  6. 这样双方都获得了密钥X,且别人无法知道它,之后双方所有数据都用密钥X加密解密。

**弊端:**单纯使用对称+非对称加密依然存在漏洞:中间人攻击。 所以除了对称+非对称,https当然还使用了其他技术,下面会讲到。

中间人攻击

中间人的确无法得到浏览器生成的密钥X,这个密钥被公钥A加密了,只有服务器拥有的私钥A才能解密。但是,中间人并不需要拿到私钥A就可以干坏事了!请看: image.png

  1. 某网站服务器拥有用于非对称加密的公钥A、私钥A
  2. 浏览器向服务器请求;
  3. 服务器把公钥A传给浏览器;
  4. 中间人生成公钥B、私钥B。再劫持到公钥A,保存下来,把数据包中的公钥A替换成自己伪造的公钥B。再传给浏览器。
  5. 浏览器实际接收到的只有中间人伪造的公钥B,它并不知道公钥被替换了。浏览器随机生成一个用于对称加密的密钥X,使用公钥B加密后传给服务器。
  6. 中间人劫持后使用公钥B解密后得到密钥X,再用公钥A加密后传给服务器。
  7. 服务器拿到后用公钥A解密得到密钥X

这样在浏览器服务器双方都不会发现异常的情况下,中间人得到了密钥X。原因在于:浏览器无法确认自己收到的公钥是不是网站自己的。为了解决这个问题,就需要使用数字证书。 **

数字证书——解决通信方身份可能被伪装的问题

解决通信方身份可能被伪装的问题,归根结底,即确认公钥是否可信,或者说确认服务器端是不是中间人伪装的。 我们可以使用数字证书来证明。数字证书向CA申请,我们先来看看CA是什么。 ** CA(Certification Authority) - 数字证书认证机构。类似于现实生活中的政府部门。

CA签发数字证书

  • 服务器的运营人员向第三方机构CA提交公钥、组织信息、个人信息(域名)等信息并申请认证;
  • CA通过线上、线下等多种手段验证申请者提供信息的真实性,如组织是否存在、企业是否合法,是否拥有域名的所有权等;
  • 如信息审核通过,CA会向申请者签发认证文件-证书。证书包含以下信息:申请者公钥、申请者的组织信息和个人信息、签发机构 CA的信息、有效时间、证书序列号等信息的明文同时包含一个签名。 其中签名的产生算法:首先,使用散列函数计算公开的明文信息的信息摘要,然后,采用 CA的私钥对信息摘要进行加密,密文即签名;

数字证书的内容

  • CA的信息
  • 申请者的信息
  • 证书本身的数字签名
  • 证书签名用到的Hash算法
  • 证书持有者公钥
  • 证书的有效时间
  • 证书序列号
  • ……

使用数字证书后

申请好数字证书后,服务器把证书传输给浏览器,浏览器从证书里取公钥就行了,证书就如身份证一样,可以证明“该公钥对应该网站”。此时,https的流程是这样的: image.png **依然存在问题:**中间人有可能把证书篡改或者直接掉包了,所以还需要验证证书。 **思考:**数字证书中签名的作用是什么?如何防止数字证书被纂改?

数字签名——解决报文可能遭篡改问题

**解决报文可能被纂改问题,归根结底,即确认数字证书是否可信。**数字证书中的签名其实就是数字签名。这里把签名单独抽出来讲。下图是证书中签名的生成和浏览器验证证书的过程。

数字签名的生成

  1. CA拥有非对称加密的私钥和公钥。
  2. CA对证书明文信息进行hash得到消息摘到。
  3. 对消息摘要用私钥加密,得到数字签名。

明文和数字签名共同组成了数字证书。这样的数字证书就可以发送给网站了。

浏览器验证证书

  1. 浏览器拿到证书后,得到明文T数字签名S
  2. 用CA机构的公钥对S解密(由于是浏览器信任的机构,所以浏览器保有它的公钥),得到摘要S’
  3. 用证书里说明的hash算法对明文T进行hash得到摘要T’
  4. 比较S’是否等于T’,等于则表明证书可信。
  5. 除了以上步骤外,浏览器还会验证证书相关的域名信息、有效时间等信息;客户端会内置信任CA的证书信息(包含公钥),如果CA不被信任,则找不到对应 CA的证书,证书也会被判定非法。

Https工作流程:

  1. 客户端发起HTTPS请求: 用户在浏览器中输入一个https网址,然后连接到server的443端口。
  2. 服务端返回事先配置好的公钥证书;
  3. 客户端验证证书: 比如是否在有效期内;证书的用途是否匹配客户端请求的站点;证书有没有在CRL吊销列表里,它的上一级证书是否有效,这个过程是递归的,直到验证到根证书(操作系统内置的Root证书或者Client内置的Root证书)。 如果验证通过,继续;否则,显示警告信息。
  4. 生成并发送加密后对称密钥:客户端使用伪随机数生成器生成加密所使用的对称密钥,用证书的公钥加密后,发送给服务器。
  5. 服务端获取对称密钥:服务端使用自己的私钥解密,得到对称密码。至此,服务端和客户端双方都拥有了相同的对称密钥,后续传送的数据就可以使用此对称加密了。
  6. 服务端使用对称密钥加密“明文内容A”,发送给客户端。
  7. 客户端使用对称密钥解密获得“明文内容A”。
  8. 客户端再次发起https请求,使用对称密钥加密请求的“明文内容B”。然后服务端使用对称密钥解密密文,得到“明文内容B”。

Q&A

中间人有可能篡改证书吗?

假设中间人纂改了证书的原文。由于他没有CA的私钥,所以他无法得到此时加密后的签名,无法相应地纂改签名。 浏览器收到证书后会发现原文hash后的值与签名解密后的hash值不一致,从而验证失败,证书不可信,便会终止向服务器传输信息,防止信息泄露给中间人。

思考:不能更改,那么把证书整个掉包呢?

中间人有可能把证书掉包吗?

假设中间人拦截到了服务器传给浏览器的证书,替换成伪造的证书后传给浏览器。之后浏览器就会错误地拿到伪造证书地公钥了。 但这并不会发生。中间人是没办法轻易伪造证书的。首先,申请证书时,中间人也必须向CA提交自己的信息,且这些信息必须真实。其次,就算中间人成功申请到了证书并替换,浏览器只需要对比信息就可以知道证书是否有效了。

为什么制作数字签名时需要hash一次?

最显然的是性能问题,前面我们已经说了非对称加密效率较差,证书信息一般较长,比较耗时。而hash后得到的是固定长度的信息(比如用md5算法hash后可以得到固定的128位的值),这样加密解密就会快很多。 当然还有安全上的原因,这部分内容相对深一些,感兴趣的可以看这篇解答:crypto.stackexchange.com/a/12780

怎么证明CA机构的公钥是可信的?

你们可能会发现上文中说到CA机构的公钥,我几乎一笔带过,“浏览器保有它的公钥”,这是个什么保有法?怎么证明这个公钥是否可信? 数字证书是为了证明网站服务器的公钥是可信的,即“该公钥是否对应该网站/机构等”,那这个CA机构的公钥是不是也可以用数字证书来证明?没错,操作系统、浏览器本身会预装一些它们信任的根证书,如果其中有该CA机构的根证书,那就可以拿到它对应的可信公钥了。 实际上证书之间的认证也可以不止一层,可以A信任B,B信任C,以此类推,我们把它叫做信任链数字证书链,也就是一连串的数字证书,由根证书为起点,透过层层信任,使终端实体证书的持有者可以获得转授的信任,以证明身份。 另外,不知你们是否遇到过网站访问不了、提示要安装证书的情况?这里安装的就是根证书。说明浏览器不认给这个网站颁发证书的机构,那么没有该机构的根证书,你就得手动下载安装(风险自己承担XD)。安装该机构的根证书后,你就有了它的公钥,就可以用它验证服务器发来的证书是否可信了。

HTTPS必须在每次请求中都要先在SSL/TLS层进行握手传输密钥吗?

第一次需要。服务器会为每个浏览器(或客户端软件)维护一个session ID,在TSL握手阶段传给浏览器,浏览器生成好密钥传给服务器后,服务器会把该密钥存到相应的session ID下,之后浏览器每次请求都会携带session ID,服务器会根据session ID找到相应的密钥并进行解密加密操作,这样就不必要每次重新制作、传输密钥了!

总结

  • Https使用的加密方案是:对称+非对称加密;
  • Https使用数字证书,解决通信方可能被伪装的问题(其实就是防止中间人伪装成Server端);
  • Https使用数字签名,解决报文可能遭篡改的问题(其实就是防止数字证书被篡改或掉包)。