Skip to content

Revive require-sri-for for scripts #129

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

Closed
wants to merge 7 commits into from
Closed

Conversation

yoavweiss
Copy link

@yoavweiss yoavweiss commented Feb 6, 2025

This ~reverts https://github.com/w3c/webappsec-subresource-integrity/pull/82/files, which reverted require-sri-for.

It only includes the script token, as it has a clear use case.

I believe the reasons for removing require-sri-for are losing ground:

Integrity checks for workers are still missing, but there's work underway to enable importmaps in workers which will give us that, at least for some assets.

require-sri-for CSP directive

Subresource-Integrity (SRI) enables developers to make sure the assets they intend to load are indeed the assets they are loading. But there's no current way for developers to be sure that all of their scripts are validated using SRI.

The require-sri-for CSP directive gives developers the ability to assert that every resource of a given type needs to be integrity checked. If a resource of that type is attempted to be loaded without integrity metadata, that attempt will fail and trigger a CSP violation report.

Example usage

A developer that wants to validate that all of their script resources have integrity checks will be able to add a CSP header similar to:

Content-Security-Policy: require-sri-for 'script' 

(Or the equivalent <meta> tag)

From that point, any external script that is fetched without a valid integrity attribute (that is, one that translates into non-empty integrity metadata) or with a "no-cors" request mode, will not be loaded.
It will also trigger a "securitypolicyviolation" event, as well as a CSP report.


Preview | Diff

@yoavweiss yoavweiss marked this pull request as draft February 6, 2025 07:50
@yoavweiss
Copy link
Author

Further work on this would require:

  • Ensuring data/blob URLs get a free pass
  • Ensuring Signature-based SRI is considered "integrity metadata".

We'd also need tests for the above

aarongable pushed a commit to chromium/chromium that referenced this pull request Feb 13, 2025
`require-sri-for` would enable documents to enforce SRI on all resources
they load (of a certain type). This CL revives a previous attempt [1]
at this that ended up being removed. It only adds the 'script' part of
it, as this has a clear use case [2].

Intent-to-Prototype: https://groups.google.com/a/chromium.org/g/blink-dev/c/CdLp5BM2FCQ/m/t9ae0Do_AAAJ

Spec PR: w3c/webappsec-subresource-integrity#129


[1] https://chromium-review.googlesource.com/c/chromium/src/+/2199260
[2] https://docs.google.com/document/d/1RcUpbpWPxXTyW0Qwczs9GCTLPD3-LcbbhL4ooBUevTM/edit?tab=t.0

Change-Id: I66acc12b073174cb33cf594b714e803e24656d27
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5877633
Reviewed-by: Antonio Sartori <[email protected]>
Commit-Queue: Yoav Weiss (@Shopify) <[email protected]>
Reviewed-by: Arthur Sonzogni <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1419883}
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this pull request Feb 13, 2025
`require-sri-for` would enable documents to enforce SRI on all resources
they load (of a certain type). This CL revives a previous attempt [1]
at this that ended up being removed. It only adds the 'script' part of
it, as this has a clear use case [2].

Intent-to-Prototype: https://groups.google.com/a/chromium.org/g/blink-dev/c/CdLp5BM2FCQ/m/t9ae0Do_AAAJ

Spec PR: w3c/webappsec-subresource-integrity#129

[1] https://chromium-review.googlesource.com/c/chromium/src/+/2199260
[2] https://docs.google.com/document/d/1RcUpbpWPxXTyW0Qwczs9GCTLPD3-LcbbhL4ooBUevTM/edit?tab=t.0

Change-Id: I66acc12b073174cb33cf594b714e803e24656d27
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5877633
Reviewed-by: Antonio Sartori <[email protected]>
Commit-Queue: Yoav Weiss (@Shopify) <[email protected]>
Reviewed-by: Arthur Sonzogni <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1419883}
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this pull request Feb 13, 2025
`require-sri-for` would enable documents to enforce SRI on all resources
they load (of a certain type). This CL revives a previous attempt [1]
at this that ended up being removed. It only adds the 'script' part of
it, as this has a clear use case [2].

