Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Subresource integrity (SRI) Support #2154

Open
steve-a-walsh opened this issue Feb 7, 2025 · 1 comment
Open

Subresource integrity (SRI) Support #2154

steve-a-walsh opened this issue Feb 7, 2025 · 1 comment
Labels
enhancement 🚀 New feature or request

Comments

@steve-a-walsh
Copy link

steve-a-walsh commented Feb 7, 2025

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 vitejs/vite#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.

@steve-a-walsh steve-a-walsh added the enhancement 🚀 New feature or request label Feb 7, 2025
@brillout
Copy link
Member

brillout commented Feb 8, 2025

Would a CSP nonce comply? See #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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement 🚀 New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants