Permalink
Please sign in to comment.
Showing
with
3,150 additions
and 3,150 deletions.
- +6 −6 Makefile
- +0 −2,426 index.bikeshed.html
- 0 index.bikeshed.bs → index.bs
- +2,320 −718 index.html
- +824 −0 index.kramdown.html
- 0 spec.markdown → spec_v1.markdown
| @@ -1,13 +1,13 @@ | ||
| -all: clean index.html index.bikeshed.html | ||
| +all: clean index.html index.kramdown.html | ||
| clean: | ||
| - rm -rf index.html index.bikeshed.html | ||
| + rm -rf index.html index.kramdown.html | ||
| -index.html: spec.markdown template.erb | ||
| - sed -e 's/\[\[/\\[\\[/g' -e 's/\]\]/\\]\\]/g' ./spec.markdown | kramdown --parse-block-html --template='template.erb' > index.html | ||
| +index.kramdown.html: spec_v1.markdown template.erb | ||
| + sed -e 's/\[\[/\\[\\[/g' -e 's/\]\]/\\]\\]/g' ./spec_v1.markdown | kramdown --parse-block-html --template='template.erb' > index.kramdown.html | ||
| -index.bikeshed.html: index.bikeshed.bs | ||
| - curl https://api.csswg.org/bikeshed/ -F file=@index.bikeshed.bs -F force=1 > ./index.bikeshed.html | ||
| +index.html: index.bs | ||
| + curl https://api.csswg.org/bikeshed/ -F [email protected] -F force=1 > ./index.html | ||
| publish: all | ||
| git push origin master | ||
2,426
index.bikeshed.html
0 additions,
2,426 deletions
not shown because the diff is too large. Please use a local Git client to view these changes.
File renamed without changes.
3,038
index.html
2,320 additions,
718 deletions
not shown because the diff is too large. Please use a local Git client to view these changes.
| @@ -0,0 +1,824 @@ | ||
| +<!DOCTYPE html> | ||
| +<html> | ||
| +<head> | ||
| + <meta charset="utf-8"> | ||
| + <title>Subresource Integrity</title> | ||
| + <script src='https://www.w3.org/Tools/respec/respec-w3c-common' class='remove'></script> | ||
| + <script class='remove'> | ||
| + var respecConfig = { | ||
| + // specification status (e.g. WD, LCWD, NOTE, etc.). If in doubt use ED. | ||
| + // Member-SUBM | ||
| + specStatus: "REC", | ||
| + | ||
| + // the specification's short name, as in http://www.w3.org/TR/short-name/ | ||
| + shortName: "SRI", | ||
| + | ||
| + // if the specification's copyright date is a range of years, specify | ||
| + // the start date here: | ||
| + copyrightStart: "2014", | ||
| + | ||
| + // if there a publicly available Editor's Draft, this is the link | ||
| + edDraftURI: "https://w3c.github.io/webappsec-subresource-integrity/", | ||
| + crEnd: "2015-12-15", | ||
| + | ||
| + previousMaturity: "PR", | ||
| + previousPublishDate: "2016-05-10", | ||
| + | ||
| + implementationReportURI: "https://github.com/w3c/webappsec-subresource-integrity/wiki/Links", | ||
| + | ||
| + // editors, add as many as you like | ||
| + // only "name" is required | ||
| + editors: [ | ||
| + { name: "Devdatta Akhawe", url: "http://devd.me", mailto: "[email protected]", company: "Dropbox, Inc.", companyURL: "https://www.dropbox.com/"}, | ||
| + { name: "Frederik Braun", url: "https://frederik-braun.com/", mailto: "[email protected]", company: "Mozilla", companyURL: "https://www.mozilla.org/", w3cid: 68466 }, | ||
| + { name: "François Marier", url: "https://fmarier.org", mailto: "[email protected]", company: "Mozilla", companyURL: "https://www.mozilla.org/" }, | ||
| + { name: "Joel Weinberger", url: "https://joelweinberger.us/", mailto: "[email protected]", company: "Google, Inc.", companyURL: "https://google.com/" }, | ||
| + ], | ||
| + | ||
| + otherLinks: [{ | ||
| + key: 'Participate', | ||
| + data: [{ | ||
| + value: 'We are on Github.', | ||
| + href: 'https://github.com/w3c/webappsec-subresource-integrity' | ||
| + }, { | ||
| + value: 'File a bug.', | ||
| + href: 'https://github.com/w3c/webappsec-subresource-integrity/issues' | ||
| + }, { | ||
| + value: 'Commit history.', | ||
| + href: 'https://github.com/w3c/webappsec-subresource-integrity/commits/gh-pages' | ||
| + }, { | ||
| + value: 'Mailing list.', | ||
| + href: 'https://lists.w3.org/Archives/Public/public-webappsec/' | ||
| + }] | ||
| + }, { | ||
| + key: 'Implementation status', | ||
| + data: [{ | ||
| + value: "Blink/Chromium", | ||
| + href: "https://code.google.com/p/chromium/issues/detail?id=355467" | ||
| + }, { | ||
| + value: "Gecko", | ||
| + href: "https://bugzilla.mozilla.org/show_bug.cgi?id=992096" | ||
| + }] | ||
| + }], | ||
| + | ||
| + // name of the WG | ||
| + wg: "Web Application Security Working Group", | ||
| + | ||
| + // URI of the public WG page | ||
| + wgURI: "http://www.w3.org/2011/webappsec/", | ||
| + | ||
| + // name (with the @w3c.org) of the public mailing to which comments are due | ||
| + wgPublicList: "public-webappsec", | ||
| + subjectPrefix: "[SRI]", | ||
| + | ||
| + // URI of the patent status for this WG, for Rec-track documents | ||
| + // !!!! IMPORTANT !!!! | ||
| + // This is important for Rec-track documents, do not copy a patent URI from a random | ||
| + // document unless you know what you're doing. If in doubt ask your friendly neighbourhood | ||
| + // Team Contact. | ||
| + wgPatentURI: "http://www.w3.org/2004/01/pp-impl/49309/status", | ||
| + | ||
| + localBiblio: { | ||
| + "CSP": { | ||
| + title: "Content Security Policy 1.1", | ||
| + href: "http://w3.org/TR/CSP11", | ||
| + authors: [ | ||
| + "Adam Barth", | ||
| + "Dan Veditz", | ||
| + "Mike West" | ||
| + ], | ||
| + status: "Working Draft", | ||
| + publisher: "W3C" | ||
| + }, | ||
| + "MIMETYPE": { | ||
| + title: "Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types", | ||
| + href: "https://tools.ietf.org/html/rfc2046", | ||
| + authors: [ | ||
| + "Ned Freed", | ||
| + "Nathaniel S. Borenstein" | ||
| + ], | ||
| + status: "Draft Standard", | ||
| + publisher: "IETF" | ||
| + }, | ||
| + "RFC4648": { | ||
| + title: "The Base16, Base32, and Base64 Data Encodings", | ||
| + href: "https://tools.ietf.org/html/rfc4648", | ||
| + authors: [ | ||
| + "Simon Josefsson", | ||
| + ], | ||
| + status: "Proposed Standard", | ||
| + publisher: "IETF" | ||
| + }, | ||
| + "RFC6920": { | ||
| + title: "Naming Things with Hashes", | ||
| + href: "http://tools.ietf.org/html/rfc6920", | ||
| + authors: [ | ||
| + "Stephen Farrell", | ||
| + "Dirk Kutscher", | ||
| + "Christian Dannewitz", | ||
| + "Borje Ohlman", | ||
| + "Ari Keranen", | ||
| + "Phillip Hallam-Baker", | ||
| + ], | ||
| + status: "Proposed Standard", | ||
| + publisher: "IETF" | ||
| + } | ||
| + } | ||
| + }; | ||
| + </script> | ||
| +</head> | ||
| +<body> | ||
| +<section id="abstract"> | ||
| + <p>This specification defines a mechanism by which user agents may verify that | ||
| +a fetched resource has been delivered without unexpected manipulation.</p> | ||
| +</section> | ||
| + | ||
| +<section id="sotd"> | ||
| + <p>A list of changes to this document may be found at | ||
| +<a href="https://github.com/w3c/webappsec-subresource-integrity">https://github.com/w3c/webappsec-subresource-integrity</a>.</p> | ||
| +</section> | ||
| + | ||
| +<section class="informative"> | ||
| + <h2 id="introduction">Introduction</h2> | ||
| + | ||
| + <p>Sites and applications on the web are rarely composed of resources from | ||
| +only a single origin. For example, authors pull scripts and styles from a | ||
| +wide variety of services and content delivery networks, and must trust | ||
| +that the delivered representation is, in fact, what they expected to | ||
| +load. If an attacker can trick a user into downloading content from | ||
| +a hostile server (via <a href="https://www.ietf.org/rfc/rfc1035.txt">DNS</a> poisoning, or other such means), the author has | ||
| +no recourse. Likewise, an attacker who can replace the file on the Content | ||
| +Delivery Network (CDN) server has the ability to inject arbitrary content.</p> | ||
| + | ||
| + <p>Delivering resources over a secure channel mitigates some of this risk: with | ||
| +<a href="https://tools.ietf.org/html/rfc5246">TLS</a>, <a href="https://tools.ietf.org/html/rfc6797">HSTS</a>, and <a href="https://tools.ietf.org/html/rfc7469">pinned public keys</a>, a user agent can be fairly certain | ||
| +that it is indeed speaking with the server it believes it’s talking to. These | ||
| +mechanisms, however, authenticate <em>only</em> the server, <em>not</em> the content. An | ||
| +attacker (or administrator) with access to the server can manipulate content with | ||
| +impunity. Ideally, authors would not only be able to pin the keys of a | ||
| +server, but also pin the <em>content</em>, ensuring that an exact representation of | ||
| +a resource, and <em>only</em> that representation, loads and executes.</p> | ||
| + | ||
| + <p>This document specifies such a validation scheme, extending two HTML elements | ||
| +with an <code>integrity</code> attribute that contains a cryptographic hash | ||
| +of the representation of the resource the author expects to load. For instance, | ||
| +an author may wish to load some framework from a shared server rather than hosting it | ||
| +on their own origin. Specifying that the <em>expected</em> SHA-384 hash of | ||
| +<code>https://example.com/example-framework.js</code> | ||
| +is <code>Li9vy3DqF8tnTXuiaAJuML3ky+er10rcgNR/VqsVpcw+ThHmYcwiB1pbOxEbzJr7</code> means | ||
| +that the user agent can verify that the data it loads from that URL matches | ||
| +that expected hash before executing the JavaScript it contains. This | ||
| +integrity verification significantly reduces the risk that an attacker can | ||
| +substitute malicious content.</p> | ||
| + | ||
| + <p>This example can be communicated to a user agent by adding the hash to a | ||
| +<code>script</code> element, like so:</p> | ||
| + | ||
| + <pre class="example"><code><script src="https://example.com/example-framework.js" | ||
| + integrity="sha384-Li9vy3DqF8tnTXuiaAJuML3ky+er10rcgNR/VqsVpcw+ThHmYcwiB1pbOxEbzJr7" | ||
| + crossorigin="anonymous"></script> | ||
| +</code></pre> | ||
| + | ||
| + <p>Scripts, of course, are not the only response type which would benefit | ||
| +from integrity validation. The scheme specified here also applies to <code>link</code> | ||
| +and future versions of this specification are likely to expand this coverage.</p> | ||
| + | ||
| + <section> | ||
| + <h3 id="goals">Goals</h3> | ||
| + | ||
| + <ol> | ||
| + <li> | ||
| + <p>Compromise of a third-party service should not automatically mean | ||
| +compromise of every site which includes its scripts. Content authors | ||
| +will have a mechanism by which they can specify expectations for | ||
| +content they load, meaning for example that they could load a | ||
| +<em>specific</em> script, and not <em>any</em> script that happens to have a | ||
| +particular URL.</p> | ||
| + </li> | ||
| + <li> | ||
| + <p>The verification mechanism should have error-reporting functionality which | ||
| +would inform the author that an invalid response was received.</p> | ||
| + </li> | ||
| + </ol> | ||
| + | ||
| + </section> | ||
| + <!-- /Introduction::Goals --> | ||
| + | ||
| + <section> | ||
| + <h3 id="use-casesexamples">Use Cases/Examples</h3> | ||
| + | ||
| + <section> | ||
| + <h4 id="resource-integrity">Resource Integrity</h4> | ||
| + | ||
| + <ul> | ||
| + <li> | ||
| + <p>An author wishes to use a content delivery network to improve performance | ||
| +for globally-distributed users. It is important, however, to ensure that | ||
| +the CDN’s servers deliver <em>only</em> the code the author expects them to | ||
| +deliver. To mitigate the risk that a CDN compromise (or unexpectedly malicious | ||
| +behavior) would change that site in unfortunate ways, the following | ||
| +<a href="#dfn-integrity-metadata">integrity metadata</a> is added to the <code>link</code> element included on the page:</p> | ||
| + | ||
| + <pre class="example"><code><link rel="stylesheet" href="https://site53.example.net/style.css" | ||
| + integrity="sha384-+/M6kredJcxdsqkczBUjMLvqyHb1K/JThDXWsBVxMEeZHEaMKEOEct339VItX1zB" | ||
| + crossorigin="anonymous"> | ||
| +</code></pre> | ||
| + </li> | ||
| + <li> | ||
| + <p>An author wants to include JavaScript provided by a third-party | ||
| +analytics service. To ensure that only the code that has been carefully | ||
| +reviewed is executed, the author generates <a href="#dfn-integrity-metadata">integrity metadata</a> for | ||
| +the script, and adds it to the <code>script</code> element:</p> | ||
| + | ||
| + <pre class="example"><code><script src="https://analytics-r-us.example.com/v1.0/include.js" | ||
| + integrity="sha384-MBO5IDfYaE6c6Aao94oZrIOiC6CGiSN2n4QUbHNPhzk5Xhm0djZLQqTpL0HzTUxk" | ||
| + crossorigin="anonymous"></script> | ||
| +</code></pre> | ||
| + </li> | ||
| + <li> | ||
| + <p>A user agent wishes to ensure that JavaScript code running in high-privilege HTML | ||
| +contexts (for example, a browser’s New Tab page) aren’t manipulated before display. | ||
| +<a href="#dfn-integrity-metadata">Integrity metadata</a> mitigates the risk that altered JavaScript will run | ||
| +in these pages’ high-privilege contexts.</p> | ||
| + </li> | ||
| + </ul> | ||
| + </section> | ||
| + <!-- Introduction::UseCases::Integrity --> | ||
| + </section> | ||
| + <!-- /Introduction::Use Cases --> | ||
| +</section> | ||
| +<!-- /Introduction --> | ||
| + | ||
| +<section id="conformance"> | ||
| + <p>Conformance requirements phrased as algorithms or specific steps can be | ||
| +implemented in any manner, so long as the end result is equivalent. In | ||
| +particular, the algorithms defined in this specification are intended to | ||
| +be easy to understand and are not intended to be performant. Implementers | ||
| +are encouraged to optimize.</p> | ||
| + | ||
| + <section> | ||
| + <h3 id="key-concepts-and-terminology">Key Concepts and Terminology</h3> | ||
| + | ||
| + <p>This section defines several terms used throughout the document.</p> | ||
| + | ||
| + <p>The term <dfn>digest</dfn> refers to the base64-encoded result of | ||
| +executing a cryptographic hash function on an arbitrary block of data.</p> | ||
| + | ||
| + <p>The term <dfn>origin</dfn> is defined in the Origin specification. | ||
| +[[!RFC6454]]</p> | ||
| + | ||
| + <p>The <dfn>representation data</dfn> and <dfn>content encoding</dfn> of a resource | ||
| +are defined by <a href="https://tools.ietf.org/html/rfc7231#section-3">RFC7231, section 3</a>. [[!RFC7231]]</p> | ||
| + | ||
| + <p>A <dfn>base64 encoding</dfn> is defined in <a href="https://tools.ietf.org/html/rfc4648#section-4">RFC 4648, section 4</a>. | ||
| +[[!RFC4648]]</p> | ||
| + | ||
| + <p>The <dfn>SHA-256</dfn>, <dfn>SHA-384</dfn>, and <dfn>SHA-512</dfn> are part | ||
| +of the <dfn>SHA-2</dfn> set of cryptographic hash functions defined by the | ||
| +NIST in <a href="http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf">“FIPS PUB 180-4: Secure Hash Standard (SHS)”</a>.</p> | ||
| + | ||
| + </section> | ||
| + | ||
| + <section> | ||
| + <h3 id="grammatical-concepts">Grammatical Concepts</h3> | ||
| + | ||
| + <p>The Augmented Backus-Naur Form (ABNF) notation used in this document is | ||
| +specified in RFC5234. [[!ABNF]]</p> | ||
| + | ||
| + <p><a href="https://tools.ietf.org/html/rfc5234#appendix-B.1">Appendix B.1</a> of [[!ABNF]] defines <code><dfn>VCHAR</dfn></code> | ||
| +(printing characters).</p> | ||
| + | ||
| + <p><code><dfn>WSP</dfn></code> (white space) characters are defined in Section | ||
| +<a href="http://www.w3.org/TR/html5/infrastructure.html#space-character">2.4.1 Common parser idioms</a> of the HTML 5 specification as | ||
| +<code>White_Space characters</code>.</p> | ||
| + | ||
| + </section> | ||
| + | ||
| +</section> | ||
| + | ||
| +<section> | ||
| + <h2 id="framework">Framework</h2> | ||
| + | ||
| + <p>The integrity verification mechanism specified here boils down to the | ||
| +process of generating a sufficiently strong cryptographic digest for a | ||
| +resource, and transmitting that digest to a user agent so that it may be | ||
| +used to verify the response.</p> | ||
| + | ||
| + <section> | ||
| + <h3 id="integrity-metadata">Integrity metadata</h3> | ||
| + | ||
| + <p>To verify the integrity of a response, a user agent requires <dfn>integrity | ||
| +metadata</dfn> as part of the <a href="https://fetch.spec.whatwg.org/#concept-request-integrity-metadata">request</a>. This metadata consists of the following | ||
| +pieces of information:</p> | ||
| + | ||
| + <ul> | ||
| + <li>cryptographic hash function (“alg”)</li> | ||
| + <li><a href="#dfn-digest">digest</a> (“val”)</li> | ||
| + <li>options (“opt”)</li> | ||
| + </ul> | ||
| + | ||
| + <p>The hash function and digest MUST be provided in order to validate a | ||
| +response’s integrity.</p> | ||
| + | ||
| + <p class="note">At the moment, no options are defined. However, future versions of | ||
| +the spec may define options, such as MIME types [[!MIMETYPE]].</p> | ||
| + | ||
| + <p>This metadata MUST be encoded in the same format as the <code>hash-source</code> (without the single quotes) | ||
| +in <a href="http://www.w3.org/TR/CSP2/#source-list-syntax">section 4.2 of the Content Security Policy Level 2 specification</a>.</p> | ||
| + | ||
| + <p>For example, given a script resource containing only the string <code>alert(\'Hello, world.\');</code>, | ||
| +an author might choose <a href="#dfn-sha-2">SHA-384</a> as a hash function. | ||
| +<code>H8BRh8j48O9oYatfu5AZzq6A9RINhZO5H16dQZngK7T62em8MUt1FLm52t+eX6xO</code> is the base64-encoded | ||
| +digest that results. This can be encoded as follows:</p> | ||
| + | ||
| + <pre class="example"><code>sha384-H8BRh8j48O9oYatfu5AZzq6A9RINhZO5H16dQZngK7T62em8MUt1FLm52t+eX6xO | ||
| +</code></pre> | ||
| + | ||
| + <div class="note"> | ||
| + <p>Digests may be generated using any number of utilities. <a href="https://www.openssl.org/">OpenSSL</a>, for | ||
| +example, is quite commonly available. The example in this section is the | ||
| +result of the following command line:</p> | ||
| + | ||
| + <pre><code>echo -n "alert('Hello, world.');" | openssl dgst -sha384 -binary | openssl base64 -A | ||
| +</code></pre> | ||
| + </div> | ||
| + | ||
| + </section> | ||
| + <!-- /Framework::Required metadata --> | ||
| + | ||
| + <section> | ||
| + <h3 id="cryptographic-hash-functions">Cryptographic hash functions</h3> | ||
| + | ||
| + <p>Conformant user agents MUST support the <a href="#dfn-sha-2">SHA-256</a>, <a href="#dfn-sha-2">SHA-384</a> | ||
| +and <a href="#dfn-sha-2">SHA-512</a> cryptographic hash functions for use as part of a | ||
| +request’s <a href="#dfn-integrity-metadata">integrity metadata</a> and MAY support additional hash functions.</p> | ||
| + | ||
| + <p>User agents SHOULD refuse to support known-weak hashing functions like MD5 or | ||
| +SHA-1 and SHOULD restrict supported hashing functions to those known to be | ||
| +collision-resistant. Additionally, user agents SHOULD re-evaluate their | ||
| +supported hash functions on a regular basis and deprecate support for those | ||
| +functions that have become insecure. See <a href="#hash-collision-attacks">Hash collision attacks</a>.</p> | ||
| + | ||
| + <section> | ||
| + <h4 id="agility">Agility</h4> | ||
| + | ||
| + <p>Multiple sets of <a href="#dfn-integrity-metadata">integrity metadata</a> may be associated with a single | ||
| +resource in order to provide agility in the face of future cryptographic discoveries. | ||
| +For example, the resource described in the previous section may be described | ||
| +by either of the following hash expressions:</p> | ||
| + | ||
| + <pre class="example"><code>sha384-dOTZf16X8p34q2/kYyEFm0jh89uTjikhnzjeLeF0FHsEaYKb1A1cv+Lyv4Hk8vHd | ||
| +sha512-Q2bFTOhEALkN8hOms2FKTDLy7eugP2zFZ1T8LCvX42Fp3WoNr3bjZSAHeOsHrbV1Fu9/A0EzCinRE7Af1ofPrw== | ||
| +</code></pre> | ||
| + | ||
| + <p>Authors may choose to specify both, for example:</p> | ||
| + | ||
| + <pre class="example"><code><script src="hello_world.js" | ||
| + integrity="sha384-dOTZf16X8p34q2/kYyEFm0jh89uTjikhnzjeLeF0FHsEaYKb1A1cv+Lyv4Hk8vHd | ||
| + sha512-Q2bFTOhEALkN8hOms2FKTDLy7eugP2zFZ1T8LCvX42Fp3WoNr3bjZSAHeOsHrbV1Fu9/A0EzCinRE7Af1ofPrw==" | ||
| + crossorigin="anonymous"></script> | ||
| +</code></pre> | ||
| + | ||
| + <p>In this case, the user agent will choose the strongest hash function in the | ||
| +list, and use that metadata to validate the response (as described below in | ||
| +the “<a href="#parse-metadata">parse metadata</a>” and “<a href="#get-the-strongest-metadata-from-set">get the strongest metadata from | ||
| +set</a>” algorithms).</p> | ||
| + | ||
| + <p>When a hash function is determined to be insecure, user agents SHOULD deprecate | ||
| +and eventually remove support for integrity validation using the insecure hash | ||
| +function. User agents MAY check the validity of responses using a digest based on | ||
| +a deprecated function.</p> | ||
| + | ||
| + <p>To allow authors to switch to stronger hash functions without being held back by older | ||
| +user agents, validation using unsupported hash functions acts like no integrity value | ||
| +was provided (see the “<a href="#does-response-match-metadatalist">Does response match metadataList</a>” algorithm below). | ||
| +Authors are encouraged to use strong hash functions, and to begin migrating to | ||
| +stronger hash functions as they become available.</p> | ||
| + </section> | ||
| + <!-- /Framework::Cryptographic hash functions::Agility --> | ||
| + | ||
| + <section> | ||
| + <h4 id="priority">Priority</h4> | ||
| + | ||
| + <p>User agents must provide a mechanism for determining the relative priority of two | ||
| +hash functions and return the empty string if the priority is equal. That is, if | ||
| +a user agent implemented a function like <dfn>getPrioritizedHashFunction(a, | ||
| +b)</dfn> it would return the hash function the user agent considers the most | ||
| +collision-resistant. For example, <code>getPrioritizedHashFunction('sha256', | ||
| +'sha512')</code> would return <code>'sha512'</code> and <code>getPrioritizedHashFunction('sha256', | ||
| +'sha256')</code> would return the empty string.</p> | ||
| + | ||
| + <p class="note">The <dfn>getPrioritizedHashFunction</dfn> is an internal | ||
| +implementation detail. It is not an API that implementors | ||
| +provide to web applications. It is used in this document | ||
| +only to simplify the algorithm description.</p> | ||
| + | ||
| + </section> | ||
| + <!-- /Framework::Cryptographic hash functions::Priority --> | ||
| + | ||
| + </section> | ||
| + <!-- /Framework::Cryptographic hash functions --> | ||
| + | ||
| + <section> | ||
| + <h3 id="response-verification-algorithms">Response verification algorithms</h3> | ||
| + | ||
| + <section> | ||
| + <h4 id="apply-algorithm-to-response">Apply <var>algorithm</var> to <var>response</var></h4> | ||
| + | ||
| + <ol> | ||
| + <li>Let <var>result</var> be the result of <a href="#apply-algorithm-to-response">applying <var>algorithm</var></a> | ||
| +to the <a href="https://tools.ietf.org/html/rfc7231#section-3">representation data</a> without any content-codings | ||
| +applied, except when the user agent intends to consume the content with | ||
| +content-encodings applied. In the latter case, let <var>result</var> be | ||
| +the result of applying <var>algorithm</var> to the <a href="https://tools.ietf.org/html/rfc7231#section-3">representation data</a>.</li> | ||
| + <li>Let <var>encodedResult</var> be result of base64-encoding | ||
| +<var>result</var>.</li> | ||
| + <li>Return <var>encodedResult</var>.</li> | ||
| + </ol> | ||
| + </section> | ||
| + <!-- Algorithms::apply --> | ||
| + <section> | ||
| + <h4 id="is-response-eligible-for-integrity-validation">Is <var>response</var> eligible for integrity validation</h4> | ||
| + | ||
| + <p>In order to mitigate an attacker’s ability to read data cross-origin by | ||
| +brute-forcing values via integrity checks, responses are only eligible for such | ||
| +checks if they are same-origin or are the result of explicit access granted to | ||
| +the loading origin via Cross Origin Resource Sharing [[!CORS]].</p> | ||
| + | ||
| + <p class="note">As noted in <a href="https://tools.ietf.org/html/rfc6454#section-4">RFC6454, section 4</a>, some user agents use | ||
| +globally unique identifiers for each file URI. This means that | ||
| +resources accessed over a <code>file</code> scheme URL are unlikely to be | ||
| +eligible for integrity checks.</p> | ||
| + | ||
| + <p class="note">Being in a <a href="https://w3c.github.io/webappsec-secure-contexts/">Secure Context</a> (e.g., a document delivered over HTTPS) is not | ||
| +necessary for the use of integrity validation. Because resource integrity is | ||
| +only an application level security tool, and it does not change the security | ||
| +state of the user agent, a Secure Context is unnecessary. However, if integrity | ||
| +is used in something other than a Secure Context (e.g., a document delivered | ||
| +over HTTP), authors should be aware that the integrity provides <em>no security | ||
| +guarantees at all</em>. For this reason, authors should only deliver integrity | ||
| +metadata in a Secure Context. See <a href="#non-secure-contexts-remain-non-secure">Non-secure contexts remain non-secure</a> for | ||
| +more discussion.</p> | ||
| + | ||
| + <p>The following algorithm details these restrictions:</p> | ||
| + | ||
| + <ol> | ||
| + <li>Let <var>response</var> be the response that results from | ||
| +<a href="https://fetch.spec.whatwg.org/#concept-fetch">fetching</a> the <var>resource</var>.</li> | ||
| + <li>If the <var>response</var> <a href="https://fetch.spec.whatwg.org/#concept-response-type">type</a> is <code>basic</code>, | ||
| +<code>cors</code> or <code>default</code>, return <code>true</code>.</li> | ||
| + <li>Return <code>false</code>.</li> | ||
| + </ol> | ||
| + | ||
| + <div class="note"> | ||
| + <p>The <a href="https://fetch.spec.whatwg.org/#concept-response-type">response types</a> are defined by the Fetch | ||
| +specification [[!FETCH]] and refer to the following:</p> | ||
| + | ||
| + <ul> | ||
| + <li><code>basic</code> is a same-origin response, and thus the requestor has full access | ||
| +to read the body.</li> | ||
| + <li><code>cors</code> is a valid response to a cross-origin, CORS-enabled request, and thus | ||
| +again the requestor has full access to read the body.</li> | ||
| + <li><code>default</code> is a valid response that is generated by a Service Worker as a | ||
| +response to the request, so its body, too, is fully readable by the requestor.</li> | ||
| + </ul> | ||
| + </div> | ||
| + | ||
| + </section> | ||
| + <!-- Algorithms::eligible --> | ||
| + <section> | ||
| + <h4 id="parse-metadata">Parse <var>metadata</var>.</h4> | ||
| + | ||
| + <p>This algorithm accepts a string, and returns either <code>no metadata</code>, or a set of | ||
| +valid hash expressions whose hash functions are understood by | ||
| +the user agent.</p> | ||
| + | ||
| + <ol> | ||
| + <li>Let <var>result</var> be the empty set.</li> | ||
| + <li>Let <var>empty</var> be equal to <code>true</code>.</li> | ||
| + <li>For each <var>token</var> returned by <a href="http://www.w3.org/TR/html5/infrastructure.html#split-a-string-on-spaces">splitting <var>metadata</var> on | ||
| +spaces</a>: | ||
| + <ol> | ||
| + <li>Set <var>empty</var> to <code>false</code>.</li> | ||
| + <li>If <var>token</var> is not a valid metadata, skip the remaining | ||
| +steps, and proceed to the next token.</li> | ||
| + <li>Parse <var>token</var> per the grammar in <a href="#dfn-integrity-metadata">integrity metadata</a>.</li> | ||
| + <li>Let <var>algorithm</var> be the <var>alg</var> component of | ||
| +<var>token</var>.</li> | ||
| + <li>If <var>algorithm</var> is a hash function recognized by the user | ||
| +agent, add the parsed <var>token</var> to <var>result</var>.</li> | ||
| + </ol> | ||
| + </li> | ||
| + <li>Return <code>no metadata</code> if <var>empty</var> is <code>true</code>, otherwise return | ||
| +<var>result</var>.</li> | ||
| + </ol> | ||
| + | ||
| + </section> | ||
| + <!-- Algorithms::parse --> | ||
| + <section> | ||
| + <h4 id="get-the-strongest-metadata-from-set">Get the strongest metadata from <var>set</var>.</h4> | ||
| + | ||
| + <ol> | ||
| + <li>Let <var>result</var> be the empty set and <var>strongest</var> be the empty | ||
| +string.</li> | ||
| + <li>For each <var>item</var> in <var>set</var>: | ||
| + <ol> | ||
| + <li>If <var>result</var> is the empty set, add <var>item</var> to | ||
| +<var>result</var> and set <var>strongest</var> to <var>item</var>, skip | ||
| +to the next <var>item</var>.</li> | ||
| + <li>Let <var>currentAlgorithm</var> be the <var>alg</var> component of | ||
| +<var>strongest</var>.</li> | ||
| + <li>Let <var>newAlgorithm</var> be the <var>alg</var> component of | ||
| +<var>item</var>.</li> | ||
| + <li>If the result of <a href="#dfn-getprioritizedhashfunction-a-b"><code>getPrioritizedHashFunction(currentAlgorithm, newAlgorithm)</code></a> | ||
| +is the empty string, add <var>item</var> to <var>result</var>. If the | ||
| +result is <var>newAlgorithm</var>, set <var>strongest</var> to | ||
| +<var>item</var>, set <var>result</var> to the empty set, and add | ||
| +<var>item</var> to <var>result</var>.</li> | ||
| + </ol> | ||
| + </li> | ||
| + <li>Return <var>result</var>.</li> | ||
| + </ol> | ||
| + | ||
| + </section> | ||
| + <!-- /Algorithms::get the strongest metadata --> | ||
| + <section> | ||
| + <h4 id="does-response-match-metadatalist">Does <var>response</var> match <var>metadataList</var>?</h4> | ||
| + | ||
| + <ol> | ||
| + <li>Let <var>parsedMetadata</var> be the result of | ||
| +<a href="#parse-metadata">parsing <var>metadataList</var></a>.</li> | ||
| + <li>If <var>parsedMetadata</var> is <code>no metadata</code>, return <code>true</code>.</li> | ||
| + <li>If <a href="#is-response-eligible-for-integrity-validation"><var>response</var> is not eligible for integrity | ||
| +validation</a>, return <code>false</code>.</li> | ||
| + <li>If <var>parsedMetadata</var> is the empty set, return <code>true</code>.</li> | ||
| + <li>Let <var>metadata</var> be the result of <a href="#get-the-strongest-metadata-from-set">getting the strongest | ||
| +metadata from <var>parsedMetadata</var></a>.</li> | ||
| + <li>For each <var>item</var> in <var>metadata</var>: | ||
| + <ol> | ||
| + <li>Let <var>algorithm</var> be the <var>alg</var> component of | ||
| +<var>item</var>.</li> | ||
| + <li>Let <var>expectedValue</var> be the <var>val</var> component of | ||
| +<var>item</var>.</li> | ||
| + <li>Let <var>actualValue</var> be the result of <a href="#apply-algorithm-to-response">applying | ||
| +<var>algorithm</var> to <var>response</var></a>.</li> | ||
| + <li>If <var>actualValue</var> is a case-sensitive match for | ||
| +<var>expectedValue</var>, return <code>true</code>.</li> | ||
| + </ol> | ||
| + </li> | ||
| + <li>Return <code>false</code>.</li> | ||
| + </ol> | ||
| + | ||
| + <p>This algorithm allows the user agent to accept multiple, valid strong hash | ||
| +functions. For example, a developer might write a <code>script</code> element such as:</p> | ||
| + | ||
| + <pre class="example"><code><script src="https://example.com/example-framework.js" | ||
| + integrity="sha384-Li9vy3DqF8tnTXuiaAJuML3ky+er10rcgNR/VqsVpcw+ThHmYcwiB1pbOxEbzJr7 | ||
| + sha384-+/M6kredJcxdsqkczBUjMLvqyHb1K/JThDXWsBVxMEeZHEaMKEOEct339VItX1zB" | ||
| + crossorigin="anonymous"></script> | ||
| +</code></pre> | ||
| + | ||
| + <p>which would allow the user agent to accept two different content payloads, one | ||
| +of which matches the first SHA384 hash value and the other matches the second | ||
| +SHA384 hash value.</p> | ||
| + | ||
| + <p class="note">User agents may allow users to modify the result of this algorithm via user | ||
| +preferences, bookmarklets, third-party additions to the user agent, and other | ||
| +such mechanisms. For example, redirects generated by an extension like | ||
| +<a href="https://www.eff.org/https-everywhere">HTTPS Everywhere</a> could load and execute | ||
| +correctly, even if the HTTPS version of a resource differs from the HTTP | ||
| +version.</p> | ||
| + | ||
| + <p class="note">This algorithm returns <code>false</code> if the response is not <a href="#is-response-eligible-for-integrity-validation">eligible</a> for integrity | ||
| +validation since Subresource Integrity requires CORS, and it is a logical error | ||
| +to attempt to use it without CORS. Additionally, user agents SHOULD report a | ||
| +warning message to the developer console to explain this failure.</p> | ||
| + </section> | ||
| + <!-- Algorithms::Match --> | ||
| + </section> | ||
| + <!-- Algorithms --> | ||
| + | ||
| + <section> | ||
| + <h3 id="verification-of-html-document-subresources">Verification of HTML document subresources</h3> | ||
| + | ||
| + <p>A variety of HTML elements result in requests for resources that are to be | ||
| +embedded into the document, or executed in its context. To support integrity | ||
| +metadata for some of these elements, a new <code>integrity</code> attribute is added to | ||
| +the list of content attributes for the <code>link</code> and <code>script</code> elements.</p> | ||
| + | ||
| + <p>A corresponding <code>integrity</code> IDL attribute which <a href="http://www.w3.org/TR/html5/infrastructure.html#reflect">reflects</a> the | ||
| +value each element’s <code>integrity</code> content attribute is added to the | ||
| +<code>HTMLLinkElement</code> and <code>HTMLScriptElement</code> interfaces.</p> | ||
| + | ||
| + <p class="note">A future revision of this specification is likely to include integrity support | ||
| +for all possible subresources, i.e., <code>a</code>, <code>audio</code>, <code>embed</code>, <code>iframe</code>, <code>img</code>, | ||
| +<code>link</code>, <code>object</code>, <code>script</code>, <code>source</code>, <code>track</code>, and <code>video</code> elements.</p> | ||
| + | ||
| + </section> | ||
| + | ||
| + <section> | ||
| + <h4 id="the-integrity-attribute">The <code>integrity</code> attribute</h4> | ||
| + | ||
| + <p>The <code>integrity</code> attribute represents <a href="#dfn-integrity-metadata">integrity metadata</a> for an element. | ||
| +The value of the attribute MUST be either the empty string, or at least one | ||
| +valid metadata as described by the following ABNF grammar:</p> | ||
| + | ||
| + <pre><code>integrity-metadata = *WSP hash-with-options *( 1*WSP hash-with-options ) *WSP / *WSP | ||
| +hash-with-options = hash-expression *("?" option-expression) | ||
| +option-expression = *VCHAR | ||
| +hash-algo = <hash-algo production from [Content Security Policy Level 2, section 4.2]> | ||
| +base64-value = <base64-value production from [Content Security Policy Level 2, section 4.2]> | ||
| +hash-expression = hash-algo "-" base64-value | ||
| +</code></pre> | ||
| + | ||
| + <p>The <code>integrity</code> IDL attribute must <a href="http://www.w3.org/TR/html5/infrastructure.html#reflect">reflect</a> the <code>integrity</code> content attribute.</p> | ||
| + | ||
| + <p><code>option-expression</code>s are associated on a per <code>hash-expression</code> basis and are | ||
| +applied only to the <code>hash-expression</code> that immediately precedes it.</p> | ||
| + | ||
| + <p>In order for user agents to remain fully forwards compatible with future | ||
| +options, the user agent MUST ignore all unrecognized <code>option-expression</code>s.</p> | ||
| + | ||
| + <p class="note">Note that while the <code>option-expression</code> has been reserved in the syntax, no | ||
| +options have been defined. It is likely that a future version of the spec will | ||
| +define a more specific syntax for options, so it is defined here as broadly | ||
| +as possible.</p> | ||
| + | ||
| + </section> | ||
| + <!-- /Framework::HTML::integrity --> | ||
| + | ||
| + <section> | ||
| + <h4 id="element-interface-extensions">Element interface extensions</h4> | ||
| + | ||
| + <section> | ||
| + <h5 id="htmllinkelement">HTMLLinkElement</h5> | ||
| + | ||
| + <dl title="partial interface HTMLLinkElement" class="idl"> | ||
| + <dt>attribute DOMString integrity</dt> | ||
| + <dd>The value of this element’s <code>integrity</code> attribute</dd> | ||
| + </dl> | ||
| + </section> | ||
| + <!-- /Framework::HTML::Interface extensions::HTMLLinkElement --> | ||
| + <section> | ||
| + <h5 id="htmlscriptelement">HTMLScriptElement</h5> | ||
| + | ||
| + <dl title="partial interface HTMLScriptElement" class="idl"> | ||
| + <dt>attribute DOMString integrity</dt> | ||
| + <dd>The value of this element’s <code>integrity</code> attribute</dd> | ||
| + </dl> | ||
| + </section> | ||
| + <!-- /Framework::HTML::Interface extensions::HTMLScriptElement --> | ||
| + </section> | ||
| + <!-- /Framework::HTML::Interface extensions --> | ||
| + <section> | ||
| + <h4 id="handling-integrity-violations">Handling integrity violations</h4> | ||
| + | ||
| + <p>The user agent will refuse to render or execute responses that fail an integrity | ||
| +check, instead returning a network error as defined in Fetch [[!FETCH]].</p> | ||
| + | ||
| + <p class="note">On a failed integrity check, an <code>error</code> event is fired. Developers | ||
| +wishing to provide a canonical fallback resource (e.g., a resource not served | ||
| +from a CDN, perhaps from a secondary, trusted, but slower source) can catch this | ||
| +<code>error</code> event and provide an appropriate handler to replace the | ||
| +failed resource with a different one.</p> | ||
| + | ||
| + </section> | ||
| + | ||
| + <section> | ||
| + <h5 id="elements">Elements</h5> | ||
| + | ||
| + <section> | ||
| + <h6 id="the-link-element-for-stylesheets">The <code>link</code> element for stylesheets</h6> | ||
| + | ||
| + <p>Whenever a user agent attempts to <a start="4" href="http://www.w3.org/TR/html5/document-metadata.html#concept-link-obtain">obtain a resource</a> pointed to by a | ||
| +<code>link</code> element that has a <code>rel</code> attribute with the keyword of <code>stylesheet</code>, | ||
| +modify step 4 to read:</p> | ||
| + | ||
| + <p>Do a potentially CORS-enabled fetch of the resulting absolute URL, with the | ||
| +mode being the current state of the element’s crossorigin content attribute, | ||
| +the origin being the origin of the link element’s Document, the default origin | ||
| +behavior set to taint, and the <a href="#dfn-integrity-metadata">integrity metadata</a> of the request set to the | ||
| +value of the element’s <code>integrity</code> attribute.</p> | ||
| + | ||
| + </section> | ||
| + <!-- /Framework::HTML::link --> | ||
| + | ||
| + <section> | ||
| + <h6 id="the-script-element">The <code>script</code> element</h6> | ||
| + | ||
| + <p>Replace step 14.1 of HTML5’s <a start="6" href="http://www.w3.org/TR/html5/scripting-1.html#prepare-a-script">“prepare a script” algorithm</a> with:</p> | ||
| + | ||
| + <ol> | ||
| + <li>Let <var>src</var> be the value of the element’s <code>src</code> attribute and | ||
| +the request’s associated <a href="#dfn-integrity-metadata">integrity metadata</a> be the value of the element’s | ||
| +<code>integrity</code> attribute.</li> | ||
| + </ol> | ||
| + | ||
| + </section> | ||
| + <!-- /Framework::HTML::Elements::script --> | ||
| + | ||
| + </section> | ||
| + <!-- /Framework::HTML::Elements --> | ||
| + | ||
| +</section> | ||
| +<!-- /Framework --> | ||
| + | ||
| +<section> | ||
| + <h2 id="proxies">Proxies</h2> | ||
| + | ||
| + <p>Optimizing proxies and other intermediate servers which modify the | ||
| +responses MUST ensure that the digest associated | ||
| +with those responses stays in sync with the new content. One option | ||
| +is to ensure that the <a href="#dfn-integrity-metadata">integrity metadata</a> associated with | ||
| +resources is updated. Another | ||
| +would be simply to deliver only the canonical version of resources | ||
| +for which a page author has requested integrity verification.</p> | ||
| + | ||
| + <p>To help inform intermediate servers, those serving the resources SHOULD | ||
| +send along with the resource a <a href="https://tools.ietf.org/html/rfc7234#section-5.2"><code>Cache-Control</code></a> header | ||
| +with a value of <a href="https://tools.ietf.org/html/rfc7234#section-5.2.1.6"><code>no-transform</code></a>.</p> | ||
| + | ||
| +</section> | ||
| +<!-- /Implementation --> | ||
| + | ||
| +<section class="informative"> | ||
| + <h2 id="security-considerations">Security Considerations</h2> | ||
| + | ||
| + <section> | ||
| + <h3 id="non-secure-contexts-remain-non-secure">Non-secure contexts remain non-secure</h3> | ||
| + | ||
| + <p><a href="#dfn-integrity-metadata">Integrity metadata</a> delivered by a context that is not a <a href="https://w3c.github.io/webappsec-secure-contexts/">Secure Context</a>, | ||
| +such as an HTTP page, only protects an origin against a compromise of the | ||
| +server where an external resources is hosted. Network attackers can alter the | ||
| +digest in-flight (or remove it entirely, or do absolutely anything else to the | ||
| +document), just as they could alter the response the hash is meant to validate. | ||
| +Thus, it is recommended that authors deliver integrity metadata only to a | ||
| +<a href="https://w3c.github.io/webappsec-secure-contexts/">Secure Context</a>. See also <a href="http://www.w3.org/2001/tag/doc/web-https">securing the web</a>.</p> | ||
| + | ||
| + </section> | ||
| + <!-- /Security::Non-secure contexts remain non-secure --> | ||
| + | ||
| + <section> | ||
| + <h3 id="hash-collision-attacks">Hash collision attacks</h3> | ||
| + | ||
| + <p>Digests are only as strong as the hash function used to generate them. It is | ||
| +recommended that user agents refuse to support known-weak hashing functions and | ||
| +limit supported algorithms to those known to be collision resistant. Examples of | ||
| +hashing functions that are not recommended include MD5 and SHA-1. At the time of | ||
| +writing, SHA-384 is a good baseline.</p> | ||
| + | ||
| + <p>Moreover, it is recommended that user agents re-evaluate their supported hash | ||
| +functions on a regular basis and deprecate support for those functions shown to | ||
| +be insecure. Over time, hash functions may be shown to be much weaker than | ||
| +expected and, in some cases, broken, so it is important that user agents stay | ||
| +aware of these developments.</p> | ||
| + | ||
| + </section> | ||
| + <!-- /Security::Hash collision --> | ||
| + | ||
| + <section> | ||
| + <h3 id="cross-origin-data-leakage">Cross-origin data leakage</h3> | ||
| + | ||
| + <p>This specification requires the <a href="http://www.w3.org/TR/html5/infrastructure.html#cors-settings-attributes">CORS settings attribute</a> to be present on | ||
| +integrity-protected cross-origin requests. If that requirement were omitted, | ||
| +attackers could violate the <a href="http://www.w3.org/Security/wiki/Same_Origin_Policy">same-origin policy</a> and determine whether | ||
| +a cross-origin resource has certain content.</p> | ||
| + | ||
| + <p>Attackers would attempt to load the resource with a known digest, and | ||
| +watch for load failures. If the load fails, the attacker could surmise | ||
| +that the response didn’t match the hash and thereby gain some insight into | ||
| +its contents. This might reveal, for example, whether or not a user is | ||
| +logged into a particular service.</p> | ||
| + | ||
| + <p>Moreover, attackers could brute-force specific values in an otherwise | ||
| +static resource. Consider a JSON response that looks like this:</p> | ||
| + | ||
| + <pre class="example"><code>{'status': 'authenticated', 'username': 'admin'} | ||
| +</code></pre> | ||
| + | ||
| + <p>An attacker could precompute hashes for the response with a variety of | ||
| +common usernames, and specify those hashes while repeatedly attempting | ||
| +to load the document. A successful load would confirm that the attacker | ||
| +has correctly guessed the username.</p> | ||
| + | ||
| + </section> | ||
| + <!-- /Security::cross-origin --> | ||
| + | ||
| +</section> | ||
| +<!-- /Security --> | ||
| + | ||
| +<section> | ||
| + <h2 id="acknowledgements">Acknowledgements</h2> | ||
| + | ||
| + <p>Much of the content here is inspired heavily by Gervase | ||
| +Markham’s <a href="http://www.gerv.net/security/link-fingerprints/">Link Fingerprints</a> concept, as well as WHATWG’s <a href="https://wiki.whatwg.org/wiki/Link_Hashes">Link Hashes</a>.</p> | ||
| + | ||
| + <p>A special thanks to Mike West of Google, Inc. for his invaluable contributions | ||
| +to the initial version of this spec. Additionally, Brad Hill, Anne van Kesteren, | ||
| +Jonathan Kingston, Mark Nottingham, Dan Veditz, Eduardo Vela, Tanvi Vyas, and | ||
| +Michal Zalewski provided invaluable feedback.</p> | ||
| + | ||
| +</section> | ||
| + | ||
| +</body> | ||
| +</html> |
0
spec.markdown → spec_v1.markdown
100755 → 100644
File renamed without changes.
0 comments on commit
7c4a2de