完全搞懂HTTPS的加密机制

HTTPS(SSL/TLS)的加密机制虽然是个前端后端开发都应了解的基本问题,但网上的不少HTTPS相关文章也总会忽略一些内容,我学习它的时候也废了挺大功夫。
对称加密、非对称加密、数字签名、数字证书等等,在学习过程当中,除了了解“它是什么”,你是否有想过“为何是它”?我认为理解了后者才真正理解了HTTPS的加密机制。
本文以问题的形式逐步展开,一步步解开HTTPS的面纱,但愿能帮助你完全搞懂HTTPS。特别是对于了解过HTTPS却在有些地方有所卡壳的人,但愿本文能帮助你理清思路。前端

为何须要加密?

由于http的内容是明文传输的,明文数据会通过中间代理服务器、路由器、wifi热点、通讯服务运营商等多个物理节点,若是信息在传输过程当中被劫持,传输的内容就彻底暴露了,他还能够篡改传输的信息且不被双方察觉,这就是中间人攻击。因此咱们才须要对信息进行加密。最直接的加密方式就是对称加密git

什么是对称加密?

就是有一个密钥,它能够对一段内容加密,加密后只能用它才能解密看到本来的内容,和咱们平常生活中用的钥匙做用差很少。github

用对称加密可行吗?

若是通讯双方都各自持有同一个密钥,且没有别人知道,这两方的通讯安全固然是能够被保证的(除非密钥被破解)。
然而最大的问题就是这个密钥怎么让传输的双方知晓,同时不被别人知道。若是由服务器生成一个密钥并传输给浏览器,那这个传输过程当中密钥被别人劫持弄到手了怎么办?以后他就能用密钥解开双方传输的任何内容了,因此这么作固然不行。
换种思路?试想一下,若是浏览器内部就预存了网站A的密钥,且能够确保除了浏览器和网站A,不会有任何外人知道该密钥,那理论上用对称加密是能够的,这样浏览器只要预存好世界上全部HTTPS网站的密钥就行啦!这么作显然不现实。
怎么办?因此咱们就须要神奇的非对称加密算法

什么是非对称加密?

有两把密钥,一般一把叫作公钥、一把叫作私钥,用公钥加密的内容必须用私钥才能解开,一样,私钥加密的内容只有公钥能解开。后端

用非对称加密可行吗?

鉴于非对称加密的机制,咱们可能会有这种思路:服务器先把公钥直接明文传输给浏览器,以后浏览器向服务器传数据前都先用这个公钥加密好再传,这条数据的安全彷佛能够保障了!由于只有服务器有相应的私钥能解开这条数据
然而由服务器到浏览器的这条路怎么保障安全?若是服务器用它的的私钥加密数据传给浏览器,那么浏览器用公钥能够解密它,而这个公钥是一开始经过明文传输给浏览器的,这个公钥被谁劫持到的话,他也能用该公钥解密服务器传来的信息了。因此目前彷佛只能保证由浏览器向服务器传输数据时的安全性(其实仍有漏洞,下文会说),那利用这点你能想到什么解决方案吗?浏览器

改良的非对称加密方案,彷佛能够?

咱们已经理解经过一组公钥私钥,已经能够保证单个方向传输的安全性,那用两组公钥私钥,是否是就能保证双向传输都安全了?请看下面的过程:安全

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

的确能够!抛开这里面仍有的漏洞不谈(下文会讲),HTTPS的加密却没使用这种方案,为何?最主要的缘由是非对称加密算法很是耗时,特别是加密解密一些较大数据的时候有些力不从心,而对称加密快不少,看来必须得用对称加密,那咱们能不能运用非对称加密的特性解决前面提到的对称加密的问题?服务器

非对称加密+对称加密?

既然非对称加密耗时,非对称加密+对称加密结合能够吗?并且得尽可能减小非对称加密的次数。固然是能够的,并且非对称加密、解密各只需用一次便可。
请看一下这个过程:session

  1. 某网站拥有用于非对称加密的公钥A、私钥A’。
  2. 浏览器像网站服务器发送请求,服务器把公钥A明文给传输浏览器。
  3. 浏览器随机生成一个用于对称加密的密钥X,用公钥A加密后传给服务器。
  4. 服务器拿到后用私钥A’解密获得密钥X。
  5. 这样双方就都拥有密钥X了,且别人没法知道它。以后双方全部数据都用密钥X加密解密。

完美!HTTPS基本就是采用了这种方案。完美?仍是有漏洞的。性能

中间人攻击

中间人的确没法获得浏览器生成的密钥B,这个密钥自己被公钥A加密了,只有服务器才有私钥A’解开拿到它呀!然而中间人却彻底不须要拿到密钥A’就能干坏事了。请看:

  1. 某网站拥有用于非对称加密的公钥A、私钥A’。
  2. 浏览器向网站服务器请求,服务器把公钥A明文给传输浏览器。
  3. 中间人劫持到公钥A,保存下来,把数据包中的公钥A替换成本身伪造的公钥B(它固然也拥有公钥B对应的私钥B’)
  4. 浏览器随机生成一个用于对称加密的密钥X,用公钥B(浏览器不知道公钥被替换了)加密后传给服务器。
  5. 中间人劫持后用私钥B’解密获得密钥X,再用公钥A加密后传给服务器
  6. 服务器拿到后用私钥A’解密获得密钥X。

这样在双方都不会发现异常的状况下,中间人获得了密钥B。根本缘由是浏览器没法确认本身收到的公钥是否是网站本身的。那么下一步就是解决下面这个问题:

如何证实浏览器收到的公钥必定是该网站的公钥?

现实生活中,若是想证实某身份证号必定是小明的,怎么办?看身份证。这里政府机构起到了“公信”的做用,身份证是由它颁发的,它自己的权威能够对一我的的身份信息做出证实。互联网中能不能搞这么个公信机构呢?给网站颁发一个“身份证”?

数字证书

网站在使用HTTPS前,须要向“CA机构”申请颁发一份数字证书,数字证书里有证书持有者、证书持有者的公钥等信息,服务器把证书传输给浏览器,浏览器从证书里取公钥就好了,证书就如身份证同样,能够证实“该公钥对应该网站”。然而这里又有一个显而易见的问题了,证书自己的传输过程当中,如何防止被篡改?即如何证实证书自己的真实性?身份证有一些防伪技术,数字证书怎么防伪呢?解决这个问题咱们就基本接近胜利了!

如何放防止数字证书被篡改?

咱们把证书内容生成一份“签名”,比对证书内容和签名是否一致就能察觉是否被篡改。这种技术就叫数字签名

数字签名

这部份内容建议看下图并结合后面的文字理解,图中左侧是数字签名的制做过程,右侧是验证过程(原图出处找不到了,能够看出来这图已经被转载了无数次了。。。)

数字签名的制做过程:

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

明文和数字签名共同组成了数字证书,这样一份数字证书就能够颁发给网站了。
那浏览器拿到服务器传来的数字证书后,如何验证它是否是真的?(有没有被篡改、掉包)

浏览器验证过程:

  1. 拿到证书,获得明文T,数字签名S。
  2. 用CA机构的公钥对S解密(因为是浏览器信任的机构,因此浏览器保有它的公钥。详情见下文),获得S’。
  3. 用证书里说明的hash算法对明文T进行hash获得T’。
  4. 比较S’是否等于T’,等于则代表证书可信。

为何这样能够证实证书可信呢?咱们来仔细想一下。

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

假设中间人篡改了证书的原文,因为他没有CA机构的私钥,因此没法获得此时加密后签名,没法相应地篡改签名。浏览器收到该证书后会发现原文和签名解密后的值不一致,则说明证书已被篡改,证书不可信,从而终止向服务器传输信息,防止信息泄露给中间人。
既然不可能篡改,那整个证书被掉包呢?

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

