[译] HPACK:http2中沉默的杀手锏

栏目: 后端 · 前端 · 发布时间: 6年前

内容简介:如果你有过HTTP/2的相关经验,你可能会知道HTTP/2强大的性能依靠了一些如下的特点,比如流复用、显示流依赖以及服务端推送。但是还有一个并不明显注意到但是却很重要的功能点,那就是HPACK头部压缩。这篇文章给出了设计HPACK的一些理由,以及它背后带来的带宽和延时上的收益。

如果你有过HTTP/2的相关经验,你可能会知道HTTP/2强大的性能依靠了一些如下的特点,比如流复用、显示流依赖以及服务端推送。

但是还有一个并不明显注意到但是却很重要的功能点,那就是HPACK头部压缩。

这篇文章给出了设计HPACK的一些理由,以及它背后带来的带宽和延时上的收益。

一些背景

你可能知道,常规HTTPS连接事实上是多层模型的多个连接的叠加。你通常关系的最基本的连接就是TCP连接(传输层),在它的上面你会有一个TLS连接(传输层/应用层混合),然后最后是一个HTTP连接(应用层)

多年以前,HTTP压缩是在TLS层使用gzip去处理的。header和body都会被压缩,因为TLS层不感知传输的数据类型,实际上两者都是使用DEFLATE算法进行压缩的。

然后提出了新的专门进行头部压缩的算法SPDY。尽管是为了headers特殊设计,包括使用了一个预处理字典,包括动态Huffman编码和字符串匹配,但是它依旧使用的是DEFLATE算法。

实际上DEFLATE和SPDY都有被攻击的危险,因为攻击者可以从压缩的头部里提取cookie中的授权秘钥:因为DEFLATE使用后向字符串匹配和动态Huffman编码,攻击者可以控制部分请求头部,然后通过修改请求部分然后看压缩之后大小改变多少,来逐步恢复完整cookie。

由于这种风险,大多数的边缘网络都禁用了头部压缩。直到HTTP/2的出现改变了这种窘况

HPACK

HTTP/2支持一种新的专门进行头部压缩的算法,叫做HPACK。HPACK的开发设计考虑到了被攻击的危险,因此可以安全使用。

HPACK能够防御攻击者攻击,因为它没有像DEFLATE一样使用后向字符串匹配和动态Huffman,它使用了下面这三种方法进行压缩:

  • 静态字典表:由61个常规header域和一些预定义的values组成的预定义字典表。
  • 动态字典表:在连接中遇到的实际header域的列表。这个字典表有大小限制,新的key进来,旧的key可能会被移除。
  • Huffman编码:静态的Huffman编码可以对任何字符串进行编码:名称或者是值。这种编码特定地用在HTTP的request/response头中,ASCII码和小写字母的编码会更短。编码最短可能只有5bits长(一个字节8bits),因此最大的原长和压缩长比率为8:5(或者是37.5%的压缩率)

HPACK流

当HPACK需要把一个header编码为name:value的形式,它首先会看静态和动态字典表。如果全部的name:value都有的话,它会简单地去找字典表的对应条目。 这通常需要1byte,在大多数情况下2bytes也就足够了。整个header编码成一个byte,太赞了。

因为许多header头都是重复的,所以上面的策略有很高的成功率。 举个例子,像这种headers: authority:www.cloudflare.com 或者是一些大的cookie通常是这种情况。

当HPACK在字典表里不能匹配整个header的时候,它就会去尝试找有相同name的header。大多数常见的haeder name会在静态表里有,比如 content-encoding, cookie, etag 。剩下的一些可能会有重复的会在动态表里。比如Cloudflare会为每一个response分配 cf-ray header,而它的值是不同的,但是name是可以复用的。

如果找到了name,它就可以再次用1~2个bytes来表示,否则的话会使用其他的原生编码或者是Huffman编码(两者中取短的那个)。header中的value也是同样的原理。

我们发现单独使用Huffman编码会节省30%的header大小。

尽管HPACK不做字符串匹配,对于攻击者来说为了找到header的value,他必须猜测整个字典表条目的value,而不是像DEFLATE一样逐步匹配,但是HPACK还是有可能受到攻击。

Request Headers

HPACK为HTTP提供的收益里面,request会比response收益更大。request的headers能够更有效的进行压缩,因为在header里面有更多的重复项。比如下面是两个requests的header,用的是Chrome浏览器:

Request #1:

authority: blog. cloudflare. com

method:GET

path: /

scheme:https

accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,/;q=0.8

accept-encoding: gzip, deflate, sdch, br

accept-language: en-US,en;q=0.8

cookie: 297 byte cookie

upgrade-insecure-requests:1

