这是本系列的最后一篇了,其实本篇的内容也跟前两篇TLS的握手和优化有关系。其实HTTPS的核心就是TLS的明文握手连接,前两篇我们花了很大的篇幅来聊这些,另外一个就是在TLS握手完成后的密文传输部分了。

  由于目前流行的 AES、ChaCha20 性能都很好,还有硬件优化,报文传输的性能损耗可以说是非常地小,小到几乎可以忽略不计了。但是,HTTPS在建立连接的时候,还是要比HTTP慢。想必大家也能猜到为什么HTTPS的连接要比HTTP慢了,嗯……就是因为TLS握手所产生的消耗。但是除了TLS握手的消耗外,其实还有一些隐形的损耗,比如:

  • 产生用于密钥交换的临时公私钥对(ECDHE);
  • 验证证书时访问 CA 获取 CRL 或者 OCSP;
  • 非对称加密解密处理“Pre-Master”。

  在最差的情况下,也就是不做任何的优化措施,HTTPS 建立连接可能会比 HTTP 慢上几百毫秒甚至几秒,这其中既有网络耗时,也有计算耗时,就会让人产生“打开一个 HTTPS 网站好慢啊”的感觉。

  不过刚才说的情况早就是“过去时”了,现在已经有了很多行之有效的 HTTPS 优化手段,运用得好可以把连接的额外耗时降低到几十毫秒甚至是“零”。

一、硬件优化

  首先是硬件的优化,说白了就是花钱。由于HTTPS连接是计算密集型,所以你可以花钱买更快的CPU,最好还可以内建AES优化,这样既可以加快握手的速度,还可以加快传输的速度。

  其次,你可以选择“SSL 加速卡”,加解密时调用它的 API,让专门的硬件来做非对称加解密,分担 CPU 的计算压力。

  不过“SSL 加速卡”也有一些缺点,比如升级慢、支持算法有限,不能灵活定制解决方案等。

  所以,就出现了第三种硬件加速方式:“SSL 加速服务器”,用专门的服务器集群来彻底“卸载”TLS 握手时的加密解密计算,性能自然要比单纯的“加速卡”要强大的多。

二、软件优化

  软件优化主要分为两部分:一个是软件升级,一个是协议优化。我们先来说软件升级。

  软件升级实施起来比较简单,就是把现在正在使用的软件尽量升级到最新版本,比如把 Linux 内核由 2.x 升级到 4.x,把 Nginx 由 1.6 升级到 1.16,把 OpenSSL 由 1.0.1 升级到 1.1.0/1.1.1。

  由于这些软件在更新版本的时候都会做性能优化、修复错误,只要运维能够主动配合,这种软件优化是最容易做的,也是最容易达成优化效果的。

  但对于很多大中型公司来说,硬件升级或软件升级都是个棘手的问题,有成千上万台各种型号的机器遍布各个机房,逐一升级不仅需要大量人手,而且有较高的风险,可能会影响正常的线上服务。所以,在软硬件升级都不可行的情况下,我们最常用的优化方式就是在现有的环境下挖掘协议自身的潜力。

三、协议优化

  如果有可能,应当尽量采用 TLS1.3,它大幅度简化了握手的过程,完全握手只要 1-RTT,而且更加安全。

  如果暂时不能升级到 1.3,只能用 1.2,那么握手时使用的密钥交换协议应当尽量选用椭圆曲线的 ECDHE 算法。它不仅运算速度快,安全性高,还支持“False Start”,能够把握手的消息往返由 2-RTT 减少到 1-RTT,达到与 TLS1.3 类似的效果。

  另外,椭圆曲线也要选择高性能的曲线,最好是 x25519,次优选择是 P-256。对称加密算法方面,也可以选用“AES_128_GCM”,它能比“AES_256_GCM”略快一点点。

四、证书优化

  除了密钥交换,另外一个耗时的东东就是证书验证了。服务器需要把自己的证书链全发给客户端,然后客户端接收后再逐一验证。

  这里就有两个优化点,一个是证书传输,一个是证书验证

  服务器的证书可以选择椭圆曲线(ECDSA)证书而不是 RSA 证书,因为 224 位的 ECC 相当于 2048 位的 RSA,所以椭圆曲线证书的“个头”要比 RSA 小很多,即能够节约带宽也能减少客户端的运算量,可谓“一举两得”。

  客户端的证书验证其实是个很复杂的操作,除了要公钥解密验证多个证书签名外,因为证书还有可能会被撤销失效,客户端有时还会再去访问 CA,下载 CRL 或者 OCSP 数据,这又会产生 DNS 查询、建立连接、收发数据等一系列网络通信,增加好几个 RTT。

  CRL(Certificate revocation list,证书吊销列表)由 CA 定期发布,里面是所有被撤销信任的证书序号,查询这个列表就可以知道证书是否有效。但 CRL 因为是“定期”发布,就有“时间窗口”的安全隐患,而且随着吊销证书的增多,列表会越来越大,一个 CRL 经常会上 MB。想象一下,每次需要预先下载几 M 的“无用数据”才能连接网站,实用性实在是太低了。所以,现在 CRL 基本上不用了,取而代之的是 OCSP(在线证书状态协议,Online Certificate Status Protocol),向 CA 发送查询请求,让 CA 返回证书的有效状态。但 OCSP 也要多出一次网络请求的消耗,而且还依赖于 CA 服务器,如果 CA 服务器很忙,那响应延迟也是等不起的。于是又出来了一个“补丁”,叫“OCSP Stapling”(OCSP 装订),它可以让服务器预先访问 CA 获取 OCSP 响应,然后在握手时随着证书一起发给客户端,免去了客户端连接 CA 服务器查询的时间。