假设有另外一个网站B也拿到了CA机构认证的证书,它想搞垮网站A,想劫持网站A的信息。因而它成为中间人拦截到了A传给浏览器的证书,而后替换成本身的证书,传给浏览器,以后浏览器就会错误地拿到B的证书里的公钥了,会致使上文提到的漏洞。
其实这并不会发生,由于证书里包含了网站A的信息,包括域名,浏览器把证书里的域名与本身请求的域名比对一下就知道有没有被掉包了。

为何制做数字签名时须要hash一次?

我初学HTTPS的时候就有这个问题,彷佛以上过程当中hash有点多余,把hash过程去掉也能保证证书没有被篡改。
最显然的是性能问题,前面咱们已经说了非对称加密效率较差,证书信息通常较长,比较耗时。而hash后获得的是固定长度的信息(好比用md5算法hash后能够获得固定的128位的值),这样加密解密就会快不少。
固然还有安全上的缘由,这部份内容相对深一些,感兴趣的能够看这篇解答:crypto.stackexchange.com/a/12780

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

大家可能会发现上文中说到CA机构的公钥,我几乎一笔带过,“浏览器保有它的公钥”,这是个什么保有法?怎么证实这个公钥是否可信?
让咱们回想一下数字证书究竟是干啥的?没错,为了证实某公钥是可信的,即“该公钥是否对应该网站/机构等”,那这个CA机构的公钥是否是也能够用数字证书来证实?没错,操做系统、浏览器自己会预装一些它们信任的根证书,若是其中有该CA机构的根证书,那就能够拿到它对应的可信公钥了。

实际上证书之间的认证也能够不止一层,能够A信任B,B信任C,以此类推,咱们把它叫作 信任链数字证书链,也就是一连串的数字证书,由根证书为起点,透过层层信任,使终端实体证书的持有者能够得到转授的信任,以证实身份。

另外,不知大家是否遇到过网站访问不了、提示要安装证书的状况?这里安装的就是跟证书。说明浏览器不认给这个网站颁发证书的机构,那么没有该机构的根证书,你就得手动下载安装(风险本身承担XD)。安装该机构的根证书后,你就有了它的公钥,就能够用它验证服务器发来的证书是否可信了。

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

这也是我当时的困惑之一,显然每次请求都经历一次密钥传输过程很是耗时,那怎么达到只传输一次呢?用session就行。
服务器会为每一个浏览器(或客户端软件)维护一个session ID,在TSL握手阶段传给浏览器,浏览器生成好密钥传给服务器后,服务器会把该密钥存到相应的session ID下,以后浏览器每次请求都会携带session ID,服务器会根据session ID找到相应的密钥并进行解密加密操做,这样就没必要要每次从新制做、传输密钥了!

总结

能够看下这张图,梳理一下整个流程(SSL、TSL握手有一些区别,不一样版本间也有区别,不过大体过程就是这样):

(出处:www.extremetech.com)


至此,咱们已自下而上地打通了HTTPS加密的整个脉络以及核心知识点,不知你是否真正搞懂了HTTPS呢?
找几个时间,多看、多想、多理解几回就会愈来愈清晰的!

那么,下面的问题你是否已经能够解答了呢?

  1. 为何要用对称加密+非对称加密?
  2. 为何不能只用非对称加密?
  3. 为何须要数字证书?
  4. 为何须要数字签名?


固然,因为篇幅所限和能力所限,一些更深刻的内容没有覆盖到。但我认为通常对于先后端工程师来讲,了解到这步就够了,有兴趣的能够再深刻研究~若有疏漏之处,欢迎指出。

这篇文章也是对我学习时的一些总结和个人一些理解,一共花了快一天才写完。若是你喜欢这篇文章,欢迎点赞分享~感谢!