这是计算机网络相关的第七篇文章。HTTPS(SSL/TLS)的加密机制是前端后端ios安卓等都应了解的基本问题。也是面试经常问的点。

一、为什么需要加密?

小时候看谍战片,情报发过来了之后,用一个小本本进行翻译,然后解密出情报。加密就是防止明文被别人看到甚至篡改嘛!

回到互联网,因为http的内容是明文传输的,明文数据会经过中间代理服务器、路由器、wifi热点、通信服务运营商等多个物理节点,如果信息在传输过程中被劫持,传输的内容就完全暴露了,他还可以篡改传输的信息且不被双方察觉,这就是中间人攻击。所以我们才需要对信息进行加密。最简单容易理解的就是对称加密 。

二、什么是对称加密?

image

小明写个求爱信给小红,小明担心小红的妈妈看到这封信的内容,他灵机一动,对信加个密,并确定好我用这个密钥加密的,小红收到之后也用这个密钥解密才行。

但是呢,这里有个麻烦的地方就是,小明和小红不在一个学校,这个钥匙呢,不方便直接送到手里。所以呢,小明得想办法把这个钥匙寄一个送给小红,好吧,就用最贵的顺丰吧!

就是有一个密钥,它可以对一段内容加密,加密后只能用它才能解密看到原本的内容,和我们日常生活中用的钥匙作用差不多。

三、用对称加密可行吗?

顺丰快递到了,结果小红不在家,小红的妈妈收到了,一看是个男同学寄的,怎么能忍住,赶紧打开,以看是一把钥匙,作为程序猿,妈妈得意一笑:哼哼,还能逃过我的眼睛?我赶紧复制一把藏着,我倒要看看他后面要寄啥来,还要加密?!

果然小红的妈妈等到了来自小明寄过来的情书,解密一看,实锤早恋。

同样地,小明这边也非常危险,快递员刚出发,就被小明的妈妈拦截了,拿到了这个钥匙,那小明还没寄出的信已经被妈妈看光了。

所以问题的根本就是,这把钥匙要传输,传输就可能被截取。

image

回到互联网,如果通信双方都各自持有同一个密钥,且没有别人知道,这两方的通信安全当然是可以被保证的(除非密钥被破解)。

然而最大的问题就是这个密钥怎么让传输的双方知晓,同时不被别人知道。

如果由服务器生成一个密钥并传输给浏览器,那这个传输过程中密钥被别人劫持弄到手了怎么办?

换种思路?试想一下,如果浏览器内部就预存了网站A的密钥,且可以确保除了浏览器和网站A,不会有任何外人知道该密钥,那理论上用对称加密是可以的,这样浏览器只要预存好世界上所有HTTPS网站的密钥就行啦!这么做显然不现实。

怎么办?所以我们就需要神奇的非对称加密。

四、什么是非对称加密?

有两把密钥,通常一把叫做公钥、一把叫做私钥。

用公钥加密的内容必须用私钥才能解开,同样,私钥加密的内容只有公钥能解开。

五、用非对称加密可行吗?

image

公钥呢,还是要通过快递员送给小红的。OK,假设小红要回信,写好了用公钥加密,小红的妈妈因为拿不到私钥,看不到信的内容。

OK,但是反过来呢?小明用私钥加密传给小红,那么小红的妈妈可就能解密了(因为公钥可能会被小红的妈妈拿到)。

回到互联网,服务器先把公钥直接明文传输给浏览器,之后浏览器向服务器传数据前都先用这个公钥加密好再传,这条数据的安全似乎可以保障了!因为只有服务器有相应的私钥能解开这条数据。

然而由服务器到浏览器的这条路怎么保障安全?

如果服务器用它的的私钥加密数据传给浏览器,那么浏览器用公钥可以解密它,而这个公钥是一开始通过明文传输给浏览器的,这个公钥被谁劫持到的话,他也能用该公钥解密服务器传来的信息了。

所以目前似乎只能保证由浏览器向服务器传输数据时的安全性(其实仍有漏洞,下文会说)。

六、改良的非对称加密方案,似乎可以?

小明和小红年纪不大,但是很聪明,针对这个情况,还是迅速升级加密方法。他们想到既然一组公钥私钥不够,那两组呢?

image

OK,小明和小红各造了一对。下面就是互相交换公钥。那么就变成:

image

下面就好办啦,小明写信用公钥B加密,那么信的内容只有小红能破解,因为小红是随身携带私钥B。相反,小红用公钥A对信加密,这样只有小明能破解,因为小明也是随身携带私钥A。好像很安全啦!除了下面提到的漏洞,唯一的缺点可能是:小红得花半天时间才能解密完这封信,有点受不了。

回到互联网。请看下面的过程:

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

的确可以!抛开这里面仍有的漏洞不谈(下文会讲),HTTPS的加密却没使用这种方案,为什么?最主要的原因是非对称加密算法非常耗时,特别是加密解密一些较大数据的时候有些力不从心。

七、非对称加密+对称加密?

小明也知道,这个信很长,用非对称加密,太慢!办法也有,没有必要对那么长的信加密,我只要保证这个真正解密的钥匙不被别人拿到就行,那么他灵机一动想到这个方法:

image

小明和小红利用非对称加密对钥匙加密,姑且认为是这个钥匙被放在了一个盒子里,这个盒子也被锁起来了,只有小红或者小明才能打开盒子,再用钥匙去解密。

这个真正用于对称加密解密的钥匙别人就拿不到啦!

自从用了这个方案,感觉又安全,解密又快,感情又深温了呢!

回到互联网,步骤如下:

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

HTTPS的基本思想就是基于这个。但是这个方案也存在上面一直在说的漏洞。

八、中间人攻击

像妈妈这样级别的程序猿可能是那他们两没办法啦,但是呢,校区有个看门的大爷,以前是个黑客,也不知道咋回事,明明才50岁,但是看起来像80岁,头上光溜溜的,冬天冷呢。整天在那胡言乱语:docker牛逼啊,spring cloud牛逼啊,这个开源软件XXX写的真好,跟周围的老大爷老大妈根本谈不到一起去。

他也是闲的蛋疼,非要掺和,因为据说他以前单身30年,苦逼敲代码,不知道谈恋爱是啥滋味,姑且认为他好奇心重吧。

在小明第一次寄公钥A的时候,大爷出手了,截取下来。换成自己做的公钥B。然后送给小红。

小红哪里会知道这公钥被掉包了呢,所以直接就用了,按照正常步骤,小红想了一个随机字符串,这次就叫xiaomingwoxuanni吧,OK,用这个公钥B对这个字符串加个密,这个字符串就被锁进了用大爷公钥B锁的盒子里。

老大爷在门口守着呢,一看到小红寄东西了,又偷偷地截取下来,用自己的私钥B来解密这个盒子。轻易地拿到了里面的字符串,OK,怕小明察觉,再用小明寄来的公钥A加密传给小明,这样双方都不知道他们的钥匙已经被大爷给获取了。

小明和小红之间的信就用xiaomingwoxuanni这个钥匙进行对称加密和对称解密,完全不知道有个大爷就天天拿着这个字符串去解密信件,看的不亦乐乎,甚至还偷偷改几个字呢。

回到互联网。中间人的确无法得到浏览器生成的密钥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。根本原因是浏览器无法确认自己收到的公钥是不是网站自己的。只要解决了这个公钥一定是这个网站发来的,那么基本就OK了

九、如何证明浏览器收到的公钥一定是该网站的公钥?

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

十、数字证书

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

SSL证书内容:

  1. 证书的发布机构CA
  2. 证书的有效期
  3. 公钥
  4. 证书所有者
  5. 签名

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

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

提到数字签名,其实原理很简单啦,就是比如我要传输一句话叫:“你给我转100块钱,我的账号是123456,转完了告诉我一声。”,如果不做任何处理,被刚才的老大爷截取了,他偷偷地改一下内容“你给我转200块钱,我的账号是654321,不要告诉任何人,尤其是你嫂子。”

是不是太坏了,弄不好被抓,大爷可不敢做大的,只敢骗个喝酒钱。

那么怎么防止大爷这种猥琐技术又高的人篡改呢?数字签名排上用场啦!

以后再传消息就是“你给我转100块钱,我的账号是123456,转完了告诉我一声。”+“!……@&@%#……!¥@¥!@%……#¥!%……”,后面那一串东西就是数字签名,简单来说,就是想办法对前面的内容进行非对称加密(这样别人根本不知道你加密的私钥是什么,也就伪装不了签名了)。传过去之后,我要对其进行解密,与传过来的明文一一对比参数,看有没有被改动过。一旦发现哪里不对应,说明已经被篡改了。

“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一次?

最显然的是性能问题,前面我们已经说了非对称加密效率较差,证书信息一般较长,比较耗时。而hash后得到的是固定长度的信息(比如用md5算法hash后可以得到固定的128位的值),这样加密解密就会快很多。

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

让我们回想一下数字证书到底是干啥的?没错,为了证明某公钥是可信的,即“该公钥是否对应该网站/机构等”,那这个CA机构的公钥是不是也可以用数字证书来证明?没错,操作系统、浏览器本身会预装一些它们信任的根证书,如果其中有该CA机构的根证书,那就可以拿到它对应的可信公钥了。

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

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

也就是说,公钥是从证书中获取的。证书是网站从机构那边申请来的,证书+签名传给浏览器。只要校验通过,那么公钥必然没有被篡改过,并且一定是这个网站传来的,那么解决了我们最核心的问题:确定公钥是我们指定的网站传来的。

既然公钥是正确的,那么小红就会用正确的公钥对随机字符串加密,中间不会出现篡改。

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

这也是我当时的困惑之一,显然每次请求都经历一次密钥传输过程非常耗时,那怎么达到只传输一次呢?用session就行。

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

十七、HTTPS原理

下面再来看看HTTPS原理就特别简单啦!

HTTPS 协议(HyperText Transfer Protocol over Secure Socket Layer):可以理解为HTTP+SSL/TLS, 即 HTTP 下加入 SSL 层,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL,用于安全的 HTTP 数据传输。

1
2
3
4
HTTP
SSL/TLS
TCP
IP

我们只要知道,在SSL层里面可以完成校验和密钥的传输。

image

理解了上面,这个图也就没啥好解释的了。

整理自:https://zhuanlan.zhihu.com/p/43789231