From 19c98a2acc722e4e3f6dc271e56be8f08c6a50ca Mon Sep 17 00:00:00 2001 From: Yoav Weiss Date: Fri, 6 Dec 2024 10:42:54 +0100 Subject: [PATCH] Hash reporting for scripts (#693) * Rough sketch of CSP report-hash * Spec builds * Add a type and tighten the language * Append the hash algorithm to the report * Change to a report-sha256 keyword * Improve definitions * move logic to post-request * Address more review comments * Review nits * Add an example * URL ref * typo * fix example * Fix example again * Review comments * Only apply to Window * Add destination * review comments --- index.bs | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 103 insertions(+), 7 deletions(-) diff --git a/index.bs b/index.bs index cc418b6a0d..7c2f6cbea7 100644 --- a/index.bs +++ b/index.bs @@ -22,7 +22,11 @@ Markup Shorthands: css off, markdown on At Risk: The [[#is-element-nonceable]] algorithm.
 {
@@ -182,7 +191,7 @@ spec: WebRTC; urlPrefix: https://www.w3.org/TR/webrtc/
   "REPORTING": {
     "href": "https://wicg.github.io/reporting/",
     "title": "Reporting API",
-    "authors": [ "Ilya Gregorik", "Mike West" ]
+    "authors": [ "Ilya Grigorik", "Mike West" ]
   },
   "TIMING": {
       "href": "https://owasp.org/www-pdf-archive/HackPra_Allstars-Browser_Timing_Attacks_-_Paul_Stone.pdf",
@@ -682,9 +691,10 @@ spec: WebRTC; urlPrefix: https://www.w3.org/TR/webrtc/
 
     ; Keywords:
     keyword-source = "'self'" / "'unsafe-inline'" / "'unsafe-eval'"
-                     / "'strict-dynamic'" / "'unsafe-hashes'" /
+                     / "'strict-dynamic'" / "'unsafe-hashes'"
                      / "'report-sample'" / "'unsafe-allow-redirects'"
-                     / "'wasm-unsafe-eval'"
+                     / "'wasm-unsafe-eval'" / "'report-sha256'"
+                     / "'report-sha384'" / "'report-sha512'"
 
     ISSUE: Bikeshed `unsafe-allow-redirects`.
 
@@ -1089,6 +1099,46 @@ spec: WebRTC; urlPrefix: https://www.w3.org/TR/webrtc/
 
   4.  Return |result|.
 
+  

Potentially report hash

+ + Given a [=response=] |response|, a [=/request=] |request|, a [=directive=] |directive| and a + [=content security policy object=] |policy|, run the following steps: + + 1. Let |algorithm| be the empty [=string=]. + 1. If |directive|'s value contains the + expression "`'report-sha256'`", set |algorithm| to "sha256". + 1. If |directive|'s value contains the + expression "`'report-sha384'`", set |algorithm| to "sha384". + 1. If |directive|'s value contains the + expression "`'report-sha512'`", set |algorithm| to "sha512". + 1. If |algorithm| is the empty [=string=], return. + 1. Let |hash| be the empty [=string=]. + 1. If |response| is [=CORS-same-origin=], then: + 1. Let |hash list| be a [=list=] of [=strings=], initially empty. + 1. [=list/Append=] |algorithm| to |hash list|. + 1. [=list/Append=] the result of [=applying algorithm to bytes=] on |response|'s + [=response/body=] and |algorithm| to |hash list|. + 1. Let |hash| be the result of [=concatenating=] |hash list| with U+002D (-). + 1. Let |global| be the |request|'s [=request/client=]'s [=/global object=]. + 1. If |global| is not a {{Window}}, return. + 1. Let |stripped document URL| to be the result of executing [[#strip-url-for-use-in-reports]] + on |global|'s [=document=]'s [=Document/URL=]. + 1. If |policy|'s [=directive set=] does not contain a [=directive=] named "report-to", return. + 1. Let |report-to directive| be a [=directive=] named "report-to" from |policy|'s [=directive + set=]. + 1. Let |body| be a [=csp hash report body=] with |stripped document URL| as its [=documentURL=], + |request|'s URL as its [=subresourceURL=], |hash| as its [=hash=], |request|'s + [=request/destination=] as its [=csp hash report body/destination=], and "subresource" as its + [=csp hash report body/type=]. + 1. [=Generate and queue a report=] with the following arguments: + : context + :: settings object + : type + :: "csp-hash" + : destination + :: |report-to directive|'s [=directive/value=]. + : data + :: |body|

Integration with HTML @@ -1593,6 +1643,50 @@ this algorithm returns normally if compilation is allowed, and throws a };

+ When a directive that impacts [=script-like=] [=request/destinations=] has a `report-sha256`, + `report-sha384` or `report-sha512` value, and a [=/request=] with a [=script-like=] + [=request/destination=] is fetched, a csp hash report will be generated and + sent out to a reporting endpoint associated with the policy. + +

csp hash reports have the report type "csp-hash".

+ +

csp hash reports are not visible to ReportingObservers. + +

A csp hash report body is a [=struct=] with the following fields: + documentURL, + subresourceURL, + hash, + destination, + type. + +

+ When a document's response contains the headers: +```http +Reporting-Endpoints: hashes-endpoint="https://example.com/reports" +Content-Security-Policy: script-src 'self' 'report-sha256'; report-to hashes-endpoint +``` + and the document loads the script "main.js", a report similar to the following one will be sent: +```http +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" + } +}] +``` +

Violation DOM Events

@@ -3702,17 +3796,19 @@ this algorithm returns normally if compilation is allowed, and throws a 1. If |request|'s destination is script-like: + 1. Call [=potentially report hash=] with |response|, |request|, |directive| and |policy|. + 1. If the result of executing [[#match-nonce-to-source-list]] on |request|'s cryptographic nonce metadata and this directive's value is "`Matches`", return "`Allowed`". - 2. If the result of executing + 1. If the result of executing [[#match-integrity-metadata-to-source-list]] on |request|'s integrity metadata and this directive's value is "`Matches`", return "`Allowed`". - 3. If |directive|'s value contains + 1. If |directive|'s value contains "`'strict-dynamic'`": 1. If |request|'s parser metadata is not @@ -3720,7 +3816,7 @@ this algorithm returns normally if compilation is allowed, and throws a Otherwise, return "`Blocked`". - 4. If the result of executing [[#match-response-to-source-list]] on + 1. If the result of executing [[#match-response-to-source-list]] on |response|, |request|, |directive|'s value, and |policy|, is "`Does Not Match`", return "`Blocked`".