user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2853.0 Safari/537.36

我把那些使用静态字典表的可以被压缩的headers标注了红色。有3个field: method:GET, path:/scheme:https ,它们始终在静态字典表里,并且会被编码成1个byte.一些其他的field只有name会被编码为1byte: authority, accept, accept-encoding, accept-language, cookie , user-agent

所有其他的部分标记为绿色,会按照Huffman编码进行处理。

没有匹配上的headers,会插到动态字典表里为后面的request去使用

让我们看一下另外一种情况:

authority:blog.cloudflare.com

method:GET

path: /assets/images/cloudflare-sprite-small.png

scheme:https

accept: image/webp,image/,/*;q=0.8

accept-encoding: gzip, deflate, sdch, br

accept-language: en-US,en;q=0.8

cookie: 297 byte cookie

referer: blog.cloudflare.com/assets/css/…

user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2853.0 Safari/537.36

这里我加上了蓝色的编码域,它们表明了那些header域匹配上了动态字典表。很明显那些域在不同的requests里面都有重复。这里面有两个域又一次出现在静态字典表里,也就是说每个域可以编码为1或者2个bytes串。一个是大概有300byte场的 cookie 头,另一个是大概130byte长的 user-agent 。把430bytes的长度压缩到仅仅4个bytes,压缩了99%。

总之多于所有的重复的request,只有两三个短字符串会编码为Huffman编码。

这个是Cloudflare在6个小时里的访问入口进来的流量的头部况

[译] HPACK:http2中沉默的杀手锏

我们可以看到请求来的头部压缩了76%。因为headers占访问流量大部分,因此所有的访问流量的空间节约十分可观

[译] HPACK:http2中沉默的杀手锏

我们可以看到由于HPACK压缩,整个流量数据量大小减少了53%。

关于http不同版本的区别参考这篇文章https://mp.weixin.qq.com/s/GICbiyJpINrHZ41u_4zT-A

Response Headers

对于response头部,HPACK的收益相对少一些。

Response #1:

cache-control: public, max-age=30

cf-cache-status:HIT

cf-h2-pushed: ,

cf-ray:2ded53145e0c1ffa-DFW

content-encoding: gzip

content-type: text/html; charset=utf-8

date: Wed, 07 Sep 2016 21:41:23 GMT

expires: Wed, 07 Sep 2016 21:41:53 GMT

link: < //cdn.bizible.com/scripts/bizible.js >; rel=preload; as=script, code.jquery.com/jquery-1.11… ; rel=preload; as=script

server: cloudflare-nginx

status:200

vary: Accept-Encoding

x-ghost-cache-status:From Cache

x-powered-by:Express

第一个response的大部分header头会编码为霍夫曼编码,还有一些匹配上了静态字典表。

Response #2:

cache-control: public, max-age=31536000

cf-bgj:imgq:100

cf-cache-status:HIT

cf-ray: 2ded53163e241ffa-DFW

content-type: image/png

date:Wed, 07 Sep 2016 21:41:23 GMT

expires: Thu, 07 Sep 2017 21:41:23 GMT

server:cloudflare-nginx

status:200

vary:Accept-Encoding

x-ghost-cache-status:From Cache

x-powered-by:Express

又一次看到,蓝色的部分匹配上了动态字典表,红色表明匹配上了静态字典表,绿色部分代表了Huffman编码的串。

第二个response可能匹配了全部12个headers中的7个。剩下的5个里面,有4个header的name可以匹配上,然后有6个字符串会去使用Huffman编码。

尽管有两个expires的header是几乎完全相同的,它们也仅使用Huffman编码,因为不能完全匹配上。

有越多的请求去处理,动态字典表就会越大,就会有越多的headers被匹配上,就会提高压缩率。

下面是返回的流量里的header情况。

[译] HPACK:http2中沉默的杀手锏

平均的压缩率是69%。但是整个出口流量的影响并没有很大。

[译] HPACK:http2中沉默的杀手锏

可能压缩情况不容易观察,但是在整个HTTP/2的出口流量里,我们还是有1.4%的节约量。虽然看起来不多,但是数据压缩量的在很多情况还是有增加的。这个数字也会因为网站处理大文件的时候受到影响。我们测量了一些网站的节约量在15%左右


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Python Machine Learning

Python Machine Learning

Sebastian Raschka / Packt Publishing - ebooks Account / 2015-9 / USD 44.99

About This Book Leverage Python' s most powerful open-source libraries for deep learning, data wrangling, and data visualization Learn effective strategies and best practices to improve and opti......一起来看看 《Python Machine Learning》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

URL 编码/解码
URL 编码/解码

URL 编码/解码

SHA 加密
SHA 加密

SHA 加密工具