diff --git a/index.bs b/index.bs index 1502f61..f52cecd 100644 --- a/index.bs +++ b/index.bs @@ -32,6 +32,14 @@ spec: ABNF; urlPrefix: https://tools.ietf.org/html/rfc5234 text: VCHAR; url: appendix-B.1 text: WSP; url: appendix-B.1 +spec: CSP; urlPrefix: https://www.w3.org/TR/CSP3/ + type: dfn + text: strip url for use in reports; url: strip-url-for-use-in-reports + +spec: FETCH; urlPrefix: https://fetch.spec.whatwg.org/ + type: dfn + text: main fetch; url: main-fetch + spec: RFC7234; urlPrefix: https://tools.ietf.org/html/rfc7234 type: dfn text: Cache-Control; url: section-5.2 @@ -44,9 +52,17 @@ spec: SHA2; urlPrefix: https://csrc.nist.gov/publications/fips/fips180-4/fips-18 text: SHA-256; url: # text: SHA-384; url: # text: SHA-512; url: # + spec: RFC8288; urlPrefix: https://tools.ietf.org/html/rfc8288 type: http-header text: link + +spec: RFC9651; urlPrefix: https://tools.ietf.org/html/rfc9651 + type: dfn + text: Dictionary; url: name-dictionaries + text: inner list; url: name-inner-lists + text: token; url: name-tokens +
spec:csp3; type:grammar; text:base64-value @@ -485,6 +501,158 @@ spec:csp3; type:grammar; text:base64-value failed resource with a different one. + + ## Integrity-Policy ## {#integrity-policy-section} + The `Integrity-Policy` and `Integrity-Policy-Report-Only` HTTP headers enable a document to + enforce a policy regarding the integrity metadata requirements on all the subresources it + loads of certain destinations. + + The headers' value is a Dictionary [[RFC9651]], with every member-value being an + inner list of tokens. + + A source is a string. The only possible value for it is "`inline`". + + A destination is a string. The only possible value for it is "`script`". + + An integrity policy struct, is a struct that contains the following: + + * sources, a list of sources, initially empty. + * blocked destinations, a list of destinations, initially empty. + * endpoints, a list of strings, initially empty. + + When processing an integrity policy, with a header list |headers| + and a header name |headerName|, do the following: + + 1. Let |integrityPolicy| be a new integrity policy struct. + 1. Let |dictionary| be the result of getting a structured field value from |headers| + given |headerName| and "`dictionary`". + 1. If |dictionary|["`sources`"] does not exist or if its value + contains "`inline`", append "`inline`" to + |integrityPolicy|'s sources. + 1. If |dictionary|["`blocked-destinations`"] exists: + 1. If its value contains "`script`", + append "`script`" to |integrityPolicy|'s blocked destinations. + 1. If |dictionary|["`endpoints`"] exists: + 1. Set |integrityPolicy|'s endpoints to |dictionary|['endpoints']. + 1. Return |integrityPolicy|. + + ### Parse Integrity-Policy headers ### {#parse-integrity-policy-headers-section} + To parse Integrity-Policy headers, given a Response |response| + and a policy container |container|, do the following: + + 1. Let |headers| be |response|'s header list. + 1. If |headers| contains ``integrity-policy``, + set |container|'s integrity policy be the result of running + processing an integrity policy with the corresponding header value. + 1. If |headers| contains ``integrity-policy-report-only``, + set |container|'s report only integrity policy be the result of running + processing an integrity policy with the corresponding header value. + + ### Should request be blocked by Integrity Policy ### {#should-request-be-blocked-by-integrity-policy-section} + To determine should request be blocked by integrity policy, given a request |request|, + do the following: + + 1. Let |policyContainer| be |request|'s policy container. + 1. If |request|'s integrity metadata is not the empty string + and |request|'s mode is either "`cors`" or "`same-origin`", + return "Allowed". + 1. Let |policy| be |policyContainer|'s integrity policy. + 1. Let |reportPolicy| be |policyContainer|'s report only integrity policy. + 1. If both |policy| and |reportPolicy| are empty integrity policy structs, return "Allowed". + 1. Let |global| be |request|'s client's global object. + 1. If |global| is not a {{Window}} nor a {{WorkerGlobalScope}}, return "`Allowed`". + 1. Let |block| be a boolean, initially false. + 1. Let |reportBlock| be a boolean, initially false. + 1. If |policy|'s sources contains "`inline`" + and |policy|'s blocked destinations contains + |request|'s destination, + set |block| to true. + 1. If |policy|'s sources contains "`inline`" + and |reportPolicy|'s blocked destinations contains + |request|'s destination, + set |reportBlock| to true. + 1. If |block| is true or |reportBlock| is true, then report violation + with |request|, |block|, |reportBlock|, |policy| and |reportPolicy|. + 1. If |block| is true, then return "`Blocked`"; otherwise "`Allowed`". + + ### Report violations ### {#report-violations} + ++ [Exposed=Window] + interface IntegrityPolicyViolationReportBody : ReportBody { + [Default] object toJSON(); + readonly attribute USVString documentURL; + readonly attribute USVString blockedURL; + readonly attribute USVString destination; + readonly attribute boolean reportOnly; + }; ++ + To report violation given a Request |request|, a boolean |block|, + a boolean |reportBlock|, an integrity policy struct |policy|, + and an integrity policy struct |reportPolicy|, do the following: + + 1. Assert: |request|'s client is not null. + 1. Let |settingsObject| be |request|'s client. + 1. Let |global| be |settingsObject|'s global object. + 1. Assert: |global| is a {{Window}} or a {{WorkerGlobalScope}}. + 1. Let |url| be null. + 1. If |global| is a {{Window}}, set |url| to |global|'s associated Document's {{Document/URL}}. + 1. If |global| is a {{WorkerGlobalScope}}, set |url| to |global|'s URL. + 1. Assert: |url| is a URL. + 1. Let |documentURL| be the result of strip URL for use in reports on |url|. + 1. Let |blockedURL| be the result of strip URL for use in reports on |request|'s URL. + 1. If |block| is true, for each |endpoint| in |policy|'s endpoints: + 1. Let |body| be a new {{IntegrityPolicyViolationReportBody}}, initialized as follows: + : {{IntegrityPolicyViolationReportBody/documentURL}} + :: |documentURL| + : {{IntegrityPolicyViolationReportBody/blockedURL}} + :: |blockedURL| + : {{IntegrityPolicyViolationReportBody/destination}} + :: |request|'s destination + : {{IntegrityPolicyViolationReportBody/reportOnly}} + :: false + 2. Generate and queue a report with the following arguments: + : context + :: |settingsObject| + : type + :: "`integrity-policy-violation`" + : destination + :: |endpoint| + : data + :: |body| + 1. If |reportBlock| is true, for each |endpoint| in |reportPolicy|'s endpoints: + 1. Let |reportBody| be a new {{IntegrityPolicyViolationReportBody}}, initialized as follows: + : {{IntegrityPolicyViolationReportBody/documentURL}} + :: |documentURL| + : {{IntegrityPolicyViolationReportBody/blockedURL}} + :: |blockedURL| + : {{IntegrityPolicyViolationReportBody/destination}} + :: |request|'s destination + : {{IntegrityPolicyViolationReportBody/reportOnly}} + :: true + 2. Generate and queue a report with the following arguments: + : context + :: |settingsObject| + : type + :: "`integrity-policy-violation`" + : destination + :: |endpoint| + : data + :: |reportBody| + + ### Integration ### {#integration} + + A policy container has extra items: + + * integrity policy, an integrity policy struct. + * report only integrity policy, an integrity policy struct. + + Add an extra step to create a policy container from a fetch response before it returns, that runs + parse Integrity-Policy headers with response and result. + + Expand step 7 of main fetch to call should request be blocked by integrity policy + and return a network error if it returns "`Blocked`". # Proxies # {#proxies}