https诞生背景及原理解析

参考视频
【web安全3】【硬核】HTTPS原理全解析

本文从最简单的加密方式(对称加密)循序渐进介绍https的产生。

一、对称加密

条件:
  • key:密钥
  • Y = f(str, key):key可用于加密
  • str = f(Y, key):key可用于解密
理想情况:
  • 流程:
    ① 客户端使用密钥key加密字符串str1,生成密文Y1。
    ② 客户端将密文传输给服务端。
    ③ 服务端收到密文Y1,根据密钥key进行解密,获取到str1。
    ④ 服务端使用str1处理完相应的逻辑后,对即将回复的数据str2,使用密钥key加密成密文Y2。
    ⑤ 服务端响应Y2给客户端。
    ⑥ 客户端收到密文Y2,根据密钥key进行解密,获取到str2。
image.png
现实中:
  • 前提条件:中间人事先充当客户端,从服务端获取到了key。
  • 流程:
    ① 客户端使用密钥key加密字符串str1,生成密文Y1。
    ② 客户端将密文传输给服务端。
    ③ 中间人劫持密文Y1,使用密钥key进行解密,获取到str1,此时客户端的请求已经泄漏。
    ④ 中间人将str1换成Z_str1,使用key,伪造出新的密文Z_Y1。
    ⑤ 将伪造后的密文Z_Y1传给服务端。
    ⑥ 服务端收到Z_Y1后,并不知道是中间人发送过来的,用key解密出Z_str1后,以为这就是客服端client发送过来的请求。
    ⑦ 服务端使用Z_str1处理完相应的逻辑后,对即将回复的数据str2,使用密钥key加密成密文Y2。
    ⑧ 服务端响应给客户端的密文Y2,再次给中间人拦截。
    ⑨ 中间人拦截到Y2,使用key解密,即可得到str2,此时str2也泄漏了。
    ⑩ 中间人将str2换成Z_str2,使用key,伪造出新的密文Z_Y2。
    ⑫ 中间人响应Z_Y2给客户端。
    ⑬ 客户端收到密文Z_Y2,根据密钥key进行解密,获取到Z_str2。本来应该得到str2,但是经过中间人的一番操作后,李代桃僵,变成了Z_str2。
image.png
总结:
  • 对称加密的只有一个密钥key,安全系数太低。
  • “中间人”可以事先以客户端的身份获取到key,只要一得到这个key,客户端和服务端传输的任何密文Y,将轻而易举被解密出来。
  • “中间人”还可以完全充当服务端的身份与客户端交互,客户端无法鉴别收到的回复是“中间人”发的还是服务端。

所以,我们看下非对称加密是否可以解决问题。

二、非对称加密

条件:
  • pKey:公钥
  • sKey:私钥
  • Y = f(str, pKey):pKey可用于加密
  • str = f(Y, pKey):pKey可用于解密
  • Y = f(str, sKey):sKey可用于加密
  • str = f(Y, sKey):sKey可用于解密
理想情况:
  • 流程:
    ① 客户端使用公钥pKey加密字符串str1,生成密文Y1。
    ② 客户端将密文传输给服务端。
    ③ 服务端收到密文Y1,根据私钥sKey进行解密,获取到str1。
    ④ 服务端使用str1处理完相应的逻辑后,对即将回复的数据str2,使用私钥sKey加密成密文Y2。
    ⑤ 服务端响应Y2给客户端。
    ⑥ 客户端收到密文Y2,根据公钥pKey进行解密,获取到str2。
image.png
现实中:
  • 前提条件:中间人事先充当客户端,从服务端获取到了pKey。
  • 流程:
    ① 客户端使用公钥key加密字符串str1,生成密文Y1。
    ② 客户端将密文Y1传输给服务端。
    ③ 中间人劫持密文Y1,由于没有私钥sKey,无法解密出原文,此时并不能之搭配客户端传递了什么信息给服务端。
    ④ 假设中间人还要挣扎,用pKey伪造出了Z_Y1。
    ⑤ 将伪造后的密文Z_Y1传给服务端。
    ⑥ 服务端收到Z_Y1后,并不知道是中间人发送过来的,用私钥sKey解密出Z_str1后,以为这就是客服端client发送过来的请求。
    ⑦ 服务端使用Z_str1处理完相应的逻辑后,对即将回复的数据str2,使用私钥sKey加密成密文Y2。
    ⑧ 服务端响应给客户端的密文Y2,再次给中间人拦截。
    ⑨ 中间人拦截到Y2,使用公钥pKey解密,即可得到str2,此时str2泄漏了。
    ⑩ 中间人将str2换成Z_str2,由于没有公钥pKey,无法伪造出新的密文Z_Y2。
image.png
总结:
  • 非对称加密有两个密钥——公钥pKey和私钥sKey,公钥由客户端保存,私钥由服务端保存。
  • 非对称加密可以保证客户端给服务端发送数据时是安全的,因为“中间人”没有私钥sKey可以解密客服端发出来的密文,
  • 但是服务端给客户端发送数据时就麻烦了,因为服务端是用私钥sKey加密的数据,客户端用公钥pKey解密,而“中间人"也有公钥pKey,导致服务端给客户端发送的密文已经没有意义,有pKey都能解析出原文。
  • 非对称加密计算复杂,相对于对称加密要耗时得多。

所以,我们看下是否能把对称加密和非对称加密结合起来使用。

三、对称加密+非对称加密

条件:
  • pKey:公钥
  • sKey:私钥
  • random:客户端随机生成的密钥
  • Y = f(str, pKey):pKey可用于加密
  • str = f(Y, pKey):pKey可用于解密
  • Y = f(str, sKey):sKey可用于加密
  • str = f(Y, sKey):sKey可用于解密
理想情况:
  • 流程:
    ① 客户端向服务端请求获取公钥pKey。
    ② 服务端访问公钥pKey。
    ③ 客户端生成一个随机密钥random。
    ④ 客户端使用公钥pKey对随机密钥random加密,生成密文Yrandom。
    ⑤ 客户端将密文Yrandom传输给服务端。
    ⑥ 服务端收到密文Yrandom,使用私钥sKey进行解密,获取到random。
    ⑦ 服务端回复客户端,已经收到了客户端安排的新密钥,至此,密钥协商成功。
    ⑧ 客户端使用密钥random加密字符串str1,生成密文Y1。
    ⑨ 客户端将密文Y1传输给服务端。
    ⑩ 服务端收到密文Y1,使用协商好的密钥random进行解密,获取到str1。
    ⑪ 服务端使用str1处理完相应的逻辑后,对即将回复的数据str2,使用密钥random加密成密文Y2。
    ⑫ 服务端响应Y2给客户端。
    ⑬ 客户端收到密文Y2,使用密钥random进行解密,获取到str2。
image.png
现实中:

中间人在客户端的第①步请求时,就进行了劫持。

  • 流程:
    ① 客户端向服务端请求获取公钥pKey。
    ② 中间人截胡client的请求。
    ③ 中间人向服务端请求获取公钥pKey。
    ④ 服务端以为是客户端发起的请求,就返回了pKey。
    ⑤ 中间人偷偷把真实的pKey保存起来。
    ⑥ 中间人伪造出一对用来跟client端通信的公私钥Z_pKey、Z_sKey。
    ⑦ 中间人冒充着server端,将伪造的Z_pKey返回给客户端。
    ⑧ 客户端接收到公钥Z_pKey后,以为是服务端响应回来的公钥,殊不知真正的共钥pKey已经被中间人截取。客户端开始生成随机密钥random。
    ⑨ 客户端继续天真地用冒牌公钥Z_pKey对random加密,还以为加密后的密文Yrandom只有服务端server的密钥sKey能解密出来。
    ⑩ 客户端开开心心地把Yrandom发送出去。
    ⑪ 中间人再次劫持请求,使用Z_sKey轻轻松松解密出Yrandom的原文,此时客户端的random泄漏了。
    ⑫ 中间人模仿客户端,伪造出随机密钥Z_random。用来后续跟服务端通信。
    ⑬ 中间人使用第⑤步获取到的真实pKey,对随机密钥Z_random进行加密得到密文YZ_random。
    ⑭ 中间人将YZ_random传送服务端.
    ⑮ 服务端使用私钥sKey对YZ_random解密,得到了假的随机密钥Z_random。服务端以为这是客户端发送过来的,因为只有与sKey匹配的公钥pKey加密出来的密文,sKey才能解开,这确实是这样。但是服务端一开始就错了,糊涂地以为pKey安全传送到了客户端手上,确没想过已经被中间人调包。
    ⑯ 服务端响应已经收到密钥信息。
    ⑰ 中间人以服务端的身份通知客户端已经收到密钥信息。至此,密钥random调包成功,接下来将正式开始监听客户端和服务端的通信。
    ⑱ 客户端使用密钥random对字符串str1加密,生成密文Y1。
    ⑲ 客户端传输密文Y1,预期传输给服务端。
    ⑳ 中间人劫持Y1,使用第⑪步保存起来的random解密出原文str1。此时,客户端的请求内容已泄漏。
    ㉑ 中间人使用私下跟服务端协商好的Z_random,对客户端的请求str1加密成Z_Y1。
    ㉒ 中间人以客户端的身份传输密文Z_Y1。
    ㉓ 服务端用第⑮步收到的Z_random,进行解密。得到str1。
    ㉔ 服务端内容根据str1请求进行响应逻辑处理,得到结果str2。接着使用Z_random对响应信息str2进行加密。
    ㉕ 服务端回复密文Y2.
    ㉖ 中间人劫持Y2。使用Z_random轻松解密出原文str2。此时,客户端预期得到的响应str2内容已经被中间人得知。
    ㉗ 中间人继续暗箱操作,把str2换成Z_str2。使用第⑪步保存起来的random对Z_str2加密成Z_Y2。
    ㉘ 中间人以服务端身份回复客户端密文Z_Y2。
    ㉙ 客户端收到密文Z_Y2后,使用random进行解密,以为这就是服务端对于str1请求作出的回复。
image.png
总结:
  • 一开始pKey的泄漏,导致后面所有过程的加密变得毫无意义。
  • 中间人同时扮演者客户端和服务端,监听着整个过程。设想哪天中间人把客户端的请求“转账200元”,偷偷改成“转账2000元”,发送给服务端,多可怕。
  • 这一切的根源是在第⑦步的时候客户端收到Z_pKey,并无法分辨其真假。

所以在https引入了权威机构CA,来帮我们验证。

四、对称加密+非对称加密+CA

条件:
  • pKey:公钥
  • Y = f(str, pKey):key可用于加密
  • str = f(Y, pKey):key可用于解密
  • c_pKey:CA机构共钥,操作计统自带。
  • c_sKey:CA机构私钥,用来签署证书。
  • lisence:证书,使用CA私钥c_sKey加密出来的密文。
理想情况:
  • 流程:
    ① 服务端带着pKey像CA机构请求获取lisence。
    ② CA机构使用c_sKey对pKey进行加密。
    ③ 返回证书lisence给服务端,服务端保存该证书。
    ④ 客户端访问服务端。
    ⑤ 服务端根据颁发者信息在操作系统中查找c_pKey(操作系统会自带一套受信任的CA机构颁发的证书列表)。
    ⑥ 客户端使用c_pKey对lisence进行解密,得到pKey。
    ⑦ ....
    (得到安全的pKey后,后续与对称加密+对称加密的流程一致:客户端生成随机密钥random,使用pKey对random进行加密,服务端使用sKey解密出random,接着再用这个协商出来的新密钥random进行密文传输)
image.png
假设这时中间人还来攻击:
  • 流程:
    ① ② ③ 照常进行,服务端获得lisence。
    ④ 客户端开始访问服务端。
    ⑤ 中间人劫持客户端请求,自己以客户端的身份去服务端请求lisence。
    ⑥ 服务端访问lisence。
    ⑦ 中间人冒仿CA机构伪造密钥对z_csKey和z_cpKey,另外再冒仿server端伪造密钥对z_sKey和z_pKey,接着生成假的证书Z_lisence。
    ⑧ 中间人返回假的Z_lisence给客户端。
    ⑨ 客户端收到Z_lisence后,根据颁发者信息,查找z_cpKey对其进行解密。
    ⑩ 但操作系统中并没有z_cpKey,此时浏览器会警告“连接不安全”。
image.png
总结:
  • 对比“对称加密+非对称加密”的方式,https有个很关键的点——CA机构c_pKey是存在于客户端本地的,客户端不再需要去请求CA机构获取公钥。这样可以避免CA返回c_pKey时,再次被中间人截获后伪造出假的公钥给客户端,因为一旦客户端收到的是假公钥,后续客户端再获取lisence时,中间人又可以截获伪造假lisences,客户端拿到假lisence,用上一步获取到的假公钥刚好可以解开,客户端还完全没意识到这是中间人发过来的,这样一来,就变得跟“对称加密+非对称加密”一样了,所以c_pKey保存在客户端本地很重要。
  • c_pKey保存在客户端本地,会出现使用我们自己签发的证书,客户端会提示“连接不安全”,如果我们想要客户端能认可我们的证书,可以把自签发的证书公钥导入证书列表中。详见上一篇文章:openssl为IP签发证书(支持多IP/内外网)

你可能感兴趣的:(https诞生背景及原理解析)