Subresource integrity (SRI) Support
Description
As a developer using Vike, I would like to add a SRI attributes including integrity="sha384-$HASH" and crossorigin="anonymous" to all preload modules with external sources (starting with http or https).
Reference https://github.com/vitejs/vite/issues/2377. There is no current viable workaround.
Suggested solution
Modify vike/node/runtime/html/injectAssets/inferHtmlTags.ts to include SRI attributes in the various types of tags when an integrity is present in pageAsset.
function inferPreloadTag(pageAsset: PageAsset): string {
const { src, assetType, mediaType, integrity } = pageAsset
const rel = getRel(pageAsset)
// `crossorigin` is needed for fonts, see https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/preload#cors-enabled_fetches
let crossorigin = null
if (isCrossOrigin(pageAsset) && !integrity) crossorigin = 'crossorigin'
if (integrity) crossorigin = 'crossorigin="anonymous"'
const attributes = [
`rel="${rel}"`,
`href="${src}"`,
!assetType ? null : `as="${assetType}"`,
!mediaType ? null : `type="${mediaType}"`,
!integrity ? null : `integrity="${integrity}"`,
crossorigin
]
.filter(Boolean)
.join(' ')
return `<link ${attributes}>`
}
function inferAssetTag(pageAsset: PageAsset): string {
const { src, assetType, mediaType, integrity } = pageAsset
const integrityAttrs = !integrity ? null : `integrity="${integrity}" crossorigin="anonymous"`
if (assetType === 'script') {
assert(mediaType === 'text/javascript')
return `<script src="${src}" ${scriptAttrs} ${integrityAttrs}></script>`
}
if (assetType === 'style') {
// WARNING: if changing following line, then also update https://github.com/vikejs/vike/blob/fae90a15d88e5e87ca9fcbb54cf2dc8773d2f229/vike/client/shared/removeFoucBuster.ts#L29
return `<link rel="stylesheet" type="text/css" href="${src}" ${integrityAttrs}>`
}
assert(false, { pageAsset })
}
Modify vike/node/runtime/renderPage/getPageAssets.ts to add integrity attribute values for each pageAsset. There are a lot of approaches here. Vike is aware of the filepaths and could easily calculate the SHA hashes when a setting like useSRI = true. Alternatively the user could provide an object matching filename to hash or callback function. There could also be a user hook
The browser accepts multiple hash algorithms, but we could strictly stick with SHA384.
Alternative
The available Vite plugins do not work as expected because Vike controls the dynamic injection of assets in <script> and <link> tags, based on the content of the page.
Another option is a DOM MutationObserver, but I don't think there is a way to make this work with SSR, although it could be added during SSR. The observer needs to make changes before the browser parses the HTML.
I considered modifying the injectFilter hook, but this seems to be focussed much more on filtering and ordering.
Additional context
We have a credit card entry form as part of our app and we must comply with PCI DSS v4.0.1. Part of this requirement is that all "payment page scripts" must have a mechanism to verify their integrity. SRI fits the bill.
See also
- https://github.com/vikejs/vike/issues/1554
Would a CSP nonce comply? See https://github.com/vikejs/vike/issues/1554.
With integrity="sha384-$HASH" you mean that the $HASH is the value from applying the SHA384 algorithm on the content of the script, correct? That could actually be easy to implement (easier than a CSP nonce). Would you be up for a PR? I can guide your through the code. I can also implement it myself but then I'll need a precise description of what is needed.
PCI DSS v4.0.1
Good to know, thanks for sharing that.
We've decided we do not need to go the SRI route and that CSP nonce satisfies the PCI requirements. This is covered under
You must prevent execution of unauthorized scripts and have a method to authorize each script This is PCI DSS 4.0.1 section 6.4.3 We're going to go the route in https://github.com/vikejs/vike/issues/1554
Thank you for circling back on this.
Re-opening as it may be relevant to other users.