五、会话复用

  到这里,我们已经讨论了四种 HTTPS 优化手段(硬件优化、软件优化、协议优化、证书优化),那么,还有没有其他更好的方式呢?

  我们再回想一下 HTTPS 建立连接的过程:先是 TCP 三次握手,然后是 TLS 一次握手。这后一次握手的重点是算出主密钥“Master Secret”,而主密钥每次连接都要重新计算,未免有点太浪费了,如果能够把“辛辛苦苦”算出来的主密钥缓存一下“重用”,不就可以免去了握手和计算的成本了吗?

  这种做法就叫“会话复用”(TLS session resumption),和 HTTP Cache 一样,也是提高 HTTPS 性能的“大杀器”,被浏览器和服务器广泛应用

  会话复用分两种,第一种叫“Session ID”,就是客户端和服务器首次连接后各自保存一个会话的 ID 号,内存里存储主密钥和其他相关的信息。当客户端再次连接时发一个 ID 过来,服务器就在内存里找,找到就直接用主密钥恢复会话状态,跳过证书验证和密钥交换,只用一个消息往返就可以建立安全通信。

六、会话票证

  “Session ID”是最早出现的会话复用技术,也是应用最广的,但它也有缺点,服务器必须保存每一个客户端的会话数据,对于拥有百万、千万级别用户的网站来说存储量就成了大问题,加重了服务器的负担。于是,又出现了第二种“Session Ticket”方案。

  它有点类似 HTTP 的 Cookie,存储的责任由服务器转移到了客户端,服务器加密会话信息,用“New Session Ticket”消息发给客户端,让客户端保存。

  重连的时候,客户端使用扩展“session_ticket”发送“Ticket”而不是“Session ID”,服务器解密后验证有效期,就可以恢复会话,开始加密通信。

  不过“Session Ticket”方案需要使用一个固定的密钥文件(ticket_key)来加密 Ticket,为了防止密钥被破解,保证“前向安全”,密钥文件需要定期轮换,比如设置为一小时或者一天。

七、预共享密钥

  “False Start”“Session ID”“Session Ticket”等方式只能实现 1-RTT,而 TLS1.3 更进一步实现了“0-RTT”,原理和“Session Ticket”差不多,但在发送 Ticket 的同时会带上应用数据(Early Data),免去了 1.2 里的服务器确认步骤,这种方式叫“Pre-shared Key”,简称为“PSK”。

  但“PSK”也不是完美的,它为了追求效率而牺牲了一点安全性,容易受到“重放攻击”(Replay attack)的威胁。黑客可以截获“PSK”的数据,像复读机那样反复向服务器发送。

  解决的办法是只允许安全的 GET/HEAD 方法,在消息里加入时间戳、“nonce”验证,或者“一次性票证”限制重放。

