basic-integrity plugin now handles absolute paths as keys as well (ref. #70)

merge-requests/23/head
Michał 'rysiek' Woźniak 2023-11-01 00:29:35 +00:00
rodzic fb63efbaa6
commit 05e9d6f2a5
3 zmienionych plików z 82 dodań i 5 usunięć

Wyświetl plik

@ -17,8 +17,10 @@ The `basic-integrity` plugin supports the following configuration options:
Array containing exactly one object which is in turn a configuration of a wrapped plugin. This plugin will be used to actually handle any requests.
- `integrity` (default: empty)
An object mapping absolute URLs (e.g. "`https://example.com/img/test.png`") to integrity hashes (e.g. "`sha384-kn5dhxz4RpBmx7xC7Dmq2N43PclV9U/niyh+4Km7oz5W0FaWdz3Op+3K0Qxz8y3z`"). Supported integrity hash algorithms [as per SRI specification](https://w3c.github.io/webappsec-subresource-integrity/#terms): `sha256`, `sha384`, `sha512`.
The integrity string can contain multiple hashes, space-separated, [as per the standard](https://w3c.github.io/webappsec-subresource-integrity/#agility).
An object mapping URLs (e.g. "`https://example.com/img/test.png`") and absolute paths (e.g. "`/img/test.png`") to integrity hashes (e.g. "`sha384-kn5dhxz4RpBmx7xC7Dmq2N43PclV9U/niyh+4Km7oz5W0FaWdz3Op+3K0Qxz8y3z`"). Supported integrity hash algorithms [as per SRI specification](https://w3c.github.io/webappsec-subresource-integrity/#terms): `sha256`, `sha384`, `sha512`.
The integrity string can contain multiple hashes, space-separated, [as per the standard](https://w3c.github.io/webappsec-subresource-integrity/#agility).
When integrity data is specified twice for the same effective URL (once using full URL, once using absolute path), it is concatenated before passing the request on to the wrapped plugin.
Using absolute paths instead of URLs as keys is useful when hosting the same website content under multiple domain names, assuming the same paths are used across all domains.
- `requireIntegrity` (default: `true`)
Boolean value specifying if integrity data is required for a request to handled. That is: if a request is being handled for a URL that does not have integrity data associated with it, should the request be processed, or errored out?

Wyświetl plik

@ -49,6 +49,11 @@ describe('browser: basic-integrity plugin', async () => {
console.debug(component + ' :: ', ...items)
}
}
// mocking window.location
// https://developer.mozilla.org/en-US/docs/Web/API/Window/location
window.location = {
origin: "https://resilient.is"
}
window.resolvingFetch = (url, init) => {
return Promise.resolve(
new Response(
@ -234,5 +239,54 @@ describe('browser: basic-integrity plugin', async () => {
})
assertEquals(await response.json(), {test: "success"})
});
it("should set integrity data specified for absolute paths correctly on relevant requests", async () => {
init.integrity = {
"/test.json": "sha384-kn5dhxz4RpBmx7xC7Dmq2N43PclV9U/niyh+4Km7oz5W0FaWdz3Op+3K0Qxz8y3z"
}
const response = await LibResilientPluginConstructors
.get('basic-integrity')(LR, init)
.fetch('https://resilient.is/test.json');
assertSpyCalls(resolvingFetchSpy, 1)
assertSpyCall(
resolvingFetchSpy,
0,
{
args: [
'https://resilient.is/test.json',
{
integrity: "sha384-kn5dhxz4RpBmx7xC7Dmq2N43PclV9U/niyh+4Km7oz5W0FaWdz3Op+3K0Qxz8y3z"
}
]
})
assertEquals(await response.json(), {test: "success"})
});
it("should concatenate integrity data specified for the same effective URL twice (by absolute path, and by URL)", async () => {
init.integrity = {
"/test.json": "sha384-kn5dhxz4RpBmx7xC7Dmq2N43PclV9U/niyh+4Km7oz5W0FaWdz3Op+3K0Qxz8y3z",
"https://resilient.is/test.json": "sha256-Aj9x0DWq9GUL1L8HibLCMa8YLKnV7IYAfpYurqrFwiQ="
}
const response = await LibResilientPluginConstructors
.get('basic-integrity')(LR, init)
.fetch('https://resilient.is/test.json');
assertSpyCalls(resolvingFetchSpy, 1)
assertSpyCall(
resolvingFetchSpy,
0,
{
args: [
'https://resilient.is/test.json',
{
integrity: "sha256-Aj9x0DWq9GUL1L8HibLCMa8YLKnV7IYAfpYurqrFwiQ= sha384-kn5dhxz4RpBmx7xC7Dmq2N43PclV9U/niyh+4Km7oz5W0FaWdz3Op+3K0Qxz8y3z"
}
]
})
assertEquals(await response.json(), {test: "success"})
});
})

Wyświetl plik

@ -24,9 +24,20 @@
name: "alt-fetch"
}],
// integrity data for each piece of content
// absolute URL -> integrity data (string)
// URL or absolute path -> integrity data (string)
//
// integrity data can contain multiple integrity hashes, space-separated, as per:
// https://w3c.github.io/webappsec-subresource-integrity/#agility
//
// integrity data specified for the same effective URL twice (using the whole URL,
// and then only the path) is concatenated
//
// for example, these two entries:
// "https://example.org/some/path/index.html": "sha384-..."
// "/some/path/index.html": "sha512-..."
//
// ...will result, if request URL is https://example.org/some/path/index.html and
// origin is https://example.org, in concatenated integrity data for that request.
integrity: {},
// if an URL has no integrity data associated with it, should it be allowed or not?
requireIntegrity: true
@ -57,11 +68,21 @@
}
// do we have integrity data in config?
// TODO: how should we treat relative URLs? how does regular fetch() treat them
//
// the service worker would send the fetch our way only if the origin matched the URL
// and we only ever get full URLs anyway
// trying a full URL (schema://example.com/...)
if (url in config.integrity) {
integrity += ' ' + config.integrity[url]
}
// trying just the path, without schema and without the domain
let path = url.replace(self.location.origin, "")
if (path in config.integrity) {
integrity += ' ' + config.integrity[path]
}
// some cleanup
integrity = integrity.trim()
@ -74,7 +95,7 @@
} else if (config.requireIntegrity) {
// bail if integrity data is not available
throw new Error(`Integrity data required but not provided for: ${url}`)
throw new Error(`Integrity data required but not provided for: ${url} nor ${path}`)
}
// log