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

Hash reporting for scripts #693

Merged
merged 18 commits into from
Dec 6, 2024
Merged

Hash reporting for scripts #693

merged 18 commits into from
Dec 6, 2024

Conversation

yoavweiss
Copy link
Contributor

@yoavweiss yoavweiss commented Nov 25, 2024

TL;DR - As discussed at yoavweiss/subresource-reporting#4 and on the WG call, this PR adds a new CSP keyword "report-hash", which triggers a new reporting type "csp-hash-report".

"report-hash" CSP keyword

Complex web applications often need to keep tabs of the subresources that they download, for security purposes.

In particular, upcoming industry standards and best practices (e.g. PCI-DSS v4 - context) require that web applications keep an inventory of all the scripts they download and execute.

This document proposes a new CSP keyword,
that would enable web developers to create and maintain such inventories in a secure manner.

Problem

Web developers load many different script assets to their sites, and those scripts can then load other assets.
Some of those assets are versioned and their content's integrity can be validated using Subresource Integrity or using Content Security Policy hashes. But those are hard to deploy when there's no current way to collect the hashes of all the scripts running on your site.

For dynamic assets, ensuring their integrity is even harder, as they are ever-green scripts that can be updated by their provider at any moment.
The web platform has no means of validating their integrity, neither in reporting nor in enforcement mode.

At the same time, upcoming security standards require web developers to maintain an up to date inventory of all scripts that execute in the context of their payment page documents,
and have a mechanism to validate their integrity.

In the absence of better mechanisms, developers and merchants will need to settle for lower fidelity security guarantees — e.g. offline hash verification through crawling.
Such mechanisms leave a lot to be desired in terms of their coverage, while at the same time add a lot of implementation complexity. We need a better path.

Proposal

A new CSP keyword could be used to send reports of all scripts executed in the context of the relevant document,
including their URLs and their hashes (for CORS-enabled or same-origin resources).

That would enable developers to set up endpoints that collect these reports, and process them to maintain an up to date and accurate
inventory of scripts and their integrity for relevant pages.

Flow

Developers can set the following headers on their navigation responses:

Reporting-Endpoints: hashes-endpoint="https://example.com/reports"
Content-Security-Policy: script-src 'report-sha256'; report-to hashes-endpoint

Each loaded and executed script would then generate and queue a report with the resource's URL and, if the response is CORS-same-origin, its integrity digest.

That would eventually send a report that looks something like the following:

POST /reports HTTP/1.1
Host: example.com
...
Content-Type: application/reports+json

[{
  "type": "csp-hash-report",
  "age": 12,
  "url": "https://example.com/",
  "user_agent": "Mozilla/5.0 (X11; Linux i686; rv:132.0) Gecko/20100101 Firefox/132.0",
  "body": {
    "document_url": "https://example.com/",
    "subresource_url": "https://example.com/main.js",
    "hash": "sha256-badbeef",
    "type": "subresource",
    "destination": "script"
  }
}]

If multiple CSP hash reports would be queued before reports are sent (at a user agent defined time), the user agent
will serialize the entire list of reports and send them in a single report.

The "type" attribute of the report provides room for future extensibility, where we could add hashes for inline scripts, evals, inline event handlers or javascript: URLs.

These reports would have no visibility to ReportingObserver, as there are no current use cases for it.

We need a new report type as these reports are different in nature from violation reports, and they are triggered at a very different point of the request's lifecycle (at least for subresources).

Considered alternatives

Resource-timing

The Resource Timing API can be used to gather up all the URLs of script resources in a document today.

It could also be extended to provide an integrity hash for CORS-enabled or same-origin resources.

However, that is not ideal because:

  • Currently browsers don’t calculate these hashes, so starting to calculate them for all scripts in all documents could introduce some overhead.
    Therefore, adding hashes to resource timing may require some opt-in mechanism.
  • Malicious scripts on the site can tamper with Resource Timing data and obfuscate their presence on the page (by e.g. reporting known-good hashes instead of their own).

Service workers

A Service Worker can tee the response streams for CORS-enabled scripts, calculate their hashes and report them to the server.