真正“搞”懂HTTPS协议19之HTTPS优化的更多相关文章

  1. 真正“搞”懂HTTP协议02之空间穿梭

    时隔四年,这个系列鸽了四年,我终于觉得我可以按照自己的思路和想法把这个系列完整的表达出来了. 想起四年前,那时候还是2018年的六月份,那时候我还工作不到两年,那时候我翻译了RFC2616的部分内容, ...

  2. 真正“搞”懂HTTP协议05之What's HTTP?

    前面几篇文章,我从纵向的空间到横向的时间,再到一个具体的小栗子,可以说是全方位,无死角的覆盖了HTTP的大部分基本框架,但是我聊的都太宽泛了,很多内容都是一笔带过,再加上一句后面再说就草草结束了.并且 ...

  3. 搞懂分布式技术19:使用RocketMQ事务消息解决分布式事务

    搞懂分布式技术19:使用RocketMQ事务消息解决分布式事务 初步认识RocketMQ的核心模块 rocketmq模块 rocketmq-broker:接受生产者发来的消息并存储(通过调用rocke ...

  4. 真正“搞”懂http协议01—背景故事

    去年读了<图解HTTP>.<图解TCP/IP>以及<图解网络硬件>但是读了之后并没有什么深刻的印象,只是有了一层模糊的脉络,刚好最近又接触了一些有关http的相关内 ...

  5. 真正“搞”懂HTTP协议03之时间穿梭

    上一篇我们简单的介绍了一下DoD模型和OSI模型,还着重的讲解了TCP的三次握手和四次挥手,让我们在空间层面,稍稍宏观的了解了HTTP所依赖的底层模型,那么这一篇,我们来追溯一下HTTP的历史,看一看 ...

  6. Charles PC端和手机端抓取HTTP和HTTPS协议请求、HTTPS通用抓包规则

    一:HTTP和HTTPS的区别 HTTP是超文本传输协议,被用在Web浏览器和网站服务器之间传递信息,HTTP协议以明文方式发送内容,不提供任何方式的数据加密,因此HTTP协议不适合传输一些敏感信息, ...

  7. 真正“搞”懂HTTP协议13之HTTP2

    在前面的章节,我们把HTTP/1.1的大部分核心内容都过了一遍,并且给出了基于Node环境的一部分示例代码,想必大家对HTTP/1.1已经不再陌生,那么HTTP/1.1的学习基本上就结束了.这两篇文章 ...

  8. 真正“搞”懂HTTP协议08之重定向

    我们知道,用来传输页面的协议就是HTTP协议,全称是超文本传输协议,而浏览器展示的页面则是用HTML编写的,HTML的全称则是超文本标记语言.你看,都叫做超文本,我在第一篇文章的时候也详细的聊过,超文 ...

  9. 真正“搞”懂HTTP协议09之这个饼干不能吃

    我们在之前的文章中介绍HTTP特性的时候聊过,HTTP是无状态的,每次聊起HTTP特性的时候,我都会回忆一下从前辉煌的日子,也就是互联网变革的初期,那时候其实HTTP不需要有状态,就是个浏览页面,没有 ...

  10. 真正“搞”懂HTTP协议07之body的玩法(实践篇)

    我真没想到这篇文章竟然写了将近一个月,一方面我在写这篇文章的时候阳了,所以将近有两周没干活,另外一方面,我发现在写基于Node的HTTP的demo的时候,我不会Node,所以我又要一边学学Node,一 ...

随机推荐

  1. QT QML实用效果之实现页面切换效果

    简介 本文介绍了如何使用QT QML和JavaScript实现页面动态加载和切换的效果. 文章目录 效果 JavaScript代码:butianyun.js文件 QML代码:主页面 页面A QML代码 ...

  2. SQL limit字句

    limit用法介绍 limit子句可以返回检索查询行的某一连续的部分 用法介绍: SELECT column_list FROM table1 ORDER BY column_list LIMIT r ...

  3. Android 常用的性能分析工具详解:GPU呈现模式

    此篇将重点介绍几种常用的Android性能分析工具: 一.Logcat 日志 选取Tag=ActivityManager,可以粗略地知道界面Displaying的时间消耗.当我们打开一个Activit ...

  4. DNS域名服务及常用国内DNS服务器地址

    DNS域名服务 DNS服务器分类 缓存域名服务器 也称为高速缓存服务器 通过向其他域名服务器查询获得域名 -> IP 地址记录 将域名查询结果缓存到本地,提高重复查询时的速度 主域名服务器 特定 ...

  5. 基于BIO的Socket通信

    基于BIO的Socket通信 告知对方命令发送完毕 关闭socket:socket.close() 关闭流:socket.shutdownOutput(),ocket.shutdownInput() ...

  6. 去哪儿旅行携手 HarmonyOS SDK | 告别繁琐,常用信息秒级填充

    背景 去哪儿旅行作为行业内领先的一站式在线旅游平台,多年来在日益加剧的市场竞争中积极寻求创新,凭借其优质的服务深受消费者青睐.2024年,去哪儿旅行适配HarmonyOS NEXT版本, 升级用户服务 ...

  7. Java高并发,创建线程的新方式Callable接口

    我们已经知道创建线程的方式有1.继承thread类.2.实现Runnable接口 接下来讲创建线程的新方式Callable接口,首先对比一下Runnable接口和Callable接口的区别: 首先创建 ...

  8. VueJS实现迷糊查询

    原文请查看公共号 前置条件: 开发环境:windows 开发框架:vue2.5 ,vue-cli 4.0+ 编辑器:HbuilderX 兼容版本:vue2.5     Chrome 99.0.4844 ...

  9. Large Language Model主题的若干论文简述

    1. Architectural Components of Large Language Models (LLMs) SentencePiece: A simple and language ind ...

  10. C++递归创建文件夹

    根据传入的参数递归进行目录的创建. 函数描述: 递归创建目录. 入参: 所要创建的目录. 返回值: 创建成功,返回TRUE:否则返回FALSE. 1 BOOL CreateDirTree(LPCTST ...