Intent-to-Prototype: https://groups.google.com/a/chromium.org/g/blink-dev/c/CdLp5BM2FCQ/m/t9ae0Do_AAAJ

Spec PR: w3c/webappsec-subresource-integrity#129

[1] https://chromium-review.googlesource.com/c/chromium/src/+/2199260
[2] https://docs.google.com/document/d/1RcUpbpWPxXTyW0Qwczs9GCTLPD3-LcbbhL4ooBUevTM/edit?tab=t.0

Change-Id: I66acc12b073174cb33cf594b714e803e24656d27
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5877633
Reviewed-by: Antonio Sartori <[email protected]>
Commit-Queue: Yoav Weiss (@Shopify) <[email protected]>
Reviewed-by: Arthur Sonzogni <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1419883}
@yoavweiss yoavweiss marked this pull request as ready for review February 14, 2025 05:19
@yoavweiss
Copy link
Author

  • Ensuring data/blob URLs get a free pass

Done

  • Ensuring Signature-based SRI is considered "integrity metadata".

The relevant Fetch parts mean that any string is considered a non-empty integrity metadata.
At the same time, we explicitly test that unknown signatures cause a request to be blocked.

@yoavweiss
Copy link
Author

The relevant Fetch parts mean that any string is considered a non-empty integrity metadata.
At the same time, we explicitly test that unknown signatures cause a request to be blocked.

done!

index.bs Outdated
Comment on lines 360 to 374
### Parsing `require-sri-for` ### {#parse-require-sri-for}

Given a string (|token list|), this algorithm returns a list of resource
types which will require integrity checks:

1. Let |protected resource types| be the empty <a for=/>set</a>.

2. For each |token| in the result of <a lt="split a string on ascii whitespace">
splitting |token list| on spaces</a>, if token matches the grammar
for <a>require-sri-for</a> and is a <a>ASCII case-insensitive match</a>
for any of the <a>known token</a>s, add |token| to |protected resource types|.
Otherwise, ignore the token.

3. Return the set of |protected resource types|.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How likely is it that we expand the list of known tokens? Otherwise a simple string-equals match would suffice.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously the list also included "style". As I don't have a clear use case for it, I didn't add it here.

We could drop this to be a simple equality check now, and expand to a list if/when the time comes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What should the behavior be in user agents which don't understand the new type?

This suggestion would make them not enforce anything at all, which seems suboptimal?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is the way CSP directives are currently defined, and that enabled us to expand them over time.

Not enforcing anything on unknown types would enable us to expand the list overtime if needed. What's the alternative you see?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking through @annevk's other comment, workers may be a good candidate for near-future expansion of the list.

@mozfreddyb
Copy link
Collaborator

With my editor hat on, I think this passes review.
With my Mozilla dinosaur hat on: We may want to align such that we have more than one implementation in planning before we merge this. How fitting that the topic is on the webappsec agenda for this week.

moz-v2v-gh pushed a commit to mozilla/gecko-dev that referenced this pull request Feb 18, 2025
Automatic update from web-platform-tests
require-sri-for: 'script'

`require-sri-for` would enable documents to enforce SRI on all resources
they load (of a certain type). This CL revives a previous attempt [1]
at this that ended up being removed. It only adds the 'script' part of
it, as this has a clear use case [2].

Intent-to-Prototype: https://groups.google.com/a/chromium.org/g/blink-dev/c/CdLp5BM2FCQ/m/t9ae0Do_AAAJ

Spec PR: w3c/webappsec-subresource-integrity#129

[1] https://chromium-review.googlesource.com/c/chromium/src/+/2199260
[2] https://docs.google.com/document/d/1RcUpbpWPxXTyW0Qwczs9GCTLPD3-LcbbhL4ooBUevTM/edit?tab=t.0

Change-Id: I66acc12b073174cb33cf594b714e803e24656d27
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5877633
Reviewed-by: Antonio Sartori <[email protected]>
Commit-Queue: Yoav Weiss (@Shopify) <[email protected]>
Reviewed-by: Arthur Sonzogni <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1419883}

--

wpt-commits: 5f473f1dcc4b545448d84c380b4a6715db612fd1
wpt-pr: 50681
i3roly pushed a commit to i3roly/firefox-dynasty that referenced this pull request Feb 19, 2025
Automatic update from web-platform-tests
require-sri-for: 'script'

`require-sri-for` would enable documents to enforce SRI on all resources
they load (of a certain type). This CL revives a previous attempt [1]
at this that ended up being removed. It only adds the 'script' part of
it, as this has a clear use case [2].

Intent-to-Prototype: https://groups.google.com/a/chromium.org/g/blink-dev/c/CdLp5BM2FCQ/m/t9ae0Do_AAAJ

Spec PR: w3c/webappsec-subresource-integrity#129

[1] https://chromium-review.googlesource.com/c/chromium/src/+/2199260
[2] https://docs.google.com/document/d/1RcUpbpWPxXTyW0Qwczs9GCTLPD3-LcbbhL4ooBUevTM/edit?tab=t.0

Change-Id: I66acc12b073174cb33cf594b714e803e24656d27
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5877633
Reviewed-by: Antonio Sartori <[email protected]>
Commit-Queue: Yoav Weiss (@Shopify) <[email protected]>
Reviewed-by: Arthur Sonzogni <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1419883}

--

wpt-commits: 5f473f1dcc4b545448d84c380b4a6715db612fd1
wpt-pr: 50681
@mikewest
Copy link
Member

On the process question @mozfreddyb raised above:

We discussed this in the WebAppSec WG yesterday (minutes at https://github.com/w3c/webappsec/blob/main/meetings/2025/2025-02-19-minutes.md#reviving-require-sri-for). Generally, folks on the call (and folks I've talked to elsewhere) are on board with this functionality.

I'd like to wait to land this in the spec until we've kicked off the adoption process for this work; it's quite clearly covered by our current charter, but I'd like to formally get the ball rolling on an SRI Level 2 we can continually update under the new(ish) W3C publication process. Once that's in place, adding this as a feature to that new workstream should be straightforward.

@simoneonofri is going to send out an email to the list to that effect based on yesterday's conversation, and if all goes well, I think we can get this in by March.

Does that work for you, @mozfreddyb and @yoavweiss?

@yoavweiss
Copy link
Author

yoavweiss commented Feb 20, 2025

Does that work for you?

Yeah, thank you! :)

@mozfreddyb
Copy link
Collaborator

Yes, but specifically, once we move to a Living Standard I would like us to ensure that we have more than 1 implementation interested and with a positive standards position before merging any changes here and elsewhere

@mikewest
Copy link
Member

@mozfreddyb: I suspect we'd generally want to end up with something like https://whatwg.org/working-mode, which sets different bars for different kinds of changes.

That said, you're editing this spec, and I think that gives you a reasonable amount of freedom to interpret when something is supported-enough to land.

jamienicol pushed a commit to jamienicol/gecko that referenced this pull request Feb 25, 2025
Automatic update from web-platform-tests
require-sri-for: 'script'

`require-sri-for` would enable documents to enforce SRI on all resources
they load (of a certain type). This CL revives a previous attempt [1]
at this that ended up being removed. It only adds the 'script' part of
it, as this has a clear use case [2].

Intent-to-Prototype: https://groups.google.com/a/chromium.org/g/blink-dev/c/CdLp5BM2FCQ/m/t9ae0Do_AAAJ

Spec PR: w3c/webappsec-subresource-integrity#129

[1] https://chromium-review.googlesource.com/c/chromium/src/+/2199260
[2] https://docs.google.com/document/d/1RcUpbpWPxXTyW0Qwczs9GCTLPD3-LcbbhL4ooBUevTM/edit?tab=t.0

Change-Id: I66acc12b073174cb33cf594b714e803e24656d27
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5877633
Reviewed-by: Antonio Sartori <[email protected]>
Commit-Queue: Yoav Weiss (@Shopify) <[email protected]>
Reviewed-by: Arthur Sonzogni <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1419883}

--

wpt-commits: 5f473f1dcc4b545448d84c380b4a6715db612fd1
wpt-pr: 50681
@annevk
Copy link
Member

annevk commented Mar 4, 2025

Was it ever considered to make this part of script-src somehow? Do we have use cases beyond script?

cc @sysrqb

@yoavweiss
Copy link
Author

Given the WAICT proposal and the discussion at WebAppSec last week, I'm renaming the directive to integrity-required to fit the rest of the integrity-* directives. This would also resolve the compat issues.

@annevk - On that call @mozfreddyb mentioned that we've already had the "directive vs. keyword" discussion in the past, and directive won. @mozfreddyb - can you post links to past discussions?

@yoavweiss yoavweiss requested review from mozfreddyb and annevk March 24, 2025 05:28
@mozfreddyb
Copy link
Collaborator

I went through original posts a couple weeks ago.

The first draft of SRI actually had an integrity policy header, but we removed that from the spec as no implementation was interested. Once GitHub had deployed SRI, they noticed that it's rather easy to forget so they called for a SRI source-expression (see (1) below), but we decided that go for a directive.

Brad Hill also suggested factoring it out of CSP due to the increasing complexity within CSP, which imho has continuously grown since then. Reporting is already its own thing, which IMO was a good choice.


  1. [CSP] "sri" source expression to enforce SRI (Dec 2015)
  2. [SRI] require-sri-for syntax and additional SRI/CSP interaction (Sep 2016)
  3. [SRI] require-sri-for: missing integrity metadata? same-origin loads? (Sep 2016)

@mozfreddyb
Copy link
Collaborator

Revisiting this after a good night of sleep, I am even more of the opinion that we're going to be able to avoid a lot of cruft and complexity by moving this to its own header.

@yoavweiss
Copy link
Author

Revisiting this after a good night of sleep

Jetleggly jealous :)

avoid a lot of cruft and complexity by moving this to its own header

Do you have a spelling in mind?

If not, I suggest we go with Integrity as the header name, and an SF list of tokens+parameters as the value.

For this specifically, one would emit: Integrity: required;script

If in the future we'd add e.g. manifest-src and style integrity enforcement, it would become Integrity: required;script;style, manifest-src;url="/foobar.json"

Does this work for y'all?

@mozfreddyb
Copy link
Collaborator

If the CSP syntax is not universally hated (???), I would keep the same syntax, namely

  • directives separated by a semicolon
  • directives start with a directive name and then a list of white-space-separated directive values

@mozfreddyb
Copy link
Collaborator

e.g. Integrity: required-inline script style (where inline says that integrity in HTML is fine, whereas other policies may say that integrity should be part of the header or a manifest)

@rvaneijk
Copy link

Friendly remark: why not staying close to the original ask:

Content-Security-Policy: require-sri-for 'TYPE'

where TYPE can be, e.g., 'script' 'style'

and perhaps - if there are use cases for these - 'script-src' 'script-src-elem' 'style-src' 'style-src-elem'

@yoavweiss
Copy link
Author

If not, I suggest we go with Integrity as the header name, and an SF list of tokens+parameters as the value.

I forgot, but we'd also need the -Report-Only equivalent..

@yoavweiss
Copy link
Author

If the CSP syntax is not universally hated (???), I would keep the same syntax, namely

  • directives separated by a semicolon
  • directives start with a directive name and then a list of white-space-separated directive values

That would mean yet another custom parser in the browser, that's kinda like CSP, but slightly different (as I believe we wanted the multiple header reconciliation to be different here, right?)

