我正在回答我自己的问题,因为我认为我现在了解 BREACH 以及如何防止它。我很想得到反馈。
BREACH 的工作原理(据我所知)
(在这里扩展对我有帮助的解释。)
假设你是攻击者。您以自己的身份登录服务。您注意到有一个search
端点,如果您发送 search term rabbits
,您会收到如下响应:
<SearchResponse>
<AuthToken>d2a372efa35aab29028c49d71f56789</AuthToken>
<SearchTerm>rabbits</SearchTerm>
<Results>
<Result>rabbits rock</Result>
<Result>yay rabbits</Result>
</Results>
</SearchResponse>
您还注意到响应是经过 gzip 压缩和加密的 (HTTPS)。
您尝试搜索格式与<AuthToken
值类似的字符串,例如aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
. 回应是:
<SearchResponse>
<AuthToken>d2a372efa35aab29028c49d71f56789</AuthToken>
<SearchTerm>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</SearchTerm>
<Results>
</Results>
</SearchResponse>
没有结果。然后你稍微修改你的搜索词:
<SearchResponse>
<AuthToken>d2a372efa35aab29028c49d71f56789</AuthToken>
<SearchTerm>d2a37aaaaaaaaaaaaaaaaaaaaaaaaaa</SearchTerm>
<Results>
</Results>
</SearchResponse>
正如你所希望的,一些有趣的事情正在发生。因为搜索词是无意义的,所以<Results>
总是一样的:空的。唯一改变的是<SearchTerm>
. 并且由于压缩,值越<SearchTerm>
相似<AuthToken>
,响应越小。
这是因为 gzip 压缩的工作原理:它在压缩时消除重复,并在解压缩时恢复它。输入越重复,压缩越小。
您再次搜索,使用<AuthToken>
.
<SearchResponse>
<AuthToken>d2a372efa35aab29028c49d71f56789</AuthToken>
<SearchTerm>d2a372efa35aab29028c49d71f56789</SearchTerm>
<Results>
</Results>
</SearchResponse>
这次你记下响应有多小。现在您知道,只要响应是这种大小,就意味着搜索词与 auth 标记完全匹配。
现在,因为这些是您的请求,您可以直接阅读它们。如果您可以对站点的另一个用户进行 MITM 攻击(例如,通过运行流氓路由器),您将能够看到加密响应的大小,但看不到实际内容。
你自己想:如果我可以欺骗其他人发送我希望他们发送的搜索词,并且如果我能看到加密的响应有多大,我可以一遍又一遍地调整搜索词。我越接近猜测身份验证令牌,响应就越小,当它是我刚刚看到的响应的大小时,我猜对了。一旦我知道他们的身份验证令牌,我就可以以他们的身份登录。
如果你能以某种方式对你的受害者执行 XSS 攻击,你可以让他们提出必要的请求。
减轻
如果出现以下情况,此攻击将不起作用:
- 服务器没有使用 HTTP 压缩(例如 gzip,在我们的示例中)
- 如果没有攻击者不知道的 CSRF 令牌,则无法成功发出请求
- 服务器永远不会将敏感数据(如 API 令牌)和用户提供的数据(如搜索词)放在同一个响应中
- 服务器从不会两次返回相同的 API 令牌(例如,如果原始令牌值在发送之前已加盖时间戳并签名,则时间戳将确保响应中的令牌不断更改)
- 正如@AndrolGenhald 在评论中指出的那样,响应总是包含随机长度的填充(尽管有足够的请求,攻击者可能会将信号与这种噪声分开)
- 如果没有会话 cookie,则无法成功发出请求,并且站点的会话 cookie 具有一个
SameSite
属性,并且潜在的受害者正在使用理解该属性的浏览器,因此它理解不包含来自另一个站点的请求的 cookie。