Skip to content
Please note that GitHub no longer supports Internet Explorer.

We recommend upgrading to the latest Microsoft Edge, Google Chrome, or Firefox.

Learn more
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

Apply integrity checks to inline script and style blocks. #86

Open
wants to merge 1 commit into
base: master
from

Conversation

@mikewest
Copy link
Member

mikewest commented Dec 16, 2019

Closes #44.

If this looks like a reasonable approach, I'll put up patches to HTML and CSP as well, and try to find someone to fix Chromium's implementation.

/cc @annevk @mozfreddyb @devd @fmarier @metromoxie


Preview | Diff

@mozfreddyb

This comment has been minimized.

Copy link
Contributor

mozfreddyb commented Dec 19, 2019

Makes sense.

IMHO this should have an informal note / redirection that CSP modified the allow behavior depending on policy.

Did you file an issue in CSP to write down the blocking of correct but disallowed (absent from policy) metadata?

@mikewest

This comment has been minimized.

Copy link
Member Author

mikewest commented Dec 19, 2019

IMHO this should have an informal note / redirection that CSP modified the allow behavior depending on policy.

CSP didn't modify SRI's behavior at all, AFAIR. It layers on top of SRI, imposing some additional restrictions prior to SRI's enforcement. (Or is that what you mean?)

Did you file an issue in CSP to write down the blocking of correct but disallowed (absent from policy) metadata?

As currently defined, it fails the bits in step 1.3 of https://w3c.github.io/webappsec-csp/#script-pre-request, which happens during Fetch, prior to SRI enforcement. So we'd expect a CSP error failing the request rather than an SRI error. I'm pretty sure that's what Chrome's console reports, and that we fire a securitypolicyviolation event.

Is there more that CSP should do here?

@mozfreddyb

This comment has been minimized.

Copy link
Contributor

mozfreddyb commented Dec 20, 2019

IMHO this should have an informal note / redirection that CSP modified the allow behavior depending on policy.

CSP didn't modify SRI's behavior at all, AFAIR. It layers on top of SRI, imposing some additional restrictions prior to SRI's enforcement. (Or is that what you mean?)

Yes. SRI will allow, but the resource matching the integrity attribute still has to pass a CSP (if existant). Maybe that's not noteworthy in itself. But what's layered on top of what isn't immediately obvious to developers, is it? I'm not sure how to make the order in which things are processed (layered) more explicit.

Did you file an issue in CSP to write down the blocking of correct but disallowed (absent from policy) metadata?

As currently defined, it fails the bits in step 1.3 of https://w3c.github.io/webappsec-csp/#script-pre-request, which happens during Fetch, prior to SRI enforcement. So we'd expect a CSP error failing the request rather than an SRI error. I'm pretty sure that's what Chrome's console reports, and that we fire a securitypolicyviolation event.

Is there more that CSP should do here?

No, that makes sense. Nevermind then.

Copy link
Member

annevk left a comment

What's the use case for this feature?

this algorithm after the CSP check in step 13.

ISSUE: This needs to be wired up to HTML's [=update a style block=] algorithm by inserting a call
to this algorithm after the CSP check in step 5.

This comment has been minimized.

Copy link
@annevk

annevk Jan 4, 2020

Member

Well, you'll also need to define it as a valid attribute for the style element if this is actually a thing we want to encourage.

This comment has been minimized.

Copy link
@mikewest

mikewest Jan 7, 2020

Author Member

You're right. I thought we'd done that already, but of course it's only valid for <link>.

jonathanKingston pushed a commit to jonathanKingston/webappsec-subresource-integrity that referenced this pull request Jan 4, 2020
@devd devd closed this in #90 Jan 7, 2020
devd added a commit that referenced this pull request Jan 7, 2020
@annevk

This comment has been minimized.

Copy link
Member

annevk commented Jan 7, 2020

This was not fixed by that PR.

@annevk annevk reopened this Jan 7, 2020
@mikewest

This comment has been minimized.

Copy link
Member Author

mikewest commented Jan 7, 2020

What's the use case for this feature?

Inline integrity information can provide some defense in depth against injection attacks (as an injection into a script block wouldn't automatically mean code execution if the block had an integrity attribute; you'd need another injection point). This protection can be enhanced via CSP's existing support for listing the set of hashes which are allowed to execute on a given page, but it seems valuable in itself.

Adding this support might also allow us to more cleanly layer CSP's behavior on top of SRI for inline blocks, just as we have for externalized scripts. That isn't user-facing at all, but might clean up the spec a bit.

There was some discussion of/agreement on this in https://www.w3.org/2016/05/16-webappsec-minutes.html#item02, and on and off since then.

@annevk

This comment has been minimized.

Copy link
Member

annevk commented Jan 7, 2020

And the injection point would filter HTML somehow and only allow injection of content already covered by the integrity attribute value? Especially that last part seemed rather curious to me, but maybe it's valid in certain complicated setups.

@mikewest

This comment has been minimized.

Copy link
Member Author

mikewest commented Jan 7, 2020

And the injection point would filter HTML somehow and only allow injection of content already covered by the integrity attribute value? Especially that last part seemed rather curious to me, but maybe it's valid in certain complicated setups.

I admit that the use case from a security perspective is somewhat contrived (@arturjanc might have actual data here from Google's products). It assumes an injection point like let name = "{{user data goes here}}";, and that developers are going to be better about filtering </script><script> from user input than "; alert(1) //.

Apple had performance reasons in the minutes linked above (that are unfortunately a bit difficult to tease out of that record), and I think there are spec-sanity reasons to do so (I find it somewhat confusing that CSP can allow inline script by hash, but that it does so completely independently of SRI).

Given that Chrome's shipping implementation is already halfway here, I'd prefer to simply make that work the way outlined here than remove it.

@annevk

This comment has been minimized.

Copy link
Member

annevk commented Jan 7, 2020

The thing I wanted to point is that the integrity value would have to match the eventual {{user data goes here}} value, right? At which point you'd likely compute the integrity value based on that, at which point it's unsafe.

@mikewest

This comment has been minimized.

Copy link
Member Author

mikewest commented Jan 7, 2020

Yes. If a developer is parsing the data on the server and generating an integrity attribute on the fly, then all bets are off.

An alternative way of looking at that is that calculating a hash to match the eventual {{user data goes here}} would be hard, and tagging script blocks with integrity information would make it difficult for future developers to develop insecure practices. Security through annoyance. :)

@annevk

This comment has been minimized.

Copy link
Member

annevk commented Jan 8, 2020

For my understanding, the expected usage pattern is that {{user data goes here}} is a finite number of different strings and you'd fill the integrity attribute on the surrounding script element with an equal number of hashes?

@arturjanc

This comment has been minimized.

Copy link

arturjanc commented Jan 25, 2020

I'm likely missing some context here, but I'm also not entirely clear on how this could be used as an injection defense:

  • If an inline script has no variable/interpolated parts then developers could calculate and add the integrity attribute, but it would be a no-op because no injection is possible in this case.
  • If an inline script has variable parts, then in order to set the correct integrity attribute the server would have to dynamically calculate its value after interpolation, which -- if there is an injection -- would include the attacker's injected string, allowing their injection to execute.

The way I see this potentially working is if there was an integrity attribute that covered the parse tree of the script, but not its full contents. Then, if I have something like <script>var foo = "${foo}" </script> in my HTML templates, I could calculate the hash of the structure of the script ahead of time and expect that the hash remains the same regardless of the contents of $foo. (And if there is an injection, the structure of the script would change and then the signature wouldn't match.)

Alas, that's not really what SRI does... :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants
You can’t perform that action at this time.