If we're keeping the same syntax, what are the benefits of splitting this to a separate header?

@mozfreddyb
Copy link
Collaborator

@rvaneijk Looks like some web pages out there area still using the header without it enforcing something. These would break. Secondly, we already know that the original require-sri-for (even if slightly differently spelled) wouldn't cater to the future use cases that we (Mozilla) already know we want to implement.

@mozfreddyb
Copy link
Collaborator

That would mean yet another custom parser in the browser, that's kinda like CSP, but slightly different (as I believe we wanted the multiple header reconciliation to be different here, right?)

Right. @annevk reminded me that we'd want to use a structured header. I almost forgot they existed.

@mikewest
Copy link
Member

a) I have basically no opinion on spelling. Happy for this to be whatever makes sense to y'all.

b) If this is a distinct header, I strongly object to reusing CSP's syntax. Structured Fields exist, please use them to normalize parsing. Please do not repeat my mistakes!

@annevk
Copy link
Member

annevk commented Mar 26, 2025

Most of the headers of this kind have -Policy as suffix. (Referrer-Policy, Cross-Origin-Opener-Policy, Content-Security-Policy, etc.) I suggest we don't deviate from that.

@tomrittervg
Copy link

I don't have opinions about the naming or structure; but as far as fields go, what we are currently thinking about is the following directives and their potential values. I don't see any problem with fitting these into Structured Headers.

Headers:

  • Integrity-Policy
  • Integrity-Policy-Report-Only

Integrity Request Destinations:

  • style
  • script
  • image, object, embed (or possibly a new one to cover multiple?)
  • document (to cover the actual page)

Enforcement Type:

  • strict OR lax (not relevant to the RO header)

Integrity Source:

  • manifest OR inline OR header hashes

If it's manifest, then we need the manifest URL
If it's manifest, then we may also specify a hash of the manifest

@yoavweiss
Copy link
Author

@mozfreddyb and I just chatted through this, and made some good progress on an actual syntax proposal.

We're proposing an Integrity-Policy header which is an SF Dictionary, where each member is an inner list of tokens.

Given the dimensions @tomrittervg mentioned above, the dictionary keys would be strict/report/user for the enforcement mode, and source for the manifest source.
We’d also need an endpoints key, to define the reporting endpoints.

The tokens in the inner lists would be the relevant request destinations for the enforcement modes, and manifest, inline or header for the source. We'd haven't dug into what the hashes definitions or manifest URL would look like, but we'd be able to add more dictionary keys and values to cover them.

That means that a header would look something like:

