一文助你理解HTTPS

150 阅读9分钟

前言

地球人都知道,HTTPS是为了让网络通讯更加的安全,但是真要说清楚它的工作原理,似乎又没那么容易。看过很多讲解的文章、博客,但是过不了多久就又会忘记。直到我偶然看到了一段HTTPS的视频讲解,我才对它的工作原理有了深刻的理解,在此与大家分享。

基本概念

在介绍https的描述中,又出现了一些 SSL/TLS 等一些专业的术语,本文不打算去解释这些枯燥而又难以理解的专业术语的概念,只打算用图文结合的方式,讲解一下https的工作原理。

HTTP

image.png

传统的http协议是应用最广泛的纯文本数据的传输协议,客户端每发送一次网络请求,都会经历多个中间的网络节点到达服务端(如上图所示)。然而传统的http请求传输的时候都使用的是明文,所以说上述的多个中间网络节点,都有可能拦截并读取你的一切网络请求的数据,这里就出现了一个著名的说法,在网络上裸奔。

对称加密

image.png

针对上面出现的明文问题,聪明的小伙伴已经开始想办法解决了。比如在客户端发送数据包之前,可以用一套 算法+密码,对我要发送的数据进行加密,然后再交给网络去传输,这样只要保证只有客户端和真正的服务器有对应的密码(算法不用担心,因为浏览器本身就内置了很多加密算法),中间的网络节点拿不到密码,也就无法解开数据包,这样也就保证了通信的安全性。

其实,这个就是我们通常所说的对称加密了。但是这个设计还是存在问题,存在的问题是,客户端怎么把加密的密码传输给服务端呢。如果还是经由网络去传输,那么必然还是要经历中间的网络节点,用来加密数据的密码依然有可能被中间的网络节点截获,那么这套设计就完全不可用了。除非这个密码由服务端来生成,然后通过离线的方式交给客户端。

事实上,这种离线方式交付密码的方式是的确有过落地场景的。

image.png

不知道大家有没有用过最早的网银(暴露年龄了😂),跑到银行办理网银业务,银行都会给你发一个U盾,当你要使用网银业务的时候,必须要在电脑的USB接口上插上这个U盾。事实上,这个U盾里就内置了网银服务器给客户端生成的加密密码(离线加密狗)。有了这个离线交付密码的过程,上述的对称加密方案就是一个比较安全的通信方式了。因为只有客户端和服务端知道这个密码,并且这个密码不用通过网络进行传输。

非对称加密

上述使用对称加密的方案对网络数据进行加密的缺点是显而易见的,世界上有那么多的网站,又有那么多的人,每个网站的服务器,需要为每一个想要来访问我网站的用户以离线的方式交付一个U盾,这显然是不现实的。

想要使用对称加密的方法进行网络传输,关键的矛盾点就转化为如何在网络中传输对称加密的密码并且不被外泄。

这个时候,非对称加密就登场了。网站拥有者通过 OpenSSL(可以理解成一种工具)一对秘钥,分别称为公钥和私钥。公钥和私钥最明显的特点就是:

用私钥加密的数据,公钥可以解开,用公钥加密的数据,私钥可以解开。但是,用公钥加密的数据,公钥是无法解开的!

这是https最最最核心的原理,请大家一定要记住。

image.png

有了上面的原理之后,我们来看一看能做些什么,是不是可以解决掉对称加密的问题了。首先,客户端跟服务端进行tcp三次握手连接,在加一次握手,客户端会告诉服务端自己支持的加密算法,这个时候服务端会判断自己是否也支持这样的加密算法,如果支持了,服务端就会返回给客户端accept消息,并下发自己的公钥。客户端拿到公钥之后,随机生成一段密码,注意,这里的密码是指上述的对称加密要用到的密码,然后用服务端下发的公钥,对这个密码进行加密并回传给服务端,服务端拿到密文之后,用自己的私钥解开密文,就拿到了对称加密的密码,这样,客户端和服务端都有了相同的对称加密的算法和密码,之后的通信,就可以通过对称加密进行,这样就保证了安全性。

