Cross-site attack using browser cache (will it work?)

Viewed 170

Scheme of the attack: Attacked site makes a request with cookies (but without Vary: Cookie HTTP header), the browser caches a response, attacking site makes the same request (but without cookies because SameSite=Strict directive in Set-Cookie was used) and gets access to the cached response. I must have missed something, or could it work?

Update: I did some experiments:

Express server:

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}`)
})

Attacked and attacker 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 as and expected shows me the token (after a second loading of course). To create an attacker I uploaded the HTML to https://jsfiddle.net/3xaoe4zf/. And it works in Chromium 84! (i.e. jsfiddle shows the token), but does not in Firefox 78. Сan anyone explain this difference?

1 Answers

This attack seems to work (at least in Chromium 84), and Vary: Cookie prevents it.

But it does not work in Firefox because it stores a separate cache for these two sites for some reason (it probably uses Origin or something similar as extra key for the cache). (Just note: Firefox does not use a cache when a page is reloaded using F5.)

This is not a Chromium/Chrome problem, just the cache works this way.

According to the specification:

The primary cache key consists of the request method and target URI.

Also, in the same section, it states that secondary keys (using Vary) can be used:

If a request target is subject to content negotiation, its cache entry might consist of multiple stored responses, each differentiated by a secondary key for the values of the original request's selecting header fields (Section 4.1).

I did not find any specific restrictions in the specification for responses received using cookies.

Update: Chrome will partition its HTTP cache starting in Chrome 86

Related