Integrity-Policy: strict=(script style), report=(image), user=(document), source=(manifest inline), endpoints=(https://example.com/report https://megacorp.com/report)

Initially, I'm planning to only specify and implement the strict and report enforcement mode keys and the script destination, as well as the source=(inline) part.
If no source is specified, inline would be the default.

In terms of future compat, if the source key is present and inline is not defined, no enforcement will be applied in current spec/implementation. That would enable us to roll out stricter integrity requirements for newer browsers, without breaking older ones.

Other unknown keys would be ignored.

@tomrittervg
Copy link

Wasn't it really useful to have a separate -RO header for CSP? So sites could deploy one CSP and test a more restrictive one at the same time? It seems like we would want that same capability, no?

@annevk
Copy link
Member

annevk commented Mar 27, 2025

Yeah, we decided to keep the -RO convention for COOP and COEP too. If we are to revisit that here someone needs to dig up the receipts as to why deviating at this point is a good idea.

@yoavweiss
Copy link
Author

The reason we thought we could avoid RO here is that we can have separate "report" destinations vs. "strict" destinations.

If there's a preference to keep RO around, we could also go with something like:

Integrity-Policy: destinations=(script style), enforcement=(block, warn), source=(manifest inline)
Integrity-Policy-Report-Only: destinations=(image), source=(manifest inline), endpoints=(https://example.com/report https://megacorp.com/report)

@mozfreddyb
Copy link
Collaborator

If we have different enforcement levels already (strict vs. lax), then it would make sense to split on the enforcement level as their own dictionary and put them on the same axis as reporting? You could still roll out a strict policy for testing in parallel to a weaker one that is known not to break the site like so: report=(script, style,image,video etc.) strict=(script)

@tomrittervg
Copy link

The reason we thought we could avoid RO here is that we can have separate "report" destinations vs. "strict" destinations.

If there's a preference to keep RO around, we could also go with something like:

Integrity-Policy: destinations=(script style), enforcement=(block, warn), source=(manifest inline)
Integrity-Policy-Report-Only: destinations=(image), source=(manifest inline), endpoints=(https://example.com/report https://megacorp.com/report)

I... don't really like that design/syntax, I feel like the RO header is easier to understand (and allows having a different reporting URL than the enforcement one, right? I would have thought that would be really valuable but maybe not). BUT this is a personal opinion and is not a blocker to moving forward if that's what you, Freddy, and others prefer.

@yoavweiss
Copy link
Author

I feel like the RO header is easier to understand

I'm not sure what you mean here. Can you share examples?

allows having a different reporting URL than the enforcement one, right? I would have thought that would be really valuable but maybe not)

Yeah, the two header design does enable us to have separate endpoints for enforcement vs. report-only. I'm not sure what's the use case for that, but it does give us this flexibility.

@tomrittervg
Copy link

I feel like the RO header is easier to understand

I'm not sure what you mean here. Can you share examples?

My quoting the entire context instead of the first line probably made it more confusing. IIUC the following are equivalent:

Integrity-Policy: destinations=(script style), enforcement=(strict), source=(manifest), manifest-url=(https://example.com/manifests/m1), endpoints=(https://example.com/report https://megacorp.com/report)
Integrity-Policy-Report-Only: destinations=(script style image), source=(manifest), manifest-url=(https://example.com/manifests/m1), endpoints=(https://example.com/report https://megacorp.com/report)

and

Integrity-Policy: strict=(script style), report=(image), source=(manifest), manifest-url=(https://example.com/manifests/m1), endpoints=(https://example.com/report https://megacorp.com/report)

I guess the difference isn't that bad in practice. Although the advantages of a separate -RO header are (I think):

  • You can specify different endpoints. I would have guessed that having different endpoints would be valuable from a view point of 'This is broken in Production and needs to be investigated and fixed' vs 'This is development work, it's not breaking anything, we can investigate it when we have an opportunity'.
  • You can specify a different manifest URL, e.g. a testing manifest that additionally includes images, or perhaps only includes images
  • I believe we intend 'Strict' and 'Lax' enforcement is mutually exclusive, so in a singular header you need to validate that only one appears. With a separate headers, Integrity-Policy requires an enforcement key (or perhaps defaults to lax) that can take only one value.
  • In a singular header, is the 'report' set a set applied on top of the strict and lax sets? If so, then with separate headers you could deploy -RO covering only 'images' (linking to an image-only manifest) and leave the script/style in the Integrity-Policy header for enforcement.

If the headers are very similar though, it's definitely a ton of duplicated bytes (source, manifest-url, endpoints).

@annevk
Copy link
Member

annevk commented Mar 31, 2025

The reason we thought we could avoid RO here is that we can have separate "report" destinations vs. "strict" destinations.

All new headers use SFV so this isn't unique and insufficient justification in my opinion.

@mozfreddyb
Copy link
Collaborator

Originally, I just found it odd that we have an axis of violation-strictness (report, lax, strict) and split that axis into the lax/strict header value and a completely separate header.

Looking at the pros & cons listed by @tomrittervg and the fact that Report-Only headers are a thing, I'm happy to give in and follow group consensus around us establishing two headers. :)

@yoavweiss
Copy link
Author

Closed in favor of #133

@annevk annevk deleted the revive_require_sri_for branch April 15, 2025 14:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants