HTTPS 知识小结
背景 1:TCP 握手
internet 上的两台机器A,B要建立起 HTTP 连接了,在这之前要先建立 TCP 连接,情景大概是这样子的:
- A:你好,我跟你建立一个TCP好吗?
- B:好啊。
- A:那我们建立一个 TCP 连接吧。
网络上有个关于 TCP 的笑话,大概就是上面的意思。当然事实上的情景要比这个复杂:
- A:你好,我跟你建立一个 TCP 好吗?我从 0x0A00 这个序号开始给你发送数据(SYN)。
- B:好啊。我从 0x0B00 开始给发送数据(SYN),我收到你 0x0A00 开始的那个握手数据啦,(ACK=0x0A01)
- A:那我们建立一个 TCP 连接吧。我收到你 0x0B00 开始的那个握手数据啦(ACK=0x0B01)
TCP 握手本质上是在约定一次二进制通讯的参数,使得网络上的两台机型能够基于这个约定交换二进制数据。因为大家也知道,二进制数据就是一堆0和1,如果没有事先约定好字节长度的分割和每个位代表的意义,是无法解读的。
背景 2:TLS 握手
还是上面的情景,A 和 B 建立好 TCP 连接后,又要建立一个 TLS 连接了
- A:你好,我跟你建立一个TLS连接吧,我支持的加密方法有 A1,A2,A3…..我的加密参数有 A10,A11,A12…
- B:好的,我们选定A1作为加密方法吧,我选择的参数是 A10,这个是我的证书,里面有公钥,你拿着我的公钥用上面的加密方法加密个密码来看看。
- A:(转过头去问CA,证书是否合法),好的,我想好一个密码啦,这是我的密码用你的公钥加密之后的结果,blablabla…
- B:(用自己的私钥去解密)我知道你的密码是多少啦,下面是你的密码对称加密之后的密文,lablablab…
实质上的 TLS 协商要比这个复杂,交换很多细节参数,TLS 连接层的安全是,保证了以下三个方面的安全
- 不被监听。即使第三方收到密文,也无法解密
- 不被篡改。如果报文有被篡改,双方能通过一定方法检验到
- 不被冒充。通讯的对象不是假冒的
要达到以上三点,很细节上的点要去参考 RFC 的
HTTP 协议
HTTPS是基于TCP+TLS的协议,要想进行HTTPS通讯,则先要进行一次TCP握手,再进行一次TLS握手,然后才能开始HTTPS通讯。握手之后,A跟B就是在交换数据了
- A:我想获取(GET)你根目录上的默认文档,我这里面缓存的最后修改时间是20161201
- B:这个文档已经修改过啦,我给你最新的文档内容吧(200),内容是XXXXXXX,最后修改时间是 20161210
- A:我想获取(GET)你名叫
/images/logo.jpg
的文档,我这里面缓存的最后修改时间是 20161201 - B:这个文档没有修改过,你直接用缓存就好(304)
- A:我给你发一份文档吧(POST),你存储在
/upload/file.jpg
里面,内容是xxxxxx - B:好的,资源创建好了(201)
可以看到HTTP1.1版本的请求基本上是在模拟人类的对话,一请示一响应,双方以此交换数据。
HTTP/2的多路复用可以减少这些来往
- A:我想获取(GET)你根目录上的默认文档
- B:好的。我给你一个帧(frame),流(stream)2是文档的内容xxxxxx,流4等下你也会用着,是
/images/logo.jpg
的内容yyyyyy
TLS 1.3
TLS1.3目前还是一个制定中的标准。其中加密部分是基于ECDH,而不是RSA的,所以我们并不需要等到服务端的证书发送过来就可以开始一些加密的计算。ECDH的原理可以参考这里。在此证书的作用就变成校验,而不是加密了。 TLS1.3握手的场景大概是这样子的
- A:你好,我跟你建立一个TLS1.3连接吧,我支持的加密方法有A1,A2,A3…..我的加密参数有A10,A11,A12…。如果你选用A1,那么ECDH公开参数是A21;如果你选用A2,那么ECDH公开参数是A22。
- B:我选用了A1,我的公开参数是B21。下面是我的证书 xxxxxxxx
A下面就可以进行GET /
之类的HTTP请求
甚至还可以进行0-RTT的握手,当然这是基于以前已经握过手。
- A:你好,我跟你建立一个TLS1.3连接吧。我以前跟你握过手的,我的证明材料如下 xxxxx。我想要你根目录下的默认文档
- B:啊,是你,我认得。这个证明是有效的。我们就用之间协商的加密方法进行加密啦。我的默认文档的内容如下:xxxxxx
可以看出这个握手是直接把TCP,TLS,HTTP三合一,这也是QUIC 0-RTT的基本原理。
排错:unable to verify the first certificate
前面 #8 #5 的时候我在处理一个网络的错误问题,当时只知道一些解决方法,也怀疑过是不是HTTPS的问题,但无法考证。后来系统地学习过HTTPS的知识之后,发现从这些知识解释这个现象是很简单的。
参考上面的TLS握手,服务端把自己的证书交给客户端之后,原则上客户端是要从CA那里去校验这个证书的合法性的,一但无法验证(verify),就会报上面的错误,而strict-ssl=false
是让npm不去验证,NODE_TLS_REJECT_UNAUTHORIZED=0
是让node-gyp不去验证。所以双方就基于一个假的证书在进行HTTPS通讯了。反过来也说明我在用的代理有进行MITM攻击。
其他 HTTPS 的优化
- hsts:简单说来,就是在HTTP连接阶段,让浏览器内部走307跳到HTTPS,而不是走302(多一个RTT),而且HSTS能缓存,能预读,使得下次浏览器访问指定网站时默认先走HTTPS。
- Ocsp stapling:前面TLS握手时,提及到客户端需要向CA确认证书的有效性,那也是一次完整的HTTP请求。而Ocsp stapling就是把这些确认过程需要的一些中间数据一次性发送给客户端,让客户端(理想状态下)只需要用内置的根证书去校验即可。
- 还有其他很多优化的内容,就不一一罗列了,可以参考 https://github.com/imweb/IMWeb-Conf-ppt/blob/master/%E3%80%8AHTTPS%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5%E3%80%8B-lancelotluo.pdf
- 要想优化,首先要知道一些基础的知识,知道数据是怎么传送的,然后根据这些知识,分阶段进行优化。其次要进行实践,不断总结。
基于 HTTPS 的前端优化
如果一个网站部署了 HTTPS,除了更加安全,前端也能基于它得到以下优化
- service worker:相当于一个缓存代理,它的生命周期在页面以外,可以页面还没加载完成时就做点事情。
- HTTP2:HTTP2 的 rfc 中有基于明文 h2c 和密文 h2 两种,但目前的浏览器厂商都只支持h2,所以想要用http2的多路复用、头部压缩等进行优化,就必须要部署HTTPS。
参考
https://tools.ietf.org/html/rfc5246
https://tools.ietf.org/html/rfc7540
https://imququ.com/post/optimize-tls-handshake.html
https://www.khanacademy.org/computing/computer-science/cryptography/modern-crypt/v/diffie-hellman-key-exchange-part-2
https://github.com/imweb/IMWeb-Conf-ppt/blob/master/%E3%80%8AHTTPS%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5%E3%80%8B-lancelotluo.pdf
以上是 HTTPS 知识小结 的全部内容, 来源链接: utcz.com/z/264692.html