Imagine a site with two documents: index.html
and test.jpg
, both located at the root. index.html
has the following content.
<!DOCTYPE html>
<html lang=en>
<head>
<meta charset=utf-8>
<meta content="text/html; charset=utf-8" http-equiv=content-type>
<title>Test</title>
</head>
<body>
<p>Hello.</p>
<img src="/test.jpg">
</body>
</html>
If served with no security headers, this works just fine. However, with these headers on index.html
:
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin
and this header on test.jpg
:
Cross-Origin-Resource-Policy: same-origin
test.jpg
will no longer be loaded by Chrome 98. It reports net::ERR_BLOCKED_BY_RESPONSE.NotSameOrigin 200
in the console.
Adding the following header to index.html
will cause the image to be blocked by Firefox 97 as well:
Content-Security-Policy: default-src 'none'; style-src 'self'; img-src 'self'; prefetch-src 'self'; frame-ancestors 'none'; form-action 'none'; upgrade-insecure-requests; block-all-mixed-content; disown-opener; sandbox; base-uri 'none'
(I'm aware that that's a lot of directives, but I tried to bisect them to what was important and couldn't figure it out.)
What is happening here? https://example.com
and https://example.com/test.jpg
are the same origin, aren't they? Explicitly navigating to https://example.com/index.html
also blocks the loading of test.jpg
. What is missing from my understanding of same-origin? Why is there a difference between Chrome and Firefox's handling? Why does adding CSP cause Firefox to start blocking the requests for test.jpg
?
In case I missed something, here are the complete set of headers for each request (from cURL):
> GET / HTTP/2
> Host: example.com
> user-agent: curl/7.77.0
> accept: */*
>
< HTTP/2 200
< date: Wed, 16 Feb 2022 04:56:43 GMT
< server: Apache
< via: e3s
< last-modified: Wed, 16 Feb 2022 04:43:18 GMT
< content-length: 226
< x-content-type-options: nosniff
< referrer-policy: same-origin
< content-security-policy: default-src 'none'; style-src 'self'; img-src 'self'; prefetch-src 'self'; frame-ancestors 'none'; form-action 'none'; upgrade-insecure-requests; block-all-mixed-content; disown-opener; sandbox; base-uri 'none'
< cross-origin-embedder-policy: require-corp
< cross-origin-opener-policy: same-origin
< etag: "e2-5d81b49ddfad8"
< accept-ranges: bytes
< vary: Accept-Encoding
< content-type: text/html; charset=UTF-8
<
> GET /test.jpg HTTP/2
> Host: example.com
> user-agent: curl/7.77.0
> accept: */*
>
< HTTP/2 200
< date: Wed, 16 Feb 2022 04:52:19 GMT
< server: Apache
< x-content-type-options: nosniff
< referrer-policy: same-origin
< cross-origin-resource-policy: same-origin
< last-modified: Wed, 16 Feb 2022 04:22:59 GMT
< etag: "18692-5d81b013bbe82"
< accept-ranges: bytes
< content-length: 99986
< cache-control: public, max-age=31557600, immutable
< age: 336
< via: e2s
< content-type: image/jpeg
<
I have not tried to reproduce, but from reading this it would make sense for Firefox to start blocking as you sandboxed the document, meaning it has an opaque origin and therefore the image will appear cross-origin.
As for Chrome, could sandboxing have been in effect there too somehow?