我的 Apache 是 2.4.46 并且使用的是 Openssl 版本 1.1.1f
我已经设置了指令SSLCompression Off
。即使我启用它,它也会说不支持 SSL 压缩,我想这很好。
但是,当我使用 Firefox 查看网页的 HTTP 标头时,我会看到以下响应标头:
HTTP/2 200 OK
date: Fri, 25 Dec 2020 12:13:58 GMT
server: Apache
expires: -1
cache-control: no-store, no-cache, must-revalidate, max-age=0
pragma: no-cache
content-security-policy: default-src https: 'unsafe-inline' 'unsafe-hashes' 'self'; img-src data: https: 'self'
x-frame-options: DENY
x-xss-protection: 1; mode=block
x-content-type-options: nosniff
strict-transport-security: max-age=63072000; includeSubDomains; preload
referrer-policy: no-referrer
permissions-policy: geolocation=();midi=();notifications=();push=();sync-xhr=(self);microphone=();camera=();magnetometer=();gyroscope=();speaker=(self);vibrate=();fullscreen=(self);payment=();
vary: Accept-Encoding
content-encoding: gzip
content-length: 3299
content-type: text/html; charset=UTF-8
X-Firefox-Spdy: h2
那句话是:content-encoding: gzip
让我担心。
但是,即使我使用 cURL 在 PHP 中使用此脚本来获取页面:
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
//enable headers
curl_setopt($ch, CURLOPT_HEADER, 1);
//get only headers
curl_setopt($ch, CURLOPT_NOBODY, 1);
curl_setopt($ch, CURLOPT_TIMEOUT_MS, 5000);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:84.0) Gecko/20100101 Firefox/84.0");
curl_setopt($ch, CURLOPT_ENCODING, "gzip");
它返回这些 HTTP 标头:
HTTP/2 200
date: Fri, 25 Dec 2020 12:16:45 GMT
server: Apache
set-cookie: __Secure-CCJRLSESSID=g7m99kljvea2g5uk58f5lfskr1; path=/; secure; HttpOnly; SameSite=Lax
expires: -1
cache-control: no-store, no-cache, must-revalidate, max-age=0
pragma: no-cache
content-security-policy: default-src https: 'unsafe-inline' 'unsafe-hashes' 'self'; img-src data: https: 'self'
x-frame-options: DENY
x-xss-protection: 1; mode=block
x-content-type-options: nosniff
strict-transport-security: max-age=63072000; includeSubDomains; preload
referrer-policy: no-referrer
permissions-policy: geolocation=();midi=();notifications=();push=();sync-xhr=(self);microphone=();camera=();magnetometer=();gyroscope=();speaker=(self);vibrate=();fullscreen=(self);payment=();
content-type: text/html; charset=UTF-8
这让我很困惑。我什至清除了 Firefox 中的缓存,但没有运气。我不想受到 CRIME 攻击。反过来,我可以完全禁用 gzip。但在我这样做之前,我想知道为什么会发生这种情况。也许是 Firefox 的错误??
更新:
它也发生在 chrome 中。
mod_deflate 配置:
SSLCompression Off
<IfModule deflate_module>
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
AddOutputFilterByType DEFLATE application/x-font
AddOutputFilterByType DEFLATE application/x-font-opentype
AddOutputFilterByType DEFLATE application/x-font-otf
AddOutputFilterByType DEFLATE application/x-font-truetype
AddOutputFilterByType DEFLATE application/x-font-ttf
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE font/opentype
AddOutputFilterByType DEFLATE font/otf
AddOutputFilterByType DEFLATE font/ttf
AddOutputFilterByType DEFLATE image/svg+xml
AddOutputFilterByType DEFLATE image/x-icon
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/xml
</IfModule>
针对CVE-2012-4929的 CRIME 攻击是在不正确混淆未加密数据的长度的情况下加密压缩的标头,这使得揭示明文标头(通过猜测)成为可能。
在您的情况下,内容被压缩,压缩数据的大小(长度)被添加为另一个标题,然后所有这些都被加密。这不容易受到 CRIME 攻击,因为未加密数据的长度永远不会泄露。
要回答您的问题,了解一些背景知识会有所帮助:
背景 - 为什么使用压缩可能会带来安全风险?
有一些所谓的“压缩侧信道攻击”基本上是使用压缩结果来尝试猜测原始文本。每个基本上都是通过将输入添加到压缩然后观察输出来工作的。这是因为许多压缩算法通过识别重复的文本并用引用替换它们来工作,而不是多次完整地重复文本。这会导致较小的消息,但确实打开了攻击机会。
这些攻击如何运作?
基本上,如果您猜测部分或全部秘密部分,将其与未知秘密部分一起添加到消息中,然后观察加密结果的大小,如果通过某些猜测它变得更小,那么您必须重复部分消息因此受益于更高的压缩率。
通过一些猜测,有可能找出秘密部分。这样做取决于能够添加到消息中,但有多种方法可以做到这一点。例如,如果您想知道
token
example.com 的 cookie 集,然后发送一条消息(可能是当人们访问您完全不相关的站点时发生的隐藏 XHR 消息?)example.com?token=1
并测量生成的消息大小(因为浏览器会自动添加消息的 cookie 也是如此)。然后尝试example.com?token=2
看看它是否更大,更小或相同。对所有可能的值重复此操作,直到找到 cookie 的第一个字符,其中消息会更小。假设在这个例子中它是token=5
. 然后尝试第二个字符(例如example.com?token=51
,example.com?token=52
...等)。重复直到你有完整的cookie。您可以直接测量消息的长度(例如,如果您可以在网络中间人,则通过观察加密的消息)或发送消息所需的时间,以便很好地猜测长度。
HTTP 消息可以通过多种方式进行压缩
压缩可以在 HTTP 消息中发生不同级别:1)在 SSL/TLS 级别,2)在 HTTP 正文级别和 3)在 HTTP 标头级别。
SSL 压缩
进行 SSL/TLS 压缩基本上不管它是下面的 HTTP 消息这一事实 - 它是在 SSL/TLS 级别完成的。像CRIME这样的攻击基本上阻止了我们使用 SSL/TLS 压缩,因为它引入了太多的方法来猜测消息的隐藏部分,基本上是使用上述算法。老实说,SSL/TLS 压缩的收益并没有那么大,特别是如果我们已经使用 gzip 或类似方法在底层 HTTP 级别压缩了正文响应,因此在加密后再次压缩它并没有真正节省那么多更多数据。所以没有真正的理由使用它,这给了一个真正的理由不使用它。SSL/TLS 压缩应始终关闭并使用SSLLabs 之类的工具确认这一点。在大多数服务器中默认情况下它是关闭的,并且已经有一段时间了,所以打开它会非常惊讶。
HTTP 正文压缩
HTTP Body 级别的压缩更有趣。这通常使用 gzip 或较新的 Brotli 算法,并且建议在大多数情况下启用,因为 Web 性能的提升非常显着。这是因为 HTTP 主体通常很大(特别是响应主体)并且网络通常相对较慢——因此通过网络发送较小的主体会带来真正的收益。现在是的,理论上这很容易受到类似的攻击(所谓的BREACH 攻击和TIME变体)——但前提是秘密数据再次出现在正文中(因此任何相同的猜测在压缩后都可以看出更小)。因此风险要小得多,因为大多数响应不包含秘密数据(例如,您最后一次看到您的 cookie 打印到页面上的屏幕是什么时候?),而标题中的 cookie 通常总是包含在内,并且在消息中占较大比例.
当然,如果您有一些打印到屏幕上的秘密信息(您的姓名、社会保险号、DoB、银行详细信息等),那么它可能很容易受到攻击,也许应该考虑不使用 HTTP 压缩这些响应,但这些响应是非典型的因此,为每个响应禁用 HTTP 压缩很少是正确的答案。即使您在屏幕上显示秘密信息,也有更好的选择:例如,根本不在屏幕上显示该数据,或者至少不完整显示(例如,除了最后 4 位之外的所有数字),不允许显示用户响应数据例如,同时在屏幕上显示,用随机字符填充数据或添加速率限制通常是更好的选择。
回到你的问题
因此,要回答您的问题,SSL 压缩和 HTTP 正文压缩是两个不同的东西,前者应该关闭,后者应该打开(除了在真正安全的应用程序中,尽管有收益,但不想冒这个风险 - 但即便如此,通常有更好的方法来处理这个)。
最后,一些关于 HTTP Header 压缩的额外信息
为了结束这个故事,让我们谈谈 HTTP 标头压缩,因为如上所述,它们通常包含攻击者会发现有价值的 cookie 机密。
HTTP/1.1 直到最近还是使用的主要版本,它不允许这样做,所以这里没有太多可谈的。这些以完全未压缩的形式发送(尽管如果使用 HTTPS 则使用 SSL/TLS 加密),因此不易受到侧通道压缩风险的影响(假设未使用 SSL 压缩)。
与 HTTP 主体相比,它们通常也非常小,因此没有人真正担心压缩它们太多。然而,随着用于构成网页的资源数量的增加(现在超过 100 个并不少见),在一直来回发送几乎相同的 HTTP 标头时会出现很多冗余(您是否看到过大小例如,用户代理标头的名称随每个请求一起发送,但对于所有这些请求从不更改?)。
因此,较新的 HTTP/2 和即将发布的 HTTP/3 协议确实允许 HTTP Header 压缩,但它们特别选择了一种不易受到这些攻击的压缩算法(HTTP/2 的 HPACK 和 HTTP/3 的类似 QPACK)。顺便说一句,这是一个明确的选择,因为 HTTP/2 所基于的早期 SPDY 协议确实使用了 gzip,因此很容易受到攻击。因此,当它被标记时,它必须作为将其标准化为 HTTP/2 的一部分进行更改。
为什么不总是使用“安全压缩”?
那么为什么我们不能对 HTTP 响应体也使用安全压缩技术(如 HPACK 或 QPACK)并避免这种情况呢?嗯,它们是非常具体的压缩技术,它使用字典或已知和重复的值。这适用于值很少且大量重复的 HTTP 标头,但对于更通用的 HTTP 主体响应来说,这并不是一个真正的选择,因为每个响应可能完全不同。
希望这能解释一些事情,从而回答你的问题。