There are a few fundemental issues with that approach though:

  • A Service Worker will not cover the first time a site loads.
  • Service Worker can be uninstalled by an attacker.
  • A Service Worker can add overhead (even if future optimizations can reduce that).

A dedicated Subresource Reporting feature

This is something considered in https://github.com/yoavweiss/subresource-reporting, but following discussions on yoavweiss/subresource-reporting#4 and on the WG call, we decided that integrating the feature as part of CSP would enable developers to better take advantage of it in order to deploy hash-based CSP restrictions.

Security & Privacy considerations

This proposal doesn't expose new information when it comes to URLs - URLs are already exposed in Resource Timing and Service Workers,
and developers can use the initiatorType or Request.destination respectively to get that information, albeit in less-secure and more complex ways.

Resource hashes are not currently exposed, but we plan to expose them only for CORS-enabled or same-origin resources, that the document can already fully read.
That means that developers can already fetch those resources and calculate their hashes on their own. (again, with added complexity)

Open questions

  • Would the CORS requirement prevent popular scripts from having their hashes collected?
    • If so, do we need a complementary Document-Policy that enforces CORS for all subresources?

Preview | Diff

@yoavweiss yoavweiss marked this pull request as draft November 25, 2024 21:45
index.bs Outdated Show resolved Hide resolved
index.bs Outdated Show resolved Hide resolved
index.bs Outdated Show resolved Hide resolved
@ddworken
Copy link

Thank you for writing this up Yoav! From a Google perspective, I want to say that we're highly supportive of integrating this into CSP. By putting this into CSP, it should be possible to also use this to aid in adoption of hash-based CSPs, enabling this proposal to offer significant defenses against both classical injection attacks and supply-chain attacks.

@annevk
Copy link
Member

annevk commented Nov 27, 2024

How do we imagine migration away from sha-256 to work?

@yoavweiss
Copy link
Contributor Author

How do we imagine migration away from sha-256 to work?

Fair point. I'll add the algorithm to the reported hash

@annevk
Copy link
Member

annevk commented Nov 27, 2024

I'm not sure that's sufficient. As a user agent that would give me a path towards emitting sha-512 instead, but that would likely break all existing consumers, no? Perhaps the acceptable algorithms have to be listed in the CSP so it's somewhat driven by the consumer of the reports?

@yoavweiss
Copy link
Contributor Author

Perhaps the acceptable algorithms have to be listed in the CSP so it's somewhat driven by the consumer of the reports?

Would that work as a directive value as @ddworken suggested?
e.g. Content-Security-Policy: script-src 'none' 'report-hash-sha-256'; report-to hashes-endpoint or somesuch?

@annevk
Copy link
Member

annevk commented Nov 27, 2024

Model-wise I think you want the same thing as with integrity. Where you can give a couple of acceptable values and the user agent picks the best one it supports. Syntax-wise I'm probably not the best person to say how that should be done in CSP.

@yoavweiss
Copy link
Contributor Author

Talking to @antosart, something like script-src 'report-hash-sha256' 'report-hash-sha512' would probably work, and will enable us to expand the list of possible hashes and the list of resources to which this applies (e.g. styles) in the future if the use cases arise.

@annevk
Copy link
Member

annevk commented Nov 27, 2024

Will script-src 'report-hash-blah' 'report-hash-sha256' ignore unknown values and end up with sha-256? If so, seems good.

@yoavweiss
Copy link
Contributor Author

Will script-src 'report-hash-blah' 'report-hash-sha256' ignore unknown values and end up with sha-256?

Yup!

index.bs Outdated Show resolved Hide resolved
index.bs Show resolved Hide resolved
index.bs Show resolved Hide resolved
index.bs Outdated Show resolved Hide resolved
@antosart
Copy link
Member

antosart commented Dec 6, 2024

Can you update the description to reflect that we don't have a new directive but rather keywords?

@yoavweiss
Copy link
Contributor Author

Can you update the description to reflect that we don't have a new directive but rather keywords?

Done!

