2 | Title: Subresource Integrity 3 | Status: ED 4 | ED: https://w3c.github.io/webappsec-subresource-integrity/ 5 | TR: http://www.w3.org/TR/SRI/ 6 | Shortname: SRI 7 | Level: 2 8 | Editor: Frederik Braun 68466, Mozilla, https://frederik-braun.com, fbraun@mozilla.com 9 | Former Editor: Devdatta Akhawe, Dropbox Inc., http://devd.me, dev.akhawe@gmail.com 10 | Former Editor: François Marier, Mozilla, https://fmarier.org, francois@mozilla.com 11 | Former Editor: Joel Weinberger, Google Inc., https://joelweinberger.us, jww@google.com 12 | Abstract: 13 | This specification defines a mechanism by which user agents may verify that a 14 | fetched resource has been delivered without unexpected manipulation. 15 | Group: webappsec 16 | Repository: w3c/webappsec-subresource-integrity 17 | Indent: 2 18 | Version History: https://github.com/w3c/webappsec-subresource-integrity/commits/gh-pages 19 | WPT Path Prefix: /subresource-integrity/ 20 | WPT Display: closed 21 | 22 | Markup Shorthands: css off, markdown on, http on 23 | Ignored Vars: src, resource, val 24 |25 | 26 |
27 | spec: ABNF; urlPrefix: https://tools.ietf.org/html/rfc5234 28 | type: dfn 29 | text: VCHAR; url: appendix-B.1 30 | text: WSP; url: appendix-B.1 31 | type: grammar 32 | text: VCHAR; url: appendix-B.1 33 | text: WSP; url: appendix-B.1 34 | 35 | spec: FETCH; urlPrefix: https://fetch.spec.whatwg.org/ 36 | type: dfn 37 | text: main fetch; url: main-fetch 38 | 39 | spec: RFC7234; urlPrefix: https://tools.ietf.org/html/rfc7234 40 | type: dfn 41 | text: Cache-Control; url: section-5.2 42 | text: no-transform; url: section-5.2.1.6 43 | 44 | spec: SHA2; urlPrefix: https://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf 45 | type: dfn 46 | text: SHA-1; url: # 47 | text: SHA-2; url: # 48 | text: SHA-256; url: # 49 | text: SHA-384; url: # 50 | text: SHA-512; url: # 51 | 52 | spec: RFC8288; urlPrefix: https://tools.ietf.org/html/rfc8288 53 | type: http-header 54 | text: link 55 | 56 | spec: RFC9651; urlPrefix: https://tools.ietf.org/html/rfc9651 57 | type: dfn 58 | text: Dictionary; url: name-dictionaries 59 | text: inner list; url: name-inner-lists 60 | text: token; url: name-tokens 61 | 62 |63 |
64 | spec:csp3; type:grammar; text:base64-value 65 |66 | 67 |
68 | { 69 | "SHA2": { 70 | "href": "http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf", 71 | "title": "FIPS PUB 180-4, Secure Hash Standard" 72 | } 73 | } 74 |75 | 76 | 77 | 78 | # Introduction # {#intro} 79 | 80 | Sites and applications on the web are rarely composed of resources from 81 | only a single origin. For example, authors pull scripts and styles from a 82 | wide variety of services and content delivery networks, and must trust 83 | that the delivered representation is, in fact, what they expected to 84 | load. If an attacker can trick a user into downloading content from 85 | a hostile server (via DNS [[RFC1035]] poisoning, or other such means), the author has 86 | no recourse. Likewise, an attacker who can replace the file on the Content 87 | Delivery Network (CDN) server has the ability to inject arbitrary content. 88 | 89 | Delivering resources over a secure channel mitigates some of this risk: with 90 | TLS [[TLS]], HSTS [[RFC6797]], and pinned public keys 91 | [[RFC7469]], a user agent can be fairly certain 92 | that it is indeed speaking with the server it believes it's talking to. These 93 | mechanisms, however, authenticate only the server, not the content. An 94 | attacker (or administrator) with access to the server can manipulate content with 95 | impunity. Ideally, authors would not only be able to pin the keys of a 96 | server, but also pin the content, ensuring that an exact representation of 97 | a resource, and only that representation, loads and executes. 98 | 99 | This document specifies such a validation scheme, extending two HTML elements 100 | with an `integrity` attribute that contains a cryptographic hash 101 | of the representation of the resource the author expects to load. For instance, 102 | an author may wish to load some framework from a shared server rather than hosting it 103 | on their own origin. Specifying that the expected SHA-384 hash of 104 | `https://example.com/example-framework.js` 105 | is `Li9vy3DqF8tnTXuiaAJuML3ky+er10rcgNR/VqsVpcw+ThHmYcwiB1pbOxEbzJr7` means 106 | that the user agent can verify that the data it loads from that URL matches 107 | that expected hash before executing the JavaScript it contains. This 108 | integrity verification significantly reduces the risk that an attacker can 109 | substitute malicious content. 110 | 111 | This example can be communicated to a user agent by adding the hash to a 112 | `script` element, like so: 113 | 114 |
461 | integrity-metadata = *WSP hash-with-options *(1*WSP hash-with-options ) *WSP / *WSP 462 | hash-with-options = hash-expression *("?" option-expression) 463 | option-expression = *VCHAR 464 | hash-expression = hash-algorithm "-" base64-value 465 |466 | 467 | `option-expression`s are associated on a per `hash-expression` basis and are 468 | applied only to the `hash-expression` that immediately precedes it. 469 | 470 | In order for user agents to remain fully forwards compatible with future 471 | options, the user agent MUST ignore all unrecognized `option-expression`s. 472 | 473 | Note: Note that while the `option-expression` has been reserved in the syntax, 474 | no options have been defined. It is likely that a future version of the spec 475 | will define a more specific syntax for options, so it is defined here as broadly 476 | as possible. 477 | 478 | ## The `integrity` link processing option ## {#the-integrity-link-processing-option} 479 | 480 | Integrity metadata can also be specified for [:link:] HTTP response headers 481 | as an `integrity` link parameter which MUST be specified using the same 482 | `integrity-metadata` grammar that applies to `integrity` attributes 483 | on elements. For example: 484 | 485 | ```http 486 | Link: ; rel=preload; as=style; crossorigin="anonymous"; integrity="sha256-[digest goes here]" 487 | ``` 488 | 489 | 490 | ## Handling integrity violations ## {#handling-integrity-violations} 491 | 492 | The user agent will refuse to render or execute responses that fail an integrity 493 | check, instead returning a network error as defined in Fetch [[!Fetch]]. 494 | 495 | Note: On a failed integrity check, an `error` event is fired. Developers 496 | wishing to provide a canonical fallback resource (e.g., a resource not served 497 | from a CDN, perhaps from a secondary, trusted, but slower source) can catch this 498 | `error` event and provide an appropriate handler to replace the 499 | failed resource with a different one. 500 | 501 | 502 | 503 | ## Integrity-Policy ## {#integrity-policy-section} 504 | The `Integrity-Policy` and `Integrity-Policy-Report-Only` HTTP headers enable a document to 505 | enforce a policy regarding the integrity metadata requirements on all the subresources it 506 | loads of certain destinations. 507 | 508 | The headers' value is a Dictionary [[RFC9651]], with every member-value being an 509 | inner list of tokens. 510 | 511 | A source is a string. The only possible value for it is "`inline`". 512 | 513 | A destination is a string. The only possible value for it is "`script`". 514 | 515 | An integrity policy, is a struct that contains the following: 516 | 517 | * sources, a list of sources, initially empty. 518 | * blocked destinations, a list of destinations, initially empty. 519 | * endpoints, a list of strings, initially empty. 520 | 521 | When processing an integrity policy, with a header list |headers| 522 | and a header name |headerName|, do the following: 523 | 524 | 1. Let |integrityPolicy| be a new integrity policy. 525 | 1. Let |dictionary| be the result of getting a structured field value from |headers| 526 | given |headerName| and "`dictionary`". 527 | 1. If |dictionary|["`sources`"] does not exist or if its value 528 | contains "`inline`", append "`inline`" to 529 | |integrityPolicy|'s sources. 530 | 1. If |dictionary|["`blocked-destinations`"] exists: 531 | 1. If its value contains "`script`", 532 | append "`script`" to |integrityPolicy|'s blocked destinations. 533 | 1. If |dictionary|["`endpoints`"] exists: 534 | 1. Set |integrityPolicy|'s endpoints to |dictionary|['endpoints']. 535 | 1. Return |integrityPolicy|. 536 | 537 | ### Parse Integrity-Policy headers ### {#parse-integrity-policy-headers-section} 538 | To parse Integrity-Policy headers, given a Response |response| 539 | and a policy container |container|, do the following: 540 | 541 | 1. Let |headers| be |response|'s header list. 542 | 1. If |headers| contains ``integrity-policy``, 543 | set |container|'s integrity policy be the result of running 544 | processing an integrity policy with the corresponding header value. 545 | 1. If |headers| contains ``integrity-policy-report-only``, 546 | set |container|'s report only integrity policy be the result of running 547 | processing an integrity policy with the corresponding header value. 548 | 549 | ### Should request be blocked by Integrity Policy ### {#should-request-be-blocked-by-integrity-policy-section} 550 | To determine should request be blocked by integrity policy, given a request |request|, 551 | do the following: 552 | 553 | 1. Let |policyContainer| be |request|'s policy container. 554 | 1. Let |parsedMetadata| be the result of calling parse metadata with 555 | |request|'s integrity metadata. 556 | 1. If |parsedMetadata| is not the empty set and 557 | |request|'s mode is either "`cors`" or "`same-origin`", 558 | return "Allowed". 559 | 1. If |request|'s url is local, 560 | return "Allowed". 561 | 1. Let |policy| be |policyContainer|'s integrity policy. 562 | 1. Let |reportPolicy| be |policyContainer|'s report only integrity policy. 563 | 1. If both |policy| and |reportPolicy| are empty integrity policys, return "Allowed". 564 | 1. Let |global| be |request|'s client's global object. 565 | 1. If |global| is not a {{Window}} nor a {{WorkerGlobalScope}}, return "`Allowed`". 566 | 1. Let |block| be a boolean, initially false. 567 | 1. Let |reportBlock| be a boolean, initially false. 568 | 1. If |policy|'s sources contains "`inline`" 569 | and |policy|'s blocked destinations contains 570 | |request|'s destination, 571 | set |block| to true. 572 | 1. If |reportPolicy|'s sources contains "`inline`" 573 | and |reportPolicy|'s blocked destinations contains 574 | |request|'s destination, 575 | set |reportBlock| to true. 576 | 1. If |block| is true or |reportBlock| is true, then report violation 577 | with |request|, |block|, |reportBlock|, |policy| and |reportPolicy|. 578 | 1. If |block| is true, then return "`Blocked`"; otherwise "`Allowed`". 579 | 580 | ### Report violations ### {#report-violations} 581 | 582 |
583 | [Exposed=Window] 584 | interface IntegrityPolicyViolationReportBody : ReportBody { 585 | [Default] object toJSON(); 586 | readonly attribute USVString documentURL; 587 | readonly attribute USVString blockedURL; 588 | readonly attribute USVString destination; 589 | readonly attribute boolean reportOnly; 590 | }; 591 |592 | 593 | To report violation given a Request |request|, a boolean |block|, 594 | a boolean |reportBlock|, an integrity policy |policy|, 595 | and an integrity policy |reportPolicy|, do the following: 596 | 597 | 1. Assert: |request|'s client is not null. 598 | 1. Let |settingsObject| be |request|'s client. 599 | 1. Let |global| be |settingsObject|'s global object. 600 | 1. Assert: |global| is a {{Window}} or a {{WorkerGlobalScope}}. 601 | 1. Let |url| be null. 602 | 1. If |global| is a {{Window}}, set |url| to |global|'s associated Document's {{Document/URL}}. 603 | 1. If |global| is a {{WorkerGlobalScope}}, set |url| to |global|'s URL. 604 | 1. Assert: |url| is a URL. 605 | 1. Let |documentURL| be the result of strip URL for use in reports on |url|. 606 | 1. Let |blockedURL| be the result of strip URL for use in reports on |request|'s URL. 607 | 1. If |block| is true, for each |endpoint| in |policy|'s endpoints: 608 | 1. Let |body| be a new {{IntegrityPolicyViolationReportBody}}, initialized as follows: 609 | : {{IntegrityPolicyViolationReportBody/documentURL}} 610 | :: |documentURL| 611 | : {{IntegrityPolicyViolationReportBody/blockedURL}} 612 | :: |blockedURL| 613 | : {{IntegrityPolicyViolationReportBody/destination}} 614 | :: |request|'s destination 615 | : {{IntegrityPolicyViolationReportBody/reportOnly}} 616 | :: false 617 | 2. Generate and queue a report with the following arguments: 618 | : context 619 | :: |settingsObject| 620 | : type 621 | :: "`integrity-policy-violation`" 622 | : destination 623 | :: |endpoint| 624 | : data 625 | :: |body| 626 | 1. If |reportBlock| is true, for each |endpoint| in |reportPolicy|'s endpoints: 627 | 1. Let |reportBody| be a new {{IntegrityPolicyViolationReportBody}}, initialized as follows: 628 | : {{IntegrityPolicyViolationReportBody/documentURL}} 629 | :: |documentURL| 630 | : {{IntegrityPolicyViolationReportBody/blockedURL}} 631 | :: |blockedURL| 632 | : {{IntegrityPolicyViolationReportBody/destination}} 633 | :: |request|'s destination 634 | : {{IntegrityPolicyViolationReportBody/reportOnly}} 635 | :: true 636 | 2. Generate and queue a report with the following arguments: 637 | : context 638 | :: |settingsObject| 639 | : type 640 | :: "`integrity-policy-violation`" 641 | : destination 642 | :: |endpoint| 643 | : data 644 | :: |reportBody| 645 | 646 | ### Integration ### {#integration} 647 | 648 | Expand step 7 of main fetch to call should request be blocked by integrity policy 649 | and return a network error if it returns "`Blocked`". 650 | 651 | # Proxies # {#proxies} 652 | 653 | Optimizing proxies and other intermediate servers which modify the 654 | responses MUST ensure that the digest associated 655 | with those responses stays in sync with the new content. One option 656 | is to ensure that the integrity metadata associated with 657 | resources is updated. Another 658 | would be simply to deliver only the canonical version of resources 659 | for which a page author has requested integrity verification. 660 | 661 | To help inform intermediate servers, those serving the resources SHOULD 662 | send along with the resource a `Cache-Control` header 663 | with a value of `no-transform`. 664 | 665 | 666 | 667 | # Security and Privacy Considerations # {#security-considerations} 668 | 669 | This section is not normative. 670 | 671 | ## Non-secure contexts remain non-secure ## {#non-secure-contexts} 672 | 673 | Integrity metadata delivered by a context that is not a Secure 674 | Context such as an HTTP page, only protects an origin against a compromise 675 | of the server where an external resources is hosted. Network attackers can alter 676 | the digest in-flight (or remove it entirely, or do absolutely anything else to 677 | the document), just as they could alter the response the hash is meant to 678 | validate. Thus, it is recommended that authors deliver integrity metadata only 679 | to a Secure Context. See also Securing the Web. 681 | 682 | ## Hash collision attacks ## {#hash-collision-attacks} 683 | 684 | Digests are only as strong as the hash function used to generate them. It is 685 | recommended that user agents refuse to support known-weak hashing functions and 686 | limit supported algorithms to those known to be collision resistant. Examples of 687 | hashing functions that are not recommended include MD5 and SHA-1. At the time of 688 | writing, SHA-384 is a good baseline. 689 | 690 | Moreover, it is recommended that user agents re-evaluate their supported hash 691 | functions on a regular basis and deprecate support for those functions shown to 692 | be insecure. Over time, hash functions may be shown to be much weaker than 693 | expected and, in some cases, broken, so it is important that user agents stay 694 | aware of these developments. 695 | 696 | ## Cross-origin data leakage ## {#cross-origin-data-leakage} 697 | 698 | This specification requires integrity-protected cross-origin requests to use the 699 | CORS protocol to ensure that the resource's content is explicitly shared 700 | with the requestor. If that requirement were omitted, 701 | attackers could violate the same-origin policy 703 | and determine whether a cross-origin resource has certain content. 704 | 705 | Attackers would attempt to load the resource with a known digest, and 706 | watch for load failures. If the load fails, the attacker could surmise 707 | that the response didn't match the hash and thereby gain some insight into 708 | its contents. This might reveal, for example, whether or not a user is 709 | logged into a particular service. 710 | 711 | Moreover, attackers could brute-force specific values in an otherwise 712 | static resource. Consider a JSON response that looks like this: 713 | 714 |
This specification defines a mechanism by which user agents may verify that 133 | a fetched resource has been delivered without unexpected manipulation.
134 |A list of changes to this document may be found at 138 | https://github.com/w3c/webappsec-subresource-integrity.
139 |Sites and applications on the web are rarely composed of resources from 145 | only a single origin. For example, authors pull scripts and styles from a 146 | wide variety of services and content delivery networks, and must trust 147 | that the delivered representation is, in fact, what they expected to 148 | load. If an attacker can trick a user into downloading content from 149 | a hostile server (via DNS poisoning, or other such means), the author has 150 | no recourse. Likewise, an attacker who can replace the file on the Content 151 | Delivery Network (CDN) server has the ability to inject arbitrary content.
152 | 153 |Delivering resources over a secure channel mitigates some of this risk: with 154 | TLS, HSTS, and pinned public keys, a user agent can be fairly certain 155 | that it is indeed speaking with the server it believes it’s talking to. These 156 | mechanisms, however, authenticate only the server, not the content. An 157 | attacker (or administrator) with access to the server can manipulate content with 158 | impunity. Ideally, authors would not only be able to pin the keys of a 159 | server, but also pin the content, ensuring that an exact representation of 160 | a resource, and only that representation, loads and executes.
161 | 162 |This document specifies such a validation scheme, extending two HTML elements
163 | with an integrity
attribute that contains a cryptographic hash
164 | of the representation of the resource the author expects to load. For instance,
165 | an author may wish to load some framework from a shared server rather than hosting it
166 | on their own origin. Specifying that the expected SHA-384 hash of
167 | https://example.com/example-framework.js
168 | is Li9vy3DqF8tnTXuiaAJuML3ky+er10rcgNR/VqsVpcw+ThHmYcwiB1pbOxEbzJr7
means
169 | that the user agent can verify that the data it loads from that URL matches
170 | that expected hash before executing the JavaScript it contains. This
171 | integrity verification significantly reduces the risk that an attacker can
172 | substitute malicious content.
This example can be communicated to a user agent by adding the hash to a
175 | script
element, like so:
<script src="https://example.com/example-framework.js"
178 | integrity="sha384-Li9vy3DqF8tnTXuiaAJuML3ky+er10rcgNR/VqsVpcw+ThHmYcwiB1pbOxEbzJr7"
179 | crossorigin="anonymous"></script>
180 |
181 |
182 | Scripts, of course, are not the only response type which would benefit
183 | from integrity validation. The scheme specified here also applies to link
184 | and future versions of this specification are likely to expand this coverage.
Compromise of a third-party service should not automatically mean 192 | compromise of every site which includes its scripts. Content authors 193 | will have a mechanism by which they can specify expectations for 194 | content they load, meaning for example that they could load a 195 | specific script, and not any script that happens to have a 196 | particular URL.
197 |The verification mechanism should have error-reporting functionality which 200 | would inform the author that an invalid response was received.
201 |An author wishes to use a content delivery network to improve performance
216 | for globally-distributed users. It is important, however, to ensure that
217 | the CDN’s servers deliver only the code the author expects them to
218 | deliver. To mitigate the risk that a CDN compromise (or unexpectedly malicious
219 | behavior) would change that site in unfortunate ways, the following
220 | integrity metadata is added to the link
element included on the page:
<link rel="stylesheet" href="https://site53.example.net/style.css"
223 | integrity="sha384-+/M6kredJcxdsqkczBUjMLvqyHb1K/JThDXWsBVxMEeZHEaMKEOEct339VItX1zB"
224 | crossorigin="anonymous">
225 |
226 | An author wants to include JavaScript provided by a third-party
229 | analytics service. To ensure that only the code that has been carefully
230 | reviewed is executed, the author generates integrity metadata for
231 | the script, and adds it to the script
element:
<script src="https://analytics-r-us.example.com/v1.0/include.js"
234 | integrity="sha384-MBO5IDfYaE6c6Aao94oZrIOiC6CGiSN2n4QUbHNPhzk5Xhm0djZLQqTpL0HzTUxk"
235 | crossorigin="anonymous"></script>
236 |
237 | A user agent wishes to ensure that JavaScript code running in high-privilege HTML 240 | contexts (for example, a browser’s New Tab page) aren’t manipulated before display. 241 | Integrity metadata mitigates the risk that altered JavaScript will run 242 | in these pages’ high-privilege contexts.
243 |Conformance requirements phrased as algorithms or specific steps can be 254 | implemented in any manner, so long as the end result is equivalent. In 255 | particular, the algorithms defined in this specification are intended to 256 | be easy to understand and are not intended to be performant. Implementers 257 | are encouraged to optimize.
258 | 259 |This section defines several terms used throughout the document.
263 | 264 |The term digest refers to the base64-encoded result of 265 | executing a cryptographic hash function on an arbitrary block of data.
266 | 267 |The term origin is defined in the Origin specification. 268 | [[!RFC6454]]
269 | 270 |The representation data and content encoding of a resource 271 | are defined by RFC7231, section 3. [[!RFC7231]]
272 | 273 |A base64 encoding is defined in RFC 4648, section 4. 274 | [[!RFC4648]]
275 | 276 |The SHA-256, SHA-384, and SHA-512 are part 277 | of the SHA-2 set of cryptographic hash functions defined by the 278 | NIST in “FIPS PUB 180-4: Secure Hash Standard (SHS)”.
279 | 280 |The Augmented Backus-Naur Form (ABNF) notation used in this document is 286 | specified in RFC5234. [[!ABNF]]
287 | 288 |Appendix B.1 of [[!ABNF]] defines VCHAR
289 | (printing characters).
WSP
(white space) characters are defined in Section
292 | 2.4.1 Common parser idioms of the HTML 5 specification as
293 | White_Space characters
.
The integrity verification mechanism specified here boils down to the 303 | process of generating a sufficiently strong cryptographic digest for a 304 | resource, and transmitting that digest to a user agent so that it may be 305 | used to verify the response.
306 | 307 |To verify the integrity of a response, a user agent requires integrity 311 | metadata as part of the request. This metadata consists of the following 312 | pieces of information:
313 | 314 |The hash function and digest MUST be provided in order to validate a 321 | response’s integrity.
322 | 323 |At the moment, no options are defined. However, future versions of 324 | the spec may define options, such as MIME types [[!MIMETYPE]].
325 | 326 |This metadata MUST be encoded in the same format as the hash-source
(without the single quotes)
327 | in section 4.2 of the Content Security Policy Level 2 specification.
For example, given a script resource containing only the string alert('Hello, world.');
,
330 | an author might choose SHA-384 as a hash function.
331 | H8BRh8j48O9oYatfu5AZzq6A9RINhZO5H16dQZngK7T62em8MUt1FLm52t+eX6xO
is the base64-encoded
332 | digest that results. This can be encoded as follows:
sha384-H8BRh8j48O9oYatfu5AZzq6A9RINhZO5H16dQZngK7T62em8MUt1FLm52t+eX6xO
335 |
336 |
337 | Digests may be generated using any number of utilities. OpenSSL, for 339 | example, is quite commonly available. The example in this section is the 340 | result of the following command line:
341 | 342 |echo -n "alert('Hello, world.');" | openssl dgst -sha384 -binary | openssl base64 -A
343 |
344 | Conformant user agents MUST support the SHA-256, SHA-384 353 | and SHA-512 cryptographic hash functions for use as part of a 354 | request’s integrity metadata and MAY support additional hash functions.
355 | 356 |User agents SHOULD refuse to support known-weak hashing functions like MD5 or 357 | SHA-1 and SHOULD restrict supported hashing functions to those known to be 358 | collision-resistant. Additionally, user agents SHOULD re-evaluate their 359 | supported hash functions on a regular basis and deprecate support for those 360 | functions that have become insecure. See Hash collision attacks.
361 | 362 |Multiple sets of integrity metadata may be associated with a single 366 | resource in order to provide agility in the face of future cryptographic discoveries. 367 | For example, the resource described in the previous section may be described 368 | by either of the following hash expressions:
369 | 370 |sha384-dOTZf16X8p34q2/kYyEFm0jh89uTjikhnzjeLeF0FHsEaYKb1A1cv+Lyv4Hk8vHd
371 | sha512-Q2bFTOhEALkN8hOms2FKTDLy7eugP2zFZ1T8LCvX42Fp3WoNr3bjZSAHeOsHrbV1Fu9/A0EzCinRE7Af1ofPrw==
372 |
373 |
374 | Authors may choose to specify both, for example:
375 | 376 |<script src="hello_world.js"
377 | integrity="sha384-dOTZf16X8p34q2/kYyEFm0jh89uTjikhnzjeLeF0FHsEaYKb1A1cv+Lyv4Hk8vHd
378 | sha512-Q2bFTOhEALkN8hOms2FKTDLy7eugP2zFZ1T8LCvX42Fp3WoNr3bjZSAHeOsHrbV1Fu9/A0EzCinRE7Af1ofPrw=="
379 | crossorigin="anonymous"></script>
380 |
381 |
382 | In this case, the user agent will choose the strongest hash function in the 383 | list, and use that metadata to validate the response (as described below in 384 | the “parse metadata” and “get the strongest metadata from 385 | set” algorithms).
386 | 387 |When a hash function is determined to be insecure, user agents SHOULD deprecate 388 | and eventually remove support for integrity validation using the insecure hash 389 | function. User agents MAY check the validity of responses using a digest based on 390 | a deprecated function.
391 | 392 |To allow authors to switch to stronger hash functions without being held back by older 393 | user agents, validation using unsupported hash functions acts like no integrity value 394 | was provided (see the “Does response match metadataList” algorithm below). 395 | Authors are encouraged to use strong hash functions, and to begin migrating to 396 | stronger hash functions as they become available.
397 |User agents must provide a mechanism for determining the relative priority of two
404 | hash functions and return the empty string if the priority is equal. That is, if
405 | a user agent implemented a function like getPrioritizedHashFunction(a,
406 | b) it would return the hash function the user agent considers the most
407 | collision-resistant. For example, getPrioritizedHashFunction('sha256',
408 | 'sha512')
would return 'sha512'
and getPrioritizedHashFunction('sha256',
409 | 'sha256')
would return the empty string.
The getPrioritizedHashFunction is an internal 412 | implementation detail. It is not an API that implementors 413 | provide to web applications. It is used in this document 414 | only to simplify the algorithm description.
415 | 416 |In order to mitigate an attacker’s ability to read data cross-origin by 444 | brute-forcing values via integrity checks, responses are only eligible for such 445 | checks if they are same-origin or are the result of explicit access granted to 446 | the loading origin via Cross Origin Resource Sharing [[!CORS]].
447 | 448 |As noted in RFC6454, section 4, some user agents use
449 | globally unique identifiers for each file URI. This means that
450 | resources accessed over a file
scheme URL are unlikely to be
451 | eligible for integrity checks.
Being in a Secure Context (e.g., a document delivered over HTTPS) is not 454 | necessary for the use of integrity validation. Because resource integrity is 455 | only an application level security tool, and it does not change the security 456 | state of the user agent, a Secure Context is unnecessary. However, if integrity 457 | is used in something other than a Secure Context (e.g., a document delivered 458 | over HTTP), authors should be aware that the integrity provides no security 459 | guarantees at all. For this reason, authors should only deliver integrity 460 | metadata in a Secure Context. See Non-secure contexts remain non-secure for 461 | more discussion.
462 | 463 |The following algorithm details these restrictions:
464 | 465 |basic
,
469 | cors
or default
, return true
.false
.The response types are defined by the Fetch 475 | specification [[!FETCH]] and refer to the following:
476 | 477 |basic
is a same-origin response, and thus the requestor has full access
479 | to read the body.cors
is a valid response to a cross-origin, CORS-enabled request, and thus
481 | again the requestor has full access to read the body.default
is a valid response that is generated by a Service Worker as a
483 | response to the request, so its body, too, is fully readable by the requestor.This algorithm accepts a string, and returns either no metadata
, or a set of
493 | valid hash expressions whose hash functions are understood by
494 | the user agent.
true
.false
.no metadata
if empty is true
, otherwise return
513 | result.getPrioritizedHashFunction(currentAlgorithm, newAlgorithm)
534 | is the empty string, add item to result. If the
535 | result is newAlgorithm, set strongest to
536 | item, set result to the empty set, and add
537 | item to result.no metadata
, return true
.false
.true
.true
.false
.This algorithm allows the user agent to accept multiple, valid strong hash
573 | functions. For example, a developer might write a script
element such as:
<script src="https://example.com/example-framework.js"
576 | integrity="sha384-Li9vy3DqF8tnTXuiaAJuML3ky+er10rcgNR/VqsVpcw+ThHmYcwiB1pbOxEbzJr7
577 | sha384-+/M6kredJcxdsqkczBUjMLvqyHb1K/JThDXWsBVxMEeZHEaMKEOEct339VItX1zB"
578 | crossorigin="anonymous"></script>
579 |
580 |
581 | which would allow the user agent to accept two different content payloads, one 582 | of which matches the first SHA384 hash value and the other matches the second 583 | SHA384 hash value.
584 | 585 |User agents may allow users to modify the result of this algorithm via user 586 | preferences, bookmarklets, third-party additions to the user agent, and other 587 | such mechanisms. For example, redirects generated by an extension like 588 | HTTPS Everywhere could load and execute 589 | correctly, even if the HTTPS version of a resource differs from the HTTP 590 | version.
591 | 592 |This algorithm returns false
if the response is not eligible for integrity
593 | validation since Subresource Integrity requires CORS, and it is a logical error
594 | to attempt to use it without CORS. Additionally, user agents SHOULD report a
595 | warning message to the developer console to explain this failure.
A variety of HTML elements result in requests for resources that are to be
605 | embedded into the document, or executed in its context. To support integrity
606 | metadata for some of these elements, a new integrity
attribute is added to
607 | the list of content attributes for the link
and script
elements.
A corresponding integrity
IDL attribute which reflects the
610 | value each element’s integrity
content attribute is added to the
611 | HTMLLinkElement
and HTMLScriptElement
interfaces.
A future revision of this specification is likely to include integrity support
614 | for all possible subresources, i.e., a
, audio
, embed
, iframe
, img
,
615 | link
, object
, script
, source
, track
, and video
elements.
integrity
attributeThe integrity
attribute represents integrity metadata for an element.
623 | The value of the attribute MUST be either the empty string, or at least one
624 | valid metadata as described by the following ABNF grammar:
integrity-metadata = *WSP hash-with-options *( 1*WSP hash-with-options ) *WSP / *WSP
627 | hash-with-options = hash-expression *("?" option-expression)
628 | option-expression = *VCHAR
629 | hash-algo = <hash-algo production from [Content Security Policy Level 2, section 4.2]>
630 | base64-value = <base64-value production from [Content Security Policy Level 2, section 4.2]>
631 | hash-expression = hash-algo "-" base64-value
632 |
633 |
634 | The integrity
IDL attribute must reflect the integrity
content attribute.
option-expression
s are associated on a per hash-expression
basis and are
637 | applied only to the hash-expression
that immediately precedes it.
In order for user agents to remain fully forwards compatible with future
640 | options, the user agent MUST ignore all unrecognized option-expression
s.
Note that while the option-expression
has been reserved in the syntax, no
643 | options have been defined. It is likely that a future version of the spec will
644 | define a more specific syntax for options, so it is defined here as broadly
645 | as possible.
integrity
attributeintegrity
attributeThe user agent will refuse to render or execute responses that fail an integrity 677 | check, instead returning a network error as defined in Fetch [[!FETCH]].
678 | 679 |On a failed integrity check, an error
event is fired. Developers
680 | wishing to provide a canonical fallback resource (e.g., a resource not served
681 | from a CDN, perhaps from a secondary, trusted, but slower source) can catch this
682 | error
event and provide an appropriate handler to replace the
683 | failed resource with a different one.
link
element for stylesheetsWhenever a user agent attempts to obtain a resource pointed to by a
694 | link
element that has a rel
attribute with the keyword of stylesheet
,
695 | modify step 4 to read:
Do a potentially CORS-enabled fetch of the resulting absolute URL, with the
698 | mode being the current state of the element’s crossorigin content attribute,
699 | the origin being the origin of the link element’s Document, the default origin
700 | behavior set to taint, and the integrity metadata of the request set to the
701 | value of the element’s integrity
attribute.
script
elementReplace step 14.1 of HTML5’s “prepare a script” algorithm with:
710 | 711 |src
attribute and
713 | the request’s associated integrity metadata be the value of the element’s
714 | integrity
attribute.Optimizing proxies and other intermediate servers which modify the 730 | responses MUST ensure that the digest associated 731 | with those responses stays in sync with the new content. One option 732 | is to ensure that the integrity metadata associated with 733 | resources is updated. Another 734 | would be simply to deliver only the canonical version of resources 735 | for which a page author has requested integrity verification.
736 | 737 |To help inform intermediate servers, those serving the resources SHOULD
738 | send along with the resource a Cache-Control
header
739 | with a value of no-transform
.
Integrity metadata delivered by a context that is not a Secure Context, 751 | such as an HTTP page, only protects an origin against a compromise of the 752 | server where an external resources is hosted. Network attackers can alter the 753 | digest in-flight (or remove it entirely, or do absolutely anything else to the 754 | document), just as they could alter the response the hash is meant to validate. 755 | Thus, it is recommended that authors deliver integrity metadata only to a 756 | Secure Context. See also securing the web.
757 | 758 |Digests are only as strong as the hash function used to generate them. It is 765 | recommended that user agents refuse to support known-weak hashing functions and 766 | limit supported algorithms to those known to be collision resistant. Examples of 767 | hashing functions that are not recommended include MD5 and SHA-1. At the time of 768 | writing, SHA-384 is a good baseline.
769 | 770 |Moreover, it is recommended that user agents re-evaluate their supported hash 771 | functions on a regular basis and deprecate support for those functions shown to 772 | be insecure. Over time, hash functions may be shown to be much weaker than 773 | expected and, in some cases, broken, so it is important that user agents stay 774 | aware of these developments.
775 | 776 |This specification requires the CORS settings attribute to be present on 783 | integrity-protected cross-origin requests. If that requirement were omitted, 784 | attackers could violate the same-origin policy and determine whether 785 | a cross-origin resource has certain content.
786 | 787 |Attackers would attempt to load the resource with a known digest, and 788 | watch for load failures. If the load fails, the attacker could surmise 789 | that the response didn’t match the hash and thereby gain some insight into 790 | its contents. This might reveal, for example, whether or not a user is 791 | logged into a particular service.
792 | 793 |Moreover, attackers could brute-force specific values in an otherwise 794 | static resource. Consider a JSON response that looks like this:
795 | 796 |{'status': 'authenticated', 'username': 'admin'}
797 |
798 |
799 | An attacker could precompute hashes for the response with a variety of 800 | common usernames, and specify those hashes while repeatedly attempting 801 | to load the document. A successful load would confirm that the attacker 802 | has correctly guessed the username.
803 | 804 |Much of the content here is inspired heavily by Gervase 814 | Markham’s Link Fingerprints concept, as well as WHATWG’s Link Hashes.
815 | 816 |A special thanks to Mike West of Google, Inc. for his invaluable contributions 817 | to the initial version of this spec. Additionally, Brad Hill, Anne van Kesteren, 818 | Jonathan Kingston, Mark Nottingham, Dan Veditz, Eduardo Vela, Tanvi Vyas, and 819 | Michal Zalewski provided invaluable feedback.
820 | 821 |VCHAR
154 | (printing characters).
155 |
156 | WSP
(white space) characters are defined in Section
157 | [2.4.1 Common parser idioms][space-chars] of the HTML 5 specification as
158 | White_Space characters
.
159 |
160 | [abnf-b1]: https://tools.ietf.org/html/rfc5234#appendix-B.1
161 | [space-chars]: http://www.w3.org/TR/html5/infrastructure.html#space-character
162 | error
event is fired. Developers
544 | wishing to provide a canonical fallback resource (e.g., a resource not served
545 | from a CDN, perhaps from a secondary, trusted, but slower source) can catch this
546 | error
event and provide an appropriate handler to replace the
547 | failed resource with a different one.
548 | {:.note}
549 |
550 |