这个时候,我们再来看看假设中间有拦截者,他能做些什么。如上面的图所示,中间的拦截者,可以拦截到服务端的公钥(因为是以明文传输的),还可以拦截到客户端用服务端公钥加密过的对称加密的密码的密文(这个地方可能有些拗口,但是大家仔细阅读,肯定可以理解)。由于中间拦截者只有服务端的公钥,没有私钥,所以他是没法解开这段密文,也就没法知道对称加密的密码!到此,是不是完美解决了之前提到的核心矛盾点:对称加密的密码在网络过程中不被外泄!

然而事实上,上面的过程还是会出现问题,来看下面的图:

image.png

拦截者可以直接拦截客户端的第一次请求,然后冒充服务端,下发自己的公钥。对于服务端来说,拦截者又可以冒充客户端,拿到真正的服务端公钥。这样拦截者两头冒充,就仿佛是个透明的传话人,依然做不到安全的交流通信。

CA & 证书

很明显,光靠客户端和服务端两个角色,已经无法解决上面的问题了,这个时候就需要引入值得信任的第三机构了。这就引出了https中经常要被提及的CA和证书的概念了。

什么是证书,顾名思义,证书就是证明你身份的物件。举个例子,假设你说你是清华大学毕业的高材生,那你怎么证明呢?那你就必须拿出你清华大学的毕业证,那又怎么证明你这个清华大学的毕业证是真的呢?那就要看证书上是不是有清华大学的钢印,是不是有清华大学校长的私人的印章。如果这些都有,那就能确认你确实是清华毕业的高材生。

同理,服务端怎么向客户端证明,我就是真正的服务端呢。那服务端就必须向大家公认的可信任的第三方机构(CA)申请证书,CA机构通过一些操作(具体是什么操作大家自行查阅,这里不做介绍),确认你是真正的服务端,然后就会给你颁发证书,证书里包含的内容包括服务端的 域名+子域名,邓白氏编码,营业执照,服务端的公钥 等信息。需要注意的是,此时CA机构会用自己的私钥对这份证书进行加密。 将加密过后的证书,颁发给真正的服务端。

那么CA机构在客户端又做了什么呢?事实上,CA机构会把自己的公钥,内置到操作系统中,注意,这里的CA机构的公钥,是内置到操作系统中的,所以全世界也就那么几家CA机构。这个时候,客户端和服务端建立连接之后,服务端只需要直接向客户端下发自己的证书就可以了。

那么这么做了以后,是不是就能解决上述的拦截者的问题了呢?咱们来看图:

image.png

服务端跟客户端建立连接之后,直接下发证书给客户端,客户端拿到证书之后,可以通过内置在操作系统中的CA的公钥,解开证书,拿到真正的服务端的公钥。然后继续上面介绍过的非对称加密和对称加密的过程,就能跟服务端进行安全的通信了。

那么接下来我们来看看这种情况下,拦截者为什么就不行了呢。首先,要明确之前拦截者能work的关键点在于,拦截者拦截了真正的服务端的公钥,替换成了自己的公钥,冒充了服务端跟客户端通信。而在加入CA机构和证书后,这条路就走不通了,原因是拦截者没有CA机构的私钥!从上面的图中可以看到,拦截者也是可以拦截服务端的证书的,也是可以解开这个证书的(因为拦截者也内置了CA机构的公钥),拦截者也可以拿到服务端的公钥,但是他却不能替换这个公钥,因为他想要替换这个公钥的话,必须要把自己的公钥再次写入证书,然而这个时候拦截者是没有CA机构的私钥的,所以他是没有办法伪造出一模一样的证书的。而拦截者用自己私钥加密的证书发送给客户端时,客户端是不认这个证书的,或者说,客户端是解不开这个证书的,因为客户端浏览器只认操作系统中默认内置的CA机构的那些公钥。由此,这条冒充之路到这儿就断开了。

至此,https工作原理介绍完毕,希望对大家有所帮助。

遗留问题:既然非对称加密已经可以work,为什么还需要对称加密?这个问题留给大家解决吧。

相关概念

SSL/TLS

X.509

OpenSSL

CA

RSA算法