@yoavweiss yoavweiss merged commit 19c98a2 into w3c:main Dec 6, 2024
2 checks passed
@yoavweiss yoavweiss deleted the hash_reporting branch December 6, 2024 09:43
github-actions bot added a commit that referenced this pull request Dec 6, 2024
SHA: 19c98a2
Reason: push, by yoavweiss

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@mikewest
Copy link
Member

mikewest commented Dec 6, 2024

I don't think we should have merged this without tests or any implementation. That's pretty contrary to the goal we discussed at TPAC of shifting into a better-maintained model for the spec.

Do you have tests written elsewhere? Is there a prototype implementation? If not, I'd prefer that we revert this, and only land it in the specification when it's not entirely aspirational. :)

@yoavweiss
Copy link
Contributor Author

Apologies if I was too hasty on the merge button..

Tests and an implementation are at https://chromium-review.googlesource.com/c/chromium/src/+/6038298, and the tests are bound to get upstreamed shortly.

@mikewest
Copy link
Member

mikewest commented Dec 6, 2024

Excellent, glad to see you're on top of it. If those land upstream today, brilliant! If something happens to kick them out of the CQ or they run into upstream issues, please pull this back out until they land.

Thanks!

aarongable pushed a commit to chromium/chromium that referenced this pull request Dec 6, 2024
Implement hash reporting for scripts as part of CSP.

PR: w3c/webappsec-csp#693

Change-Id: Ie8d97d6094ca7601d84258cc5e1bca540eb49b39
Bug: 377830102
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6038298
Reviewed-by: Antonio Sartori <[email protected]>
Commit-Queue: Yoav Weiss (@Shopify) <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1392854}
@yoavweiss
Copy link
Contributor Author

Will do!!

chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this pull request Dec 6, 2024
Implement hash reporting for scripts as part of CSP.

PR: w3c/webappsec-csp#693

Change-Id: Ie8d97d6094ca7601d84258cc5e1bca540eb49b39
Bug: 377830102
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6038298
Reviewed-by: Antonio Sartori <[email protected]>
Commit-Queue: Yoav Weiss (@Shopify) <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1392854}
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this pull request Dec 6, 2024
Implement hash reporting for scripts as part of CSP.

PR: w3c/webappsec-csp#693

Change-Id: Ie8d97d6094ca7601d84258cc5e1bca540eb49b39
Bug: 377830102
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6038298
Reviewed-by: Antonio Sartori <[email protected]>
Commit-Queue: Yoav Weiss (@Shopify) <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1392854}
@yoavweiss
Copy link
Contributor Author

And the tests are merged upstream!

@mikewest
Copy link
Member

mikewest commented Dec 7, 2024

Thanks for following up!

@dveditz
Copy link
Member

dveditz commented Dec 10, 2024

How are we going to get to an agreed "CSP 3" if we're still actively merging in new features no one has discussed or agreed to yet?!

@yoavweiss
Copy link
Contributor Author

This was discussed at the WG meeting (and the use case was discussed at TPAC before that).

Therefore, I thought we have agreement on this direction. Apologies if that's not the case.

What's the best path forward? Is there a branch for "beyond CSP 3" features?

moz-v2v-gh pushed a commit to mozilla/gecko-dev that referenced this pull request Dec 11, 2024
…estonly

Automatic update from web-platform-tests
CSP report-hash keyword for scripts

Implement hash reporting for scripts as part of CSP.

PR: w3c/webappsec-csp#693

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

--

wpt-commits: 22b20cf0eb577a7df17f7105e47e2b1b818d07b3
wpt-pr: 49566
i3roly pushed a commit to i3roly/firefox-dynasty that referenced this pull request Dec 12, 2024
…estonly

Automatic update from web-platform-tests
CSP report-hash keyword for scripts

Implement hash reporting for scripts as part of CSP.

PR: w3c/webappsec-csp#693

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

--

wpt-commits: 22b20cf0eb577a7df17f7105e47e2b1b818d07b3
wpt-pr: 49566
gecko-dev-updater pushed a commit to marco-c/gecko-dev-wordified-and-comments-removed that referenced this pull request Dec 13, 2024
…estonly

Automatic update from web-platform-tests
CSP report-hash keyword for scripts

Implement hash reporting for scripts as part of CSP.

PR: w3c/webappsec-csp#693

Change-Id: Ie8d97d6094ca7601d84258cc5e1bca540eb49b39
Bug: 377830102
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6038298
Reviewed-by: Antonio Sartori <antoniosartorichromium.org>
Commit-Queue: Yoav Weiss (Shopify) <yoavweisschromium.org>
Cr-Commit-Position: refs/heads/main{#1392854}

--

wpt-commits: 22b20cf0eb577a7df17f7105e47e2b1b818d07b3
wpt-pr: 49566

UltraBlame original commit: 10f6fe317a85bc855c0ebb34f34a75bee102ddf0
gecko-dev-updater pushed a commit to marco-c/gecko-dev-comments-removed that referenced this pull request Dec 13, 2024
…estonly

Automatic update from web-platform-tests
CSP report-hash keyword for scripts

Implement hash reporting for scripts as part of CSP.

PR: w3c/webappsec-csp#693

Change-Id: Ie8d97d6094ca7601d84258cc5e1bca540eb49b39
Bug: 377830102
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6038298
Reviewed-by: Antonio Sartori <antoniosartorichromium.org>
Commit-Queue: Yoav Weiss (Shopify) <yoavweisschromium.org>
Cr-Commit-Position: refs/heads/main{#1392854}

--

wpt-commits: 22b20cf0eb577a7df17f7105e47e2b1b818d07b3
wpt-pr: 49566

UltraBlame original commit: 10f6fe317a85bc855c0ebb34f34a75bee102ddf0
gecko-dev-updater pushed a commit to marco-c/gecko-dev-wordified that referenced this pull request Dec 13, 2024
…estonly

Automatic update from web-platform-tests
CSP report-hash keyword for scripts

Implement hash reporting for scripts as part of CSP.

PR: w3c/webappsec-csp#693

Change-Id: Ie8d97d6094ca7601d84258cc5e1bca540eb49b39
Bug: 377830102
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6038298
Reviewed-by: Antonio Sartori <antoniosartorichromium.org>
Commit-Queue: Yoav Weiss (Shopify) <yoavweisschromium.org>
Cr-Commit-Position: refs/heads/main{#1392854}

--

wpt-commits: 22b20cf0eb577a7df17f7105e47e2b1b818d07b3
wpt-pr: 49566

UltraBlame original commit: 10f6fe317a85bc855c0ebb34f34a75bee102ddf0
@sysrqb
Copy link

sysrqb commented Jan 6, 2025

This change is confusing to me. As a site, receiving a stream of hashes tells me nothing about the actual integrity of the associated scripts. Creating an inventory of assets doesn't seem valuable to clients, by itself.

Is the expectation that someone will investigate why the hash of a script changed? Using this reporting mechanism for automatically collecting script hashes and automatically updating relevant CSP directives without review would seemingly render SRI meaningless for supply-chain attacks. Maybe this is already true in reality, where most sites using SRI blindly update the hashes?

What is the actual guidance on how this should be used?

@yoavweiss
Copy link
Contributor Author

Is the expectation that someone will investigate why the hash of a script changed?

Yes. The expectation is that (some) sites will maintain an inventory of all of their scripts and their expected hashes:

  • For versioned first-party scripts, the expected hashes can be produced at e.g. build time
  • For versioned third-party scripts, the expected hashes can be produced by the third party's build process (and provided to consumers out-of-band) or through an audit.
  • For evergreen third party scripts, the expected hashes can be produced by the third party's build process (and provided to consumers out-of-band).

Using this reporting mechanism for automatically collecting script hashes and automatically updating relevant CSP directives without review would seemingly render SRI meaningless for supply-chain attacks

That's definitely not how this is intended to be used.

Maybe this is already true in reality, where most sites using SRI blindly update the hashes?

I sure hope not, but it's true that folks don't need this feature to shoot themselves in the foot that way.

@yoavweiss yoavweiss mentioned this pull request Jan 8, 2025
1 task
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.

9 participants