首页 > 解决方案 > 使用浏览器缓存的跨站点攻击(会起作用吗?)

问题描述

攻击方案:被攻击站点使用 cookie 发出请求(但没有Vary: CookieHTTP 标头),浏览器缓存响应,攻击站点发出相同的请求(但没有 cookie,因为使用SameSite=Strict了指令 in Set-Cookie)并访问缓存的响应。我一定错过了什么,或者它可以工作吗?

更新:我做了一些实验:

快递服务器:

const express = require('express')
const app = express()
const port = 3000

app.get('/token', (req, res) => {
    let secret = "No access";
    if (req.headers['cookie'] && req.headers['cookie'].includes('token=1234')) {
        secret = '1234';
    }
    res.set({
        'Set-Cookie': 'token=1234; Path=/; Max-Age=2592000; HttpOnly; SameSite=Strict',
        'Access-Control-Allow-Origin': '*',
        'Content-Type': 'text/plain',
        'ETag': secret,
        // 'Vary': 'Cookie',
        'Cache-Control': 'max-age=1000',
    });
    res.send(secret);
})
app.get('/', (req, res) => {
    res.sendFile(__dirname + '/index.html');
})

app.listen(port, () => {
    console.log(`Example app listening at http://localhost:${port}`)
})

被攻击和攻击者index.html


<!DOCTYPE html>
<html>
<body>
    <div></div>
    <script>
        fetch('http://localhost:3000/token').then(function(response) {
            return response.text();
        }).then(function(text) {
            document.querySelector('div').textContent = text;
        });
    </script>
</body>
</html>

localhost:3000正如预期的那样,向我展示了令牌(当然是在第二次加载之后)。为了创建攻击者,我将 HTML 上传到https://jsfiddle.net/3xaoe4zf/。它适用于 Chromium 84!(即 jsfiddle 显示了令牌),但在 Firefox 78 中没有。有人可以解释这种差异吗?

标签: httpsecurityhttp-headersbrowser-cachehttp-caching

解决方案


这种攻击似乎有效(至少在 Chromium 84 中),并Vary: Cookie阻止了它。

但它在 Firefox 中不起作用,因为它出于某种原因为这两个站点存储了一个单独的缓存(它可能使用Origin或类似的东西作为缓存的额外键)。(请注意:当使用 F5 重新加载页面时,Firefox 不使用缓存。)

这不是 Chromium/Chrome 问题,只是缓存以这种方式工作。

根据规范

主缓存键由请求方法和目标 URI 组成。

此外,在同一部分中,它指出Vary可以使用辅助键(使用 ):

如果请求目标接受内容协商,则其缓存条目可能包含多个存储的响应,每个响应由原始请求的选择标头字段的值的辅助键进行区分(第 4.1 节)。

对于使用 cookie 接收的响应,我在规范中没有发现任何具体限制。

更新:Chrome 将从 Chrome 86 开始对其 HTTP 缓存进行分区


推荐阅读