Permalink
Please sign in to comment.
Browse files
Merge pull request #27 from metromoxie/bikeshed-conversion-basic
Basic bikeshed conversion. Leaving bikeshed version in separate file until v1 spec is finalized.
- Loading branch information...
Showing
with
2,243 additions
and 1 deletion.
- +4 −1 Makefile
- +736 −0 default.css
- +687 −0 index.bikeshed.bs
- +816 −0 index.bikeshed.html
| @@ -1,11 +1,14 @@ | ||
| -all: clean index.html | ||
| +all: clean index.html index.bikeshed.html | ||
| clean: | ||
| rm -rf index.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.bikeshed.html: index.bikeshed.bs | ||
| + bikeshed -f spec ./index.bikeshed.bs | ||
| + | ||
| publish: all | ||
| git push origin master | ||
| git push origin master:gh-pages |
736
default.css
| @@ -0,0 +1,736 @@ | ||
| +/* | ||
| + * Style sheet for WebAppSec specifications (stolen wholesale from the CSSWG), | ||
| + * to be used in addition to http://www.w3.org/StyleSheets/TR/W3C-{WD,PR,REC} | ||
| + */ | ||
| + | ||
| +@media print { | ||
| + html { margin: 0 !important } | ||
| + body { font-family: serif } | ||
| + th, td { font-family: inherit } | ||
| + a { color: inherit !important } | ||
| + .example:before { font-family: serif !important } | ||
| + a:link, a:visited { text-decoration: none !important } | ||
| + a:link:after, a:visited:after { /* create a cross-ref "see..." */ } | ||
| +} | ||
| +@page { | ||
| + margin: 1.5cm 1.1cm; | ||
| +} | ||
| + | ||
| +body { | ||
| + counter-reset: exampleno figure issue; | ||
| + max-width: 50em; | ||
| + margin: 0 auto !important; | ||
| +} | ||
| + | ||
| +/* Pagination */ | ||
| +h1, h2, h3, h4, h5, h6 { page-break-after: avoid } | ||
| +figure, div.figure, div.sidefigure, pre, table.propdef, table.propdef-extra, | ||
| +.example { page-break-inside: avoid } | ||
| +dt { page-break-after: avoid } | ||
| + | ||
| +span.id {float: right; font-weight: bold} | ||
| + | ||
| +/* General Structural Markup */ | ||
| +h2, h3, h5, h6 { margin-top: 3em; } | ||
| + | ||
| +/* #subtitle is a subtitle in an H2 under the H1 */ | ||
| +h1 + h2, #subtitle + h2 { margin-top: 0; } | ||
| + | ||
| +h4 { margin-top: 4em; } | ||
| + | ||
| +h2 + h3, h3 + h4, h4 + h5, h5 + h6 { margin-top: 1.2em } | ||
| + | ||
| +hr:not([title]) { | ||
| + font-size: 1.5em; | ||
| + text-align: center; | ||
| + margin: 1em auto; | ||
| + border: transparent solid; | ||
| + background: transparent; | ||
| +} | ||
| +hr:not([title])::before { | ||
| + content: "\1F411\2003\2003\1F411\2003\2003\1F411"; | ||
| +} | ||
| + | ||
| +p, div.note, div.issue, details.why { | ||
| + margin-top: 1em; | ||
| + margin-bottom: 1em; | ||
| +} | ||
| + | ||
| +dd > p:first-child, li > p:first-child, .note > p:first-child, .issue > p:first-child { | ||
| + margin-top: 0 | ||
| +} | ||
| + | ||
| +pre { | ||
| + margin-top: 1em; | ||
| + margin-bottom: 1em; | ||
| +} | ||
| + | ||
| +pre, code { | ||
| + font-family: Menlo, Consolas, "DejaVu Sans Mono", monospace; | ||
| + font-size: .9em; | ||
| +} | ||
| + | ||
| +img { | ||
| + border-style: none; | ||
| + color: white; | ||
| +} | ||
| +.toc { | ||
| +} | ||
| + | ||
| +body { | ||
| + line-height: 1.5; | ||
| +} | ||
| + | ||
| +a.logo:link, a.logo:visited { | ||
| + padding: 0; | ||
| + border-style: none; | ||
| +} | ||
| + | ||
| +dl dd { margin: 0 0 1em 2em } | ||
| +.head dd { margin-bottom: 0; } | ||
| +ul, ol { margin-left: 0; padding-left: 2em; } | ||
| +li { margin: 0.25em 2em 0.5em 0; padding-left: 0 } | ||
| + | ||
| +ul.indexlist { margin-left: 0; columns: 13em; } | ||
| +ul.indexlist li { margin-left: 0; list-style: none } | ||
| +ul.indexlist li li { margin-left: 1em } | ||
| +ul.indexlist a { font-weight: bold; } | ||
| +ul.indexlist ul, ul.indexlist dl { font-size: smaller; } | ||
| +ul.indexlist dl { margin-top: 0; } | ||
| +ul.indexlist dt { margin: .2em 0 .2em 20px;} | ||
| +ul.indexlist dd { margin: .2em 0 .2em 40px;} | ||
| + | ||
| +/* .self-link is a link to the element */ | ||
| +.heading, .issue, .note, .example, li, dt { position: relative; } | ||
| +a.self-link { | ||
| + position: absolute; | ||
| + top: 0; | ||
| + left: -2.5em; | ||
| + width: 2em; | ||
| + height: 2em; | ||
| + text-align: center; | ||
| + border: none; | ||
| + transition: opacity .2s; | ||
| + opacity: .5; | ||
| +} | ||
| +a.self-link:hover { | ||
| + opacity: 1; | ||
| +} | ||
| +.heading > a.self-link { | ||
| + font-size: 83%; | ||
| +} | ||
| +li > a.self-link { | ||
| + left: -3.5em; | ||
| +} | ||
| +dfn > a.self-link { | ||
| + top: auto; | ||
| + left: auto; | ||
| + opacity: 0; | ||
| + width: 1.5em; | ||
| + height: 1.5em; | ||
| + background: gray; | ||
| + color: white; | ||
| + font-style: normal; | ||
| + transition: opacity .2s, background-color .2s, color .2s; | ||
| +} | ||
| +dfn:hover > a.self-link { | ||
| + opacity: 1; | ||
| +} | ||
| +dfn > a.self-link:hover { | ||
| + color: black; | ||
| +} | ||
| + | ||
| +a.self-link::before { content: "¶"; } | ||
| +.heading > a.self-link::before { content: "§"; } | ||
| +dfn > a.self-link::before { content: "#"; } | ||
| + | ||
| +/* Examples */ | ||
| + | ||
| +.example { | ||
| + counter-increment: exampleno; | ||
| +} | ||
| +.example:before { | ||
| + content: "Example"; | ||
| + content: "Example " counter(exampleno); | ||
| + min-width: 7.5em; | ||
| + text-transform: uppercase; | ||
| + display: block; | ||
| +} | ||
| +div.illegal-example:before, pre.illegal-example:before { | ||
| + content: "Invalid Example"; | ||
| + content: "Invalid Example" counter(exampleno); | ||
| +} | ||
| +.example, .illegal-example, div.html, div.illegal-html, div.xml, | ||
| +div.illegal-xml, pre.html, | ||
| +pre.illegal-html, pre.xml, pre.illegal-xml { | ||
| + padding: 0.5em; | ||
| + margin: 1em 0; | ||
| + position: relative; | ||
| + clear: both; | ||
| +} | ||
| +pre.example, pre.illegal-example, pre.html, | ||
| +pre.illegal-html, pre.xml, pre.illegal-xml { | ||
| + padding-top: 1.5em; | ||
| +} | ||
| +pre.illegal-example { color: red } | ||
| +div.illegal-example { color: red } | ||
| +div.illegal-example p { color: black } | ||
| + | ||
| +div.html { color: #600 } | ||
| +pre.html { color: #600 } | ||
| +pre.illegal-html { color: red } | ||
| +div.illegal-html { color: red } | ||
| +div.illegal-html p { color: black } | ||
| +pre.deprecated-html { color: red } | ||
| +div.deprecated-html { color: red } | ||
| +div.deprecated-html p { color: black } | ||
| + | ||
| +div.xml { color: #600 } | ||
| +pre.xml { color: #600 } | ||
| +pre.illegal-xml { color: red } | ||
| +div.illegal-xml { color: red } | ||
| +div.illegal-xml p { color: black } | ||
| + | ||
| +.css, .property { color: #005a9c } /* inline CSS code (SPAN/CODE) */ | ||
| +code.css { font-family: inherit; font-size: 100% } | ||
| +code.html { color: #600 } /* inline HTML */ | ||
| +code.xml { color: #600 } /* inline XML */ | ||
| +.property { font: inherit; white-space: nowrap; } /* name of a CSS property (SPAN) */ | ||
| +.descriptor { } /* name of a CSS descriptor (SPAN) */ | ||
| +.type { font-style: italic } /* A <type> value for a property */ | ||
| + | ||
| +/* Autolinks produced using Bikeshed. */ | ||
| +[data-link-type="property"]::before, | ||
| +[data-link-type="propdesc"]::before, | ||
| +[data-link-type="descriptor"]::before, | ||
| +[data-link-type="value"]::before, | ||
| +[data-link-type="function"]::before, | ||
| +[data-link-type="at-rule"]::before, | ||
| +[data-link-type="selector"]::before, | ||
| +[data-link-type="maybe"]::before {content: "\2018";} | ||
| +[data-link-type="property"]::after, | ||
| +[data-link-type="propdesc"]::after, | ||
| +[data-link-type="descriptor"]::after, | ||
| +[data-link-type="value"]::after, | ||
| +[data-link-type="function"]::after, | ||
| +[data-link-type="at-rule"]::after, | ||
| +[data-link-type="selector"]::after, | ||
| +[data-link-type="maybe"]::after {content: "\2019";} | ||
| +[data-link-type].production::before, | ||
| +[data-link-type].production::after, | ||
| +.prod [data-link-type]::before, | ||
| +.prod [data-link-type]::after { content: ""; } | ||
| + | ||
| + | ||
| +/* Element-type link styling */ | ||
| +[data-link-type=element] { font-family: monospace; } | ||
| +[data-link-type=element]::before { content: "<" } | ||
| +[data-link-type=element]::after { content: ">" } | ||
| + | ||
| +dfn { font-weight: bolder; } | ||
| + | ||
| +.issue, .note, .example, .why { | ||
| + padding: .5em; | ||
| + /* padding: .5rem; /* proposed unit in css3-values */ | ||
| + border-left-width: .5em; | ||
| + /* border-left-width: .5rem; /* proposed unit in css3-values */ | ||
| + border-left-style: solid; | ||
| +} | ||
| +span.note, span.issue { | ||
| + padding: .1em .5em .15em; | ||
| + border-right-width: .5em; | ||
| + border-right-style: solid; | ||
| +} | ||
| + | ||
| +/* Open issue / editorial remark; not intended for a final publication */ | ||
| +.issue { | ||
| + border-color: #E05252; | ||
| + background: #FBE9E9; | ||
| + counter-increment: issue; | ||
| + overflow: auto; | ||
| +} | ||
| + | ||
| +.issue:before { | ||
| + content: "Issue " counter(issue); | ||
| + padding-right: 1em; | ||
| + text-transform: uppercase; | ||
| + color: #E05252; | ||
| +} | ||
| + | ||
| +/* Class note is a non-normative note. May be inline or a P or DIV */ | ||
| +.note, .why { | ||
| + border-color: #52E052; | ||
| + background: #E9FBE9; | ||
| + overflow: auto; | ||
| +} | ||
| + | ||
| +.normref { color: red } | ||
| +.informref { color: green } | ||
| + | ||
| +/* Example box */ | ||
| +.example { | ||
| + border-color: #E0CB52; | ||
| + background: #FCFAEE; | ||
| + overflow: auto; | ||
| +} | ||
| + | ||
| +.example:before { | ||
| + color: #B9AB2D; | ||
| + font-family: sans-serif; | ||
| +} | ||
| + | ||
| +details.why { | ||
| + border-color: #52E052; | ||
| + background: #E9FBE9; | ||
| + display: block; | ||
| +} | ||
| + | ||
| +details.why > summary { | ||
| + font-style: italic; | ||
| + display: block; | ||
| +} | ||
| + | ||
| +details.why[open] > summary { | ||
| + border-bottom: 1px silver solid; | ||
| +} | ||
| + | ||
| +/* ToC not indented, but font style shows hierarchy */ | ||
| +ul.toc {margin: 1em 0; padding: 0; line-height: 1.3; font-weight: bold; /*text-transform: uppercase;*/ } | ||
| +ul.toc ul {margin: 0; padding: 0; font-weight: normal; text-transform: none; } | ||
| +ul.toc ul ul {margin: 0 0 0 2em; font-style: italic; } | ||
| +ul.toc ul ul ul {margin: 0} | ||
| +ul.toc > li {margin: 1.5em 0; padding: 0; } | ||
| +ul.toc ul.toc li { margin: 0.3em 0 0 0; } | ||
| +ul.toc a { text-decoration: none; border-bottom-style: none; } | ||
| +ul.toc a:hover, ul.toc a:focus { border-bottom-style: solid; } | ||
| +/* | ||
| +ul.toc li li li, ul.toc li li li ul {margin-left: 0; display: inline} | ||
| +ul.toc li li li ul, ul.toc li li li ul li {margin-left: 0; display: inline} | ||
| +*/ | ||
| + | ||
| +/* Section numbers in a column of their own */ | ||
| +ul.toc span.secno {float: left; width: 4em; margin-left: -5em} | ||
| +ul.toc ul ul span.secno { margin-left: -7em; } | ||
| +/*ul.toc span.secno {text-align: right}*/ | ||
| +ul.toc li {clear: both} | ||
| +ul.toc {margin-left: 5em} | ||
| +/* If we had 'tab', floats would not be needed here: | ||
| + ul.toc span.secno {tab: 5em right; margin-right: 1em} | ||
| + ul.toc li {text-indent: 5em hanging} | ||
| + The second line in case items wrap | ||
| +*/ | ||
| + | ||
| +ul.index { | ||
| + list-style: none; | ||
| +} | ||
| + | ||
| +s, del {text-decoration: line-through; color: red} | ||
| +u, ins {text-decoration: underline; color: #080} | ||
| + | ||
| +div.figure, p.figure, div.sidefigure, figure { | ||
| + text-align: center; | ||
| + margin: 2.5em 0; | ||
| +} | ||
| +div.figure pre, div.sidefigure pre, figure pre { | ||
| + text-align: left; | ||
| + display: table; | ||
| + margin: 1em auto; | ||
| +} | ||
| +.figure table, figure table { | ||
| + margin: auto; | ||
| +} | ||
| +div.sidefigure, figure.sidefigure { | ||
| + float: right; | ||
| + width: 50%; | ||
| + margin: 0 0 0.5em 0.5em | ||
| +} | ||
| +div.figure img, div.sidefigure img, figure img, | ||
| +div.figure object, div.sidefigure object, figure object { | ||
| + display: block; | ||
| + margin: auto; | ||
| + max-width: 100% | ||
| +} | ||
| +p.caption, figcaption, caption { | ||
| + text-align: center; | ||
| + font-style: italic; | ||
| + font-size: 90%; | ||
| +} | ||
| +p.caption:before, figcaption:before { | ||
| + content: "Figure " counter(figure) ". "; | ||
| + font-weight: bold; | ||
| +} | ||
| +p.caption, figcaption { | ||
| + counter-increment: figure; | ||
| +} | ||
| + | ||
| +/* DL list is indented, but figure inside it is not */ | ||
| +dd { margin-left: 2em } | ||
| +dd div.figure, dd figure { margin-left: -2em } | ||
| + | ||
| +sup { | ||
| + vertical-align: super; | ||
| + font-size: 80% | ||
| +} | ||
| + | ||
| +/* "Equations" (not real MathML, but simple HTML) are put in a | ||
| +blockquote and may have an equation number. We make sure the | ||
| +blockquote has enough margin on the right and then put the equation | ||
| +number there. */ | ||
| + | ||
| +blockquote { | ||
| + margin: 0.5em 4em 0.5em 2em; | ||
| + text-indent: 0; | ||
| +} | ||
| +.eqno { | ||
| + text-align: right; | ||
| + float: right; | ||
| + width: 3em; | ||
| + margin: 0 -4em 0 0; | ||
| + font-weight: bold; | ||
| + /* background: silver; color: black; padding: 0.1em */ | ||
| +} | ||
| + | ||
| +table.equiv-table { border-spacing: 0; margin: 0.5em 0 } | ||
| +table.equiv-table th, table.equiv-table td { padding: 0.3em } | ||
| +table.equiv-table th { text-align: left } | ||
| +/* table.equiv-table th:first-child { text-align: right } */ | ||
| +table.equiv-table td, table.equiv-table th { border-bottom: thin solid #666 } | ||
| +table.equiv-table { border-bottom: hidden } | ||
| +table.equiv-table { empty-cells: show } | ||
| +table.equiv-table caption { margin: 0.5em 0 0 0 } | ||
| + | ||
| +/* Style for table of properties */ | ||
| +table.proptable { | ||
| + font-size: small; | ||
| + border-collapse: collapse; | ||
| + border-spacing: 0; | ||
| + text-align: left; | ||
| + margin: 1em 0; | ||
| +} | ||
| + | ||
| +table.proptable td, table.proptable th { | ||
| + padding: 0.4em; | ||
| + text-align: center; | ||
| +} | ||
| + | ||
| +table.proptable tr:hover td { | ||
| + background: #DEF; | ||
| +} | ||
| + | ||
| + | ||
| +/* Style for table that defines a property or a descriptor */ | ||
| +table.propdef, table.propdef-extra, table.descdef, table.definition-table { | ||
| + border-spacing: 0; | ||
| + padding: 0 1em 0.5em; | ||
| + width: 100%; | ||
| + table-layout: fixed; | ||
| + background: #DEF; | ||
| + margin: 1.2em 0; | ||
| + border-left: 0.5em solid #8CCBF2; | ||
| +} | ||
| + | ||
| +table.propdef td, table.propdef-extra td, table.descdef td, table.definition-table td, | ||
| +table.propdef th, table.propdef-extra th, table.descdef th, table.definition-table th { | ||
| + padding: 0.5em; | ||
| + vertical-align: baseline; | ||
| + border-bottom: 1px solid #bbd7e9; | ||
| +} | ||
| +/* | ||
| +table.propdef dfn, table.propdef-extra dfn, table.descdef dfn { | ||
| + font-weight: bold; | ||
| + font-style: normal | ||
| +} | ||
| +*/ | ||
| + | ||
| +table.propdef td:first-child, | ||
| +table.propdef-extra td:first-child, | ||
| +table.descdef td:first-child, | ||
| +table.definition-table td:first-child, | ||
| +table.propdef th:first-child, | ||
| +table.propdef-extra th:first-child, | ||
| +table.descdef th:first-child, | ||
| +table.definition-table th:first-child { | ||
| + font-style: italic; | ||
| + font-weight: normal; | ||
| + width: 8.3em; | ||
| + padding-left: 1em; | ||
| +} | ||
| +table.propdef td[colspan]:first-child, | ||
| +table.propdef-extra td[colspan]:first-child, | ||
| +table.descdef td[colspan]:first-child, | ||
| +table.definition-table td[colspan]:first-child, | ||
| +table.propdef th[colspan]:first-child, | ||
| +table.propdef-extra th[colspan]:first-child, | ||
| +table.descdef th[colspan]:first-child, | ||
| +table.definition-table th[colspan]:first-child { | ||
| + font-style: inherit | ||
| +} | ||
| +table.propdef tr:first-child, | ||
| +table.propdef-extra tr:first-child, | ||
| +table.descdef tr:first-child, | ||
| +table.definition-table tr:first-child { | ||
| + | ||
| +} | ||
| + | ||
| +table.propdef > tbody > tr:last-child th, | ||
| +table.propdef-extra > tbody > tr:last-child th, | ||
| +table.descdef > tbody > tr:last-child th, | ||
| +table.definition-table > tbody > tr:last-child th, | ||
| +table.propdef > tbody > tr:last-child td, | ||
| +table.propdef-extra > tbody > tr:last-child td, | ||
| +table.descdef > tbody > tr:last-child td, | ||
| +table.definition-table > tbody > tr:last-child td { | ||
| + border-bottom: 0; | ||
| +} | ||
| + | ||
| +table.propdef tr:first-child th, | ||
| +table.propdef-extra tr:first-child th, | ||
| +table.descdef tr:first-child th, | ||
| +table.definition-table tr:first-child th, | ||
| +table.propdef tr:first-child td, | ||
| +table.propdef-extra tr:first-child td, | ||
| +table.descdef tr:first-child td, | ||
| +table.definition-table tr:first-child td { | ||
| + padding-top: 1em; | ||
| +} | ||
| + | ||
| +/* For when values are extra-complex and need formatting for readability */ | ||
| +table td.pre { | ||
| + white-space: pre-wrap; | ||
| +} | ||
| + | ||
| +/* A footnote at the bottom of a propdef */ | ||
| +table.propdef td.footnote, | ||
| +table.propdef-extra td.footnote, | ||
| +table.descdef td.footnote, | ||
| +table.definition-table td.footnote { | ||
| + padding-top: 0.6em; | ||
| + width: auto | ||
| +} | ||
| +table.propdef td.footnote:before, | ||
| +table.propdef-extra td.footnote:before, | ||
| +table.descdef td.footnote:before, | ||
| +table.definition-table td.footnote:before { | ||
| + content: " "; | ||
| + display: block; | ||
| + height: 0.6em; | ||
| + width: 4em; | ||
| + border-top: thin solid; | ||
| +} | ||
| + | ||
| +/* The link in the first column in the property table (formerly a TD) */ | ||
| +table.proptable td .property, | ||
| +table.proptable th .property { | ||
| + display: block; | ||
| + text-align: left; | ||
| + font-weight: bold; | ||
| +} | ||
| + | ||
| + | ||
| +/* Styling for IDL fragments */ | ||
| + | ||
| +pre.idl { | ||
| + padding: .5em 1em; | ||
| + background: #DEF; | ||
| + margin: 1.2em 0; | ||
| + border-left: 0.5em solid #8CCBF2; | ||
| +} | ||
| +pre.idl :link, pre.idl :visited { | ||
| + color:inherit; | ||
| + background:transparent; | ||
| +} | ||
| + | ||
| + | ||
| +/* CSS modules typically don't use MUST, SHOULD etc. from RFC 2119, | ||
| +or, if they do, they don't put them in uppercase. But the following | ||
| +class is provided in case a spec wants to use RFC 2119 terms in | ||
| +uppercase in the source. */ | ||
| + | ||
| +em.rfc2119 { | ||
| + text-transform: lowercase; | ||
| + font-variant: small-caps; | ||
| + font-style: normal | ||
| +} | ||
| + | ||
| +/* In Profile specs, a table of required features: */ | ||
| + | ||
| +table.features th { | ||
| + background: #00589f; | ||
| + color: #fff; | ||
| + text-align: left; | ||
| + padding: 0.2em 0.2em 0.2em 0.5em; | ||
| +} | ||
| +table.features td { | ||
| + vertical-align: top; | ||
| + border-bottom: 1px solid #ccc; | ||
| + padding: 0.3em 0.3em 0.3em 0.7em; | ||
| +} | ||
| + | ||
| + | ||
| +/* Style for data tables (and properly marked-up proptables) */ | ||
| + | ||
| +.data, .proptable { | ||
| + margin: 1em auto; | ||
| + border-collapse: collapse; | ||
| + width: 100%; | ||
| + border: hidden; | ||
| +} | ||
| +.data { | ||
| + text-align: center; | ||
| + width: auto; | ||
| +} | ||
| +.data caption { | ||
| + width: 100%; | ||
| +} | ||
| + | ||
| +.data td, .data th, | ||
| +.proptable td, .proptable th { | ||
| + padding: 0.5em; | ||
| + border-width: 1px; | ||
| + border-color: silver; | ||
| + border-top-style: solid; | ||
| +} | ||
| + | ||
| +.data thead td:empty { | ||
| + padding: 0; | ||
| + border: 0; | ||
| +} | ||
| + | ||
| +.data thead th[scope="row"], | ||
| +.proptable thead th[scope="row"] { | ||
| + text-align: right; | ||
| + color: inherit; | ||
| +} | ||
| + | ||
| +.data thead, | ||
| +.proptable thead, | ||
| +.data tbody, | ||
| +.proptable tbody { | ||
| + color: inherit; | ||
| + border-bottom: 2px solid; | ||
| +} | ||
| + | ||
| +.data colgroup { | ||
| + border-left: 2px solid; | ||
| +} | ||
| + | ||
| +.data tbody th:first-child, | ||
| +.proptable tbody th:first-child , | ||
| +.data tbody td[scope="row"]:first-child, | ||
| +.proptable tbody td[scope="row"]:first-child { | ||
| + text-align: right; | ||
| + color: inherit; | ||
| + border-right: 2px solid; | ||
| + border-top: 1px solid silver; | ||
| + padding-right: 1em; | ||
| +} | ||
| +.data.define td:last-child { | ||
| + text-align: left; | ||
| +} | ||
| + | ||
| +.data tbody th[rowspan], | ||
| +.proptable tbody th[rowspan], | ||
| +.data tbody td[rowspan], | ||
| +.proptable tbody td[rowspan]{ | ||
| + border-left: 1px solid silver; | ||
| +} | ||
| + | ||
| +.data tbody th[rowspan]:first-child, | ||
| +.proptable tbody th[rowspan]:first-child, | ||
| +.data tbody td[rowspan]:first-child, | ||
| +.proptable tbody td[rowspan]:first-child{ | ||
| + border-left: 0; | ||
| + border-right: 1px solid silver; | ||
| +} | ||
| + | ||
| +.complex.data th, | ||
| +.complex.data td { | ||
| + border: 1px solid silver; | ||
| +} | ||
| + | ||
| +.data td.long { | ||
| + vertical-align: baseline; | ||
| + text-align: left; | ||
| +} | ||
| + | ||
| +.data img { | ||
| + vertical-align: middle; | ||
| +} | ||
| + | ||
| +table.propdef { | ||
| + table-layout: auto; | ||
| +} | ||
| +.propdef th { | ||
| + font-style: italic; | ||
| + font-weight: normal; | ||
| + text-align: left; | ||
| + width: 3em; | ||
| +} | ||
| +dt dfn code { | ||
| + font-size: inherit; | ||
| +} | ||
| + | ||
| +/* Style for switch/case <dl>s */ | ||
| +dl.switch { | ||
| + padding-left: 2em; | ||
| +} | ||
| +dl.switch > dt { | ||
| + text-indent: -1.5em; | ||
| +} | ||
| +dl.switch > dt:before { | ||
| + content: '\21AA'; | ||
| + padding: 0 0.5em 0 0; | ||
| + display: inline-block; | ||
| + width: 1em; | ||
| + text-align: right; | ||
| + line-height: 0.5em; | ||
| +} | ||
| + | ||
| + | ||
| +/* Style for At Risk features (intended as editorial aid, not intended for publishing) */ | ||
| +.atrisk::before { | ||
| + position: absolute; | ||
| + margin-left: -5em; | ||
| + margin-top: -2px; | ||
| + padding: 4px; | ||
| + border: 1px solid; | ||
| + content: 'At risk'; | ||
| + font-size: small; | ||
| + background-color: white; | ||
| + color: gray; | ||
| + border-radius: 1em; | ||
| + text-align: center; | ||
| +} | ||
| + | ||
| +.toc .atrisk::before { content:none } | ||
| + | ||
| + | ||
| +/* This is mostly to make the list inside the CR exit criteria more compact. */ | ||
| +ol.inline, ol.inline li {display: inline; padding: 0; margin: 0} | ||
| +ol.inline {counter-reset: list-item} | ||
| +ol.inline li {counter-increment: list-item} | ||
| +ol.inline li:before {content: "(" counter(list-item) ") "; font-weight: bold} | ||
| + | ||
| +/* This styles the obsoletion notice on some of our older/abandoned specs. */ | ||
| +details.annoying-warning[open] { | ||
| + background: #fdd; | ||
| + color: red; | ||
| + font-weight: bold; | ||
| + text-align: center; | ||
| + padding: .5em; | ||
| + border: thick solid red; | ||
| + border-radius: 1em; | ||
| + position: fixed; | ||
| + left: 1em; | ||
| + right: 1em; | ||
| + bottom: 1em; | ||
| + z-index: 1000; | ||
| +} | ||
| + | ||
| +details.annoying-warning:not([open]) > summary { | ||
| + background: #fdd; | ||
| + color: red; | ||
| + font-weight: bold; | ||
| + text-align: center; | ||
| + padding: .5em; | ||
| +} |
| @@ -0,0 +1,687 @@ | ||
| +<pre class="metadata"> | ||
| +Title: Subresource Integrity | ||
| +Status: CR | ||
| +Deadline: 2015-12-15 | ||
| +ED: https://w3c.github.io/webappsec-subresource-integrity/ | ||
| +TR: http://www.w3.org/TR/SRI/ | ||
| +Previous Version: http://www.w3.org/TR/2015/WD-SRI-20151006/ | ||
| +Shortname: SRI | ||
| +Level: 1 | ||
| +Editor: Devdatta Akhawe, Dropbox Inc., http://devd.me, [email protected] | ||
| +Editor: Frederik Braun 68466, Mozilla, https://frederik-braun.com, [email protected] | ||
| +Editor: Francois Marier, Mozilla, https://fmarier.org, [email protected] | ||
| +Editor: Joel Weinberger, Google Inc., https://joelweinberger.us, [email protected] | ||
| +Abstract: | ||
| + This specification defines a mechanism by which user agents may verify that a | ||
| + fetched resource has been delivered without unexpected manipulation. | ||
| +Group: webappsec | ||
| +Repository: w3c/webappsec-subresource-integrity | ||
| +Indent: 2 | ||
| +Version History: https://github.com/w3c/webappsec-subresource-integrity/commits/gh-pages | ||
| +!Implementation status: <a href="https://code.google.com/p/chromium/issues/detail?id=355467">Blink/Chromium</a><br /><a href="https://bugzilla.mozilla.org/show_bug.cgi?id=992096">Gecko</a> | ||
| +!Implementation report: <a href="https://github.com/w3c/webappsec-subresource-integrity/wiki/Links">https://github.com/w3c/webappsec-subresource-integrity/wiki/Links</a> | ||
| + | ||
| +Markup Shorthands: css off, markdown on | ||
| +Ignored Vars: src, resource, val | ||
| +</pre> | ||
| + | ||
| +<pre class="anchors"> | ||
| +spec: ABNF; urlPrefix: https://tools.ietf.org/html/rfc5234 | ||
| + type: dfn | ||
| + text: VCHAR; url: appendix-B.1 | ||
| + text: WSP; url: appendix-B.1 | ||
| + type: grammar | ||
| + text: ALPHA; url: appendix-B.1 | ||
| + text: DIGIT; url: appendix-B.1 | ||
| + text: VCHAR; url: appendix-B.1 | ||
| + text: WSP; url: appendix-B.1 | ||
| + | ||
| +spec: Fetch; urlPrefix: https://fetch.spec.whatwg.org | ||
| + type: dfn | ||
| + text: fetch; url: concept-fetch | ||
| + text: request; url: concept-request | ||
| + text: response type; url: concept-response-type | ||
| + | ||
| +spec: HTML5; urlPrefix: http://www.w3.org/TR/html5/ | ||
| + type: dfn | ||
| + urlPrefix: document-metadata.html | ||
| + text: obtain a resource; url: #concept-link-obtain | ||
| + urlPrefix: infrastructure.html | ||
| + text: CORS settings attribute; url: #cors-settings-attributes | ||
| + text: reflect; url: #reflect | ||
| + text: split on spaces; url: #split-a-string-on-spaces | ||
| + urlPrefix: scripting-1.html | ||
| + text: prepare a script; url: #prepare-a-script | ||
| + | ||
| +spec: RFC7234; urlPrefix: https://tools.ietf.org/html/rfc7234 | ||
| + type: dfn | ||
| + text: Cache-Control; url: section-5.2 | ||
| + text: no-transform; url: section-5.2.1.6 | ||
| + | ||
| +spec: SECURE-CONTEXTS; urlPrefix: "http://www.w3.org/TR/powerful-features/" | ||
| + type: dfn | ||
| + text: Secure Context; urlPrefix: # | ||
| + | ||
| +spec: SHA2; urlPrefix: http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf | ||
| + type: dfn | ||
| + text: SHA-1; url: # | ||
| + text: SHA-2; url: # | ||
| + text: SHA-256; url: # | ||
| + text: SHA-384; url: # | ||
| + text: SHA-512; url: # | ||
| +</pre> | ||
| + | ||
| +<pre class="biblio"> | ||
| +{ | ||
| + "SECURE-CONTEXTS": { | ||
| + "authors": [ "Mike West", "Yan Zhu" ], | ||
| + "href": "https://w3c.github.io/webappsec-secure-contexts/", | ||
| + "title": "Secure Contexts", | ||
| + "status": "WD", | ||
| + "publisher": "W3C" | ||
| + }, | ||
| + "SHA2": { | ||
| + "href": "http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf", | ||
| + "title": "FIPS PUB 180-4, Secure Hash Standard" | ||
| + } | ||
| +} | ||
| +</pre> | ||
| + | ||
| +<!-- ####################################################################### --> | ||
| + | ||
| +# Introduction # {#intro} | ||
| + | ||
| +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 DNS [[RFC1035]] 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. | ||
| + | ||
| +Delivering resources over a secure channel mitigates some of this risk: with | ||
| +TLS [[TLS]], HSTS [[RFC6797]], and pinned public keys | ||
| +[[RFC7469]], 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. | ||
| + | ||
| +This document specifies such a validation scheme, extending two HTML elements | ||
| +with an `integrity` 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 | ||
| +`https://example.com/example-framework.js` | ||
| +is `Li9vy3DqF8tnTXuiaAJuML3ky+er10rcgNR/VqsVpcw+ThHmYcwiB1pbOxEbzJr7` 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. | ||
| + | ||
| +This example can be communicated to a user agent by adding the hash to a | ||
| +`script` element, like so: | ||
| + | ||
| +<div class="example"> | ||
| +<pre> | ||
| + <script src="https://example.com/example-framework.js" | ||
| + integrity="sha384-Li9vy3DqF8tnTXuiaAJuML3ky+er10rcgNR/VqsVpcw+ThHmYcwiB1pbOxEbzJr7" | ||
| + crossorigin="anonymous"></script> | ||
| +</pre> | ||
| +</div> | ||
| + | ||
| +Scripts, of course, are not the only response type which would benefit | ||
| +from integrity validation. The scheme specified here also applies to `link` | ||
| +and future versions of this specification are likely to expand this coverage. | ||
| + | ||
| +## Goals ## {#goals} | ||
| + | ||
| +1. 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. | ||
| + | ||
| +2. The verification mechanism should have error-reporting functionality which | ||
| + would inform the author that an invalid response was received. | ||
| + | ||
| +## Use Cases/Examples ## {#examples} | ||
| + | ||
| +### Resource Integrity ### {#resource-integrity} | ||
| + | ||
| +* 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>integrity metadata</a> is added to the `link` element included on the page: | ||
| + | ||
| + <div class="example"> | ||
| + <pre> | ||
| + <link rel="stylesheet" href="https://site53.example.net/style.css" | ||
| + integrity="sha384-+/M6kredJcxdsqkczBUjMLvqyHb1K/JThDXWsBVxMEeZHEaMKEOEct339VItX1zB" | ||
| + crossorigin="anonymous"> | ||
| + </pre> | ||
| + </div> | ||
| + | ||
| +* 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>integrity metadata</a> for | ||
| + the script, and adds it to the `script` element: | ||
| + | ||
| + <div class="example"> | ||
| + <pre> | ||
| + <script src="https://analytics-r-us.example.com/v1.0/include.js" | ||
| + integrity="sha384-MBO5IDfYaE6c6Aao94oZrIOiC6CGiSN2n4QUbHNPhzk5Xhm0djZLQqTpL0HzTUxk" | ||
| + crossorigin="anonymous"></script> | ||
| + </pre> | ||
| + </div> | ||
| + | ||
| +* 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>Integrity metadata</a> mitigates the risk that altered JavaScript will run | ||
| + in these pages' high-privilege contexts. | ||
| + | ||
| +<!-- ####################################################################### --> | ||
| + | ||
| +# Key Concepts and Terminology # {#terms} | ||
| + | ||
| +This section defines several terms used throughout the document. | ||
| + | ||
| +The term <dfn>digest</dfn> refers to the base64 encoded result of | ||
| +executing a cryptographic hash function on an arbitrary block of data. | ||
| + | ||
| +The terms <dfn>origin</dfn>, <dfn>cross-origin</dfn>, and <dfn>same-origin</dfn> | ||
| +are defined by the Origin specification. [[!ORIGIN]] | ||
| + | ||
| +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">Section 3 | ||
| +of RFC 7231</a>. [[!RFC7231]] | ||
| + | ||
| +A <dfn>base64 encoding</dfn> is defined in <a | ||
| +href="https://tools.ietf.org/html/rfc4648#section-4">Section 4 of RFC 4648</a>. | ||
| +[[!RFC4648]] | ||
| + | ||
| +The <a>SHA-256</a>, <a>SHA-384</a>, and <a>SHA-512</a> are part | ||
| +of the <a>SHA-2</a> set of cryptographic hash functions defined by the | ||
| +NIST. [[!SHA2]] | ||
| + | ||
| +## Grammatical Concepts ## {#grammar-concepts} | ||
| + | ||
| +The Augmented Backus-Naur Form (ABNF) notation used in this document is | ||
| +specified in RFC5234. [[!ABNF]] | ||
| + | ||
| +<a href="https://tools.ietf.org/html/rfc5234#appendix-B.1">Appendix B.1</a> of | ||
| +[[!ABNF]] defines <a>VCHAR</a> (printing characters). | ||
| + | ||
| +<a>WSP</a> (white space) characters are defined in <a href="http://www.w3.org/TR/html5/infrastructure.html#space-character">Section 2.4.1 Common parser idioms</a> of the HTML 5 specification as | ||
| +<code>White_Space characters</code>. [[!HTML5]] | ||
| + | ||
| +</section> | ||
| + | ||
| +<!-- ####################################################################### --> | ||
| + | ||
| +# Framework # {#framework} | ||
| + | ||
| +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. | ||
| + | ||
| +## Integrity metadata ## {#integrity-metadata-description} | ||
| + | ||
| +To verify the integrity of a response, a user agent requires <dfn>integrity | ||
| +metadata</dfn> as part of the <a>request</a>. This metadata consists of the | ||
| +following pieces of information: | ||
| + | ||
| +* cryptographic hash function ("alg") | ||
| +* <a>digest</a> ("val") | ||
| +* options ("opt") | ||
| + | ||
| +The hash function and digest MUST be provided in order to validate a | ||
| +response's integrity. | ||
| + | ||
| +Note: At the moment, no options are defined. However, future versions of | ||
| +the spec may define options, such as MIME types [[!MIME-TYPES]]. | ||
| + | ||
| +This metadata MUST be encoded in the same format as the `hash-source` (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>. | ||
| + | ||
| +For example, given a script resource containing only the string `alert(\'Hello, | ||
| +world.\');`, an author might choose <a>SHA-384</a> as a hash function. | ||
| +`H8BRh8j48O9oYatfu5AZzq6A9RINhZO5H16dQZngK7T62em8MUt1FLm52t+eX6xO` is the <a | ||
| +lt="base64 encoding">base64 encoded</a> digest that results. This can be encoded | ||
| +as follows: | ||
| + | ||
| +<div class="example"> | ||
| +<pre> | ||
| + sha384-H8BRh8j48O9oYatfu5AZzq6A9RINhZO5H16dQZngK7T62em8MUt1FLm52t+eX6xO | ||
| +</pre> | ||
| +</div> | ||
| + | ||
| +<div class="note"> | ||
| +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: | ||
| + | ||
| +<pre> | ||
| + echo -n "alert('Hello, world.');" | openssl dgst -sha384 -binary | openssl base64 -A | ||
| +</pre> | ||
| +</div> | ||
| + | ||
| +## Cryptographic hash functions ## {#hash-functions} | ||
| + | ||
| +Conformant user agents MUST support the <a>SHA-256</a>, <a>SHA-384</a>, | ||
| +and <a>SHA-512</a> cryptographic hash functions for use as part of a | ||
| +request's <a>integrity metadata</a> and MAY support additional hash functions. | ||
| + | ||
| +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 [[#hash-collision-attacks]]. | ||
| + | ||
| +### Agility ### {#agility} | ||
| + | ||
| +Multiple sets of <a>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: | ||
| + | ||
| +<div class="example"> | ||
| +<pre> | ||
| + sha384-dOTZf16X8p34q2/kYyEFm0jh89uTjikhnzjeLeF0FHsEaYKb1A1cv+Lyv4Hk8vHd | ||
| + sha512-Q2bFTOhEALkN8hOms2FKTDLy7eugP2zFZ1T8LCvX42Fp3WoNr3bjZSAHeOsHrbV1Fu9/A0EzCinRE7Af1ofPrw== | ||
| +</pre> | ||
| +</div> | ||
| + | ||
| +Authors may choose to specify both, for example: | ||
| + | ||
| +<div class="example"> | ||
| +<pre> | ||
| + <script src="hello_world.js" | ||
| + integrity="sha384-dOTZf16X8p34q2/kYyEFm0jh89uTjikhnzjeLeF0FHsEaYKb1A1cv+Lyv4Hk8vHd | ||
| + sha512-Q2bFTOhEALkN8hOms2FKTDLy7eugP2zFZ1T8LCvX42Fp3WoNr3bjZSAHeOsHrbV1Fu9/A0EzCinRE7Af1ofPrw==" | ||
| + crossorigin="anonymous"></script> | ||
| +</pre> | ||
| +</div> | ||
| + | ||
| +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 [[#parse-metadata]] and [[#get-the-strongest-metadata]] algorithms). | ||
| + | ||
| +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. | ||
| + | ||
| +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 [[#does-response-match-metadatalist]] algorithm below). | ||
| +Authors are encouraged to use strong hash functions, and to begin migrating to | ||
| +stronger hash functions as they become available. | ||
| + | ||
| +### Priority ### {#priority} | ||
| + | ||
| +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</dfn>(a, | ||
| +b) it would return the hash function the user agent considers the most | ||
| +collision-resistant. For example, `getPrioritizedHashFunction('sha256', | ||
| +'sha512')` would return `'sha512'` and `getPrioritizedHashFunction('sha256', | ||
| +'sha256')` would return the empty string. | ||
| + | ||
| +Note: The <a>getPrioritizedHashFunction</a> 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. | ||
| + | ||
| +## Response verification algorithms ## {#verification-algorithms} | ||
| + | ||
| +### Apply |algorithm| to |response| ### {#apply-algorithm-to-response} | ||
| + | ||
| +1. Let |result| be the result of [[#apply-algorithm-to-response]] | ||
| + to the <a>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 |result| be | ||
| + the result of applying |algorithm| to the <a>representation data</a>. | ||
| +2. Let |encodedResult| be result of <a>base64 encoding</a> |result|. | ||
| +3. Return |encodedResult|. | ||
| + | ||
| +### Is |response| eligible for integrity validation? ### {#is-response-eligible} | ||
| + | ||
| +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]]. | ||
| + | ||
| +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 `file` scheme URL are unlikely to be | ||
| +eligible for integrity checks. | ||
| + | ||
| +Note: Being in a <a>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 [[#non-secure-contexts]] for | ||
| +more discussion. | ||
| + | ||
| +The following algorithm details these restrictions: | ||
| + | ||
| +1. Let |response| be the response that results from | ||
| + <a lt="fetch">fetching</a> the |resource|. | ||
| +2. If the <a>|response| type</a> is `basic`, | ||
| + `cors` or `default`, return `true`. | ||
| +3. Return `false`. | ||
| + | ||
| +<div class="note"> | ||
| +The <a lt="response type">response types</a> are defined by the Fetch | ||
| +specification [[!FETCH]] and refer to the following: | ||
| + | ||
| +* `basic` is a <a>same-origin</a> response, and thus the requestor has full access | ||
| + to read the body. | ||
| +* `cors` is a valid response to a <a>cross-origin</a>, CORS-enabled request, and thus | ||
| + again the requestor has full access to read the body. | ||
| +* `default` 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. | ||
| + | ||
| +</div> | ||
| + | ||
| +Note: Since the <a>response type</a> for data URLs will always be "opaque" for | ||
| +`script` and `link` elements, such URLs are never eligible for integrity | ||
| +checks. Blob URLs on the other hand are usually considered <a>same-origin</a> | ||
| +and therefore are eligible for integrity checks. | ||
| + | ||
| +### Parse |metadata| ### {#parse-metadata} | ||
| + | ||
| +This algorithm accepts a string, and returns either `no metadata`, or a set of | ||
| +valid hash expressions whose hash functions are understood by | ||
| +the user agent. | ||
| + | ||
| +1. Let |result| be the empty set. | ||
| +2. Let |empty| be equal to `true`. | ||
| +3. For each |token| returned by <a lt="split on space">splitting |metadata| on | ||
| + spaces</a>: | ||
| + 1. Set |empty| to `false`. | ||
| + 2. If |token| is not a valid metadata, skip the remaining | ||
| + steps, and proceed to the next token. | ||
| + 3. Parse |token| per the grammar in <a>integrity metadata</a>. | ||
| + 4. Let |algorithm| be the |alg| component of | ||
| + |token|. | ||
| + 5. If |algorithm| is a hash function recognized by the user | ||
| + agent, add the parsed |token| to |result|. | ||
| +4. Return `no metadata` if |empty| is `true`, otherwise return | ||
| + |result|. | ||
| + | ||
| +### Get the strongest metadata from |set| ### {#get-the-strongest-metadata} | ||
| + | ||
| +1. Let |result| be the empty set and |strongest| be the empty | ||
| + string. | ||
| +2. For each |item| in |set|: | ||
| + 1. If |result| is the empty set, add |item| to | ||
| + |result| and set |strongest| to |item|, skip | ||
| + to the next |item|. | ||
| + 2. Let |currentAlgorithm| be the |alg| component of | ||
| + |strongest|. | ||
| + 3. Let |newAlgorithm| be the |alg| component of | ||
| + |item|. | ||
| + 4. If the result of <a lt="getPrioritizedHashFunction"> | ||
| + getPrioritizedHashFunction(|currentAlgorithm|, |newAlgorithm|)</a> | ||
| + is the empty string, add |item| to |result|. If the result is | ||
| + |newAlgorithm|, set |strongest| to |item|, set |result| to the empty | ||
| + set, and add |item| to |result|. | ||
| +3. Return |result|. | ||
| + | ||
| +### Does |response| match |metadataList|? ### {#does-response-match-metadatalist} | ||
| + | ||
| +1. Let |parsedMetadata| be the result of | ||
| + [parsing |metadataList|][parse]. | ||
| +2. If |parsedMetadata| is `no metadata`, return `true`. | ||
| +3. If <a href="#is-response-eligible">|response| is not eligible for integrity | ||
| + validation</a>, return `false`. | ||
| +4. If |parsedMetadata| is the empty set, return `true`. | ||
| +5. Let |metadata| be the result of <a href="#get-the-strongest-metadata"> | ||
| + getting the strongest metadata from |parsedMetadata|</a>. | ||
| +6. For each |item| in |metadata|: | ||
| + 1. Let |algorithm| be the |alg| component of | ||
| + |item|. | ||
| + 2. Let |expectedValue| be the |val| component of | ||
| + |item|. | ||
| + 3. Let |actualValue| be the result of <a | ||
| + href="#apply-algorithm-to-response">applying |algorithm| to |response| | ||
| + </a>. | ||
| + 4. If |actualValue| is a case-sensitive match for | ||
| + |expectedValue|, return `true`. | ||
| +7. Return `false`. | ||
| + | ||
| +This algorithm allows the user agent to accept multiple, valid strong hash | ||
| +functions. For example, a developer might write a `script` element such as: | ||
| + | ||
| +<div class="example"> | ||
| +<pre> | ||
| + <script src="https://example.com/example-framework.js" | ||
| + integrity="sha384-Li9vy3DqF8tnTXuiaAJuML3ky+er10rcgNR/VqsVpcw+ThHmYcwiB1pbOxEbzJr7 | ||
| + sha384-+/M6kredJcxdsqkczBUjMLvqyHb1K/JThDXWsBVxMEeZHEaMKEOEct339VItX1zB" | ||
| + crossorigin="anonymous"></script> | ||
| +</pre> | ||
| +</div> | ||
| + | ||
| +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. | ||
| + | ||
| +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. | ||
| + | ||
| +Note: This algorithm returns `false` if the response is not <a | ||
| +href="#is-response-eligible">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. | ||
| + | ||
| +## Verification of HTML document subresources ## {#verification-of-html-document-subresources} | ||
| + | ||
| +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 `integrity` attribute is added to | ||
| +the list of content attributes for the `link` and `script` elements. | ||
| + | ||
| +A corresponding `integrity` IDL attribute which <a>reflects</a> the | ||
| +value each element's `integrity` content attribute is added to the | ||
| +`HTMLLinkElement` and `HTMLScriptElement` interfaces. | ||
| + | ||
| +Note: A future revision of this specification is likely to include integrity support | ||
| +for all possible subresources, i.e., `a`, `audio`, `embed`, `iframe`, `img`, | ||
| +`link`, `object`, `script`, `source`, `track`, and `video` elements. | ||
| + | ||
| +## The `integrity` attribute ## {#the-integrity-attribute} | ||
| + | ||
| +The `integrity` attribute represents <a>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: | ||
| + | ||
| +<pre dfn-type="grammar" link-type="grammar"> | ||
| + <dfn>integrity-metadata</dfn> = *<a>WSP</a> <a>hash-with-options</a> *(1*<a>WSP</a> <a>hash-with-options</a> ) *<a>WSP</a> / *<a>WSP</a> | ||
| + <dfn>hash-with-options</dfn> = <a>hash-expression</a> *("?" <a>option-expression</a>) | ||
| + <dfn>option-expression</dfn> = *<a>VCHAR</a> | ||
| + <dfn>hash-algo</dfn> = <hash-algo production from [Content Security Policy Level 2, section 4.2]> | ||
| + <dfn>base64-value</dfn> = <base64-value production from [Content Security Policy Level 2, section 4.2]> | ||
| + <dfn>hash-expression</dfn> = <a>hash-algo</a> "-" <a>base64-value</a> | ||
| +</pre> | ||
| + | ||
| +The `integrity` IDL attribute must <a>reflect</a> the `integrity` content attribute. | ||
| + | ||
| +`option-expression`s are associated on a per `hash-expression` basis and are | ||
| +applied only to the `hash-expression` that immediately precedes it. | ||
| + | ||
| +In order for user agents to remain fully forwards compatible with future | ||
| +options, the user agent MUST ignore all unrecognized `option-expression`s. | ||
| + | ||
| +Note: Note that while the `option-expression` 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. | ||
| + | ||
| +## Element interface extensions ## {#interface-extensions} | ||
| + | ||
| +### HTMLLinkElement ### {#HTMLLinkElement} | ||
| + | ||
| +<pre class="idl"> | ||
| + partial interface HTMLLinkElement { | ||
| + attribute DOMString integrity; | ||
| + }; | ||
| +</pre> | ||
| + | ||
| +#### Attributes #### {#HTMLLinkElement-Attributes} | ||
| +<b>integrity</b> of type `DOMString`: The value of this element's integrity | ||
| +attribute. | ||
| + | ||
| +### HTMLScriptElement ### {#HTMLScriptElement} | ||
| +<pre class="idl"> | ||
| + partial interface HTMLScriptElement { | ||
| + attribute DOMString integrity; | ||
| + }; | ||
| +</pre> | ||
| + | ||
| +#### Attributes #### {#HTMLScriptElement-Attributes} | ||
| +<b>integrity</b> of type `DOMString`: The value of this element's integrity | ||
| +attribute. | ||
| + | ||
| +## Handling integrity violations ## {#handling-integrity-violations} | ||
| + | ||
| +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]]. | ||
| + | ||
| +Note: On a failed integrity check, an `error` 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 | ||
| +`error` event and provide an appropriate handler to replace the | ||
| +failed resource with a different one. | ||
| + | ||
| +## Elements ## {#elements} | ||
| + | ||
| +### The `link` element for stylesheets ### {#link-element-for-stylesheets} | ||
| + | ||
| +Whenever a user agent attempts to <a>obtain a resource</a> pointed to by a | ||
| +`link` element that has a `rel` attribute with the keyword of `stylesheet`, | ||
| +modify step 4 to read: | ||
| + | ||
| +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>integrity metadata</a> of the request set to | ||
| +the value of the element's `integrity` attribute. | ||
| + | ||
| +### The `script` element ### {#script-element} | ||
| + | ||
| +Replace step 14.1 of HTML5's <a>prepare a script</a> algorithm with: | ||
| + | ||
| +1. Let |src| be the value of the element's `src` attribute and | ||
| + the request's associated <a>integrity metadata</a> be the value of the | ||
| + element's `integrity` attribute. | ||
| + | ||
| +<!-- ####################################################################### --> | ||
| + | ||
| +# Proxies # {#proxies} | ||
| + | ||
| +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>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. | ||
| + | ||
| +To help inform intermediate servers, those serving the resources SHOULD | ||
| +send along with the resource a <a>`Cache-Control`</a> header | ||
| +with a value of <a>`no-transform`</a>. | ||
| + | ||
| +<!-- ####################################################################### --> | ||
| + | ||
| +# Security Considerations # {#security-considerations} | ||
| + | ||
| +<em> This section is not normative.</em> | ||
| + | ||
| +## Non-secure contexts remain non-secure ## {#non-secure-contexts} | ||
| + | ||
| +<a>Integrity metadata</a> delivered by a context that is not a <a>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>Secure Context</a>. See also <a | ||
| +href="http://www.w3.org/2001/tag/doc/web-https ">Securing the Web</a>. | ||
| + | ||
| +## Hash collision attacks ## {#hash-collision-attacks} | ||
| + | ||
| +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. | ||
| + | ||
| +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. | ||
| + | ||
| +## Cross-origin data leakage ## {#cross-origin-data-leakage} | ||
| + | ||
| +This specification requires the <a>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. | ||
| + | ||
| +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. | ||
| + | ||
| +Moreover, attackers could brute-force specific values in an otherwise | ||
| +static resource. Consider a JSON response that looks like this: | ||
| + | ||
| +<div class="example"> | ||
| +<pre> | ||
| + {'status': 'authenticated', 'username': 'admin'} | ||
| +</pre> | ||
| +</div> | ||
| + | ||
| +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. | ||
| + | ||
| +<!-- ####################################################################### --> | ||
| + | ||
| +# Acknowledgements # {#acknowledgements} | ||
| + | ||
| +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>. | ||
| + | ||
| +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. |
| @@ -0,0 +1,816 @@ | ||
| +<!doctype html><html lang="en"> | ||
| + <head> | ||
| + <meta content="text/html; charset=utf-8" http-equiv="Content-Type"> | ||
| + <title>Subresource Integrity</title> | ||
| + <link href="default.css" rel="stylesheet" type="text/css"> | ||
| + <link href="https://www.w3.org/StyleSheets/TR/W3C-CR" rel="stylesheet" type="text/css"> | ||
| + <meta content="Bikeshed 1.0.0" name="generator"> | ||
| + </head> | ||
| + <body class="h-entry"> | ||
| + <div class="head"> | ||
| + <p data-fill-with="logo"><a class="logo" href="http://www.w3.org/"> <img alt="W3C" height="48" src="https://www.w3.org/Icons/w3c_home" width="72"> </a> </p> | ||
| + <h1 class="p-name no-ref" id="title">Subresource Integrity</h1> | ||
| + <h2 class="no-num no-toc no-ref heading settled" id="subtitle"><span class="content">W3C Candidate Recommendation, <time class="dt-updated" datetime="2016-01-19">19 January 2016</time></span></h2> | ||
| + <div data-fill-with="spec-metadata"> | ||
| + <dl> | ||
| + <dt>This version: | ||
| + <dd><a class="u-url" href="http://www.w3.org/TR/2016/CR-SRI-1-20160119/">http://www.w3.org/TR/2016/CR-SRI-1-20160119/</a> | ||
| + <dt>Latest version: | ||
| + <dd><a href="http://www.w3.org/TR/SRI/">http://www.w3.org/TR/SRI/</a> | ||
| + <dt>Editor's Draft: | ||
| + <dd><a href="https://w3c.github.io/webappsec-subresource-integrity/">https://w3c.github.io/webappsec-subresource-integrity/</a> | ||
| + <dt>Previous Versions: | ||
| + <dd><a href="http://www.w3.org/TR/2015/WD-SRI-20151006/" rel="previous">http://www.w3.org/TR/2015/WD-SRI-20151006/</a> | ||
| + <dt>Version History: | ||
| + <dd><a href="https://github.com/w3c/webappsec-subresource-integrity/commits/gh-pages">https://github.com/w3c/webappsec-subresource-integrity/commits/gh-pages</a> | ||
| + <dt>Feedback: | ||
| + <dd><span><a href="mailto:[email protected]?subject=%5BSRI%5D%20YOUR%20TOPIC%20HERE">[email protected]</a> with subject line “<kbd>[SRI] <i data-lt="">… message topic …</i></kbd>” (<a href="http://lists.w3.org/Archives/Public/public-webappsec/" rel="discussion">archives</a>)</span> | ||
| + <dt>Issue Tracking: | ||
| + <dd><a href="https://github.com/w3c/webappsec-subresource-integrity/issues/">GitHub</a> | ||
| + <dt class="editor">Editors: | ||
| + <dd class="editor p-author h-card vcard"><a class="p-name fn u-url url" href="http://devd.me">Devdatta Akhawe</a> (<span class="p-org org">Dropbox Inc.</span>) <a class="u-email email" href="mailto:[email protected]">[email protected]</a> | ||
| + <dd class="editor p-author h-card vcard" data-editor-id="68466"><a class="p-name fn u-url url" href="https://frederik-braun.com">Frederik Braun</a> (<span class="p-org org">Mozilla</span>) <a class="u-email email" href="mailto:[email protected]">[email protected]</a> | ||
| + <dd class="editor p-author h-card vcard"><a class="p-name fn u-url url" href="https://fmarier.org">Francois Marier</a> (<span class="p-org org">Mozilla</span>) <a class="u-email email" href="mailto:[email protected]">[email protected]</a> | ||
| + <dd class="editor p-author h-card vcard"><a class="p-name fn u-url url" href="https://joelweinberger.us">Joel Weinberger</a> (<span class="p-org org">Google Inc.</span>) <a class="u-email email" href="mailto:[email protected]">[email protected]</a> | ||
| + <dt>Implementation status: | ||
| + <dd><span><a href="https://code.google.com/p/chromium/issues/detail?id=355467">Blink/Chromium</a><br><a href="https://bugzilla.mozilla.org/show_bug.cgi?id=992096">Gecko</a></span> | ||
| + <dt>Implementation report: | ||
| + <dd><span><a href="https://github.com/w3c/webappsec-subresource-integrity/wiki/Links">https://github.com/w3c/webappsec-subresource-integrity/wiki/Links</a></span> | ||
| + <dd><span></span> | ||
| + </dl> | ||
| + </div> | ||
| + <div data-fill-with="warning"></div> | ||
| + <p class="copyright" data-fill-with="copyright"><a href="http://www.w3.org/Consortium/Legal/ipr-notice#Copyright">Copyright</a> © 2016 <a href="http://www.w3.org/"><abbr title="World Wide Web Consortium">W3C</abbr></a><sup>®</sup> (<a href="http://www.csail.mit.edu/"><abbr title="Massachusetts Institute of Technology">MIT</abbr></a>, <a href="http://www.ercim.eu/"><abbr title="European Research Consortium for Informatics and Mathematics">ERCIM</abbr></a>, <a href="http://www.keio.ac.jp/">Keio</a>, <a href="http://ev.buaa.edu.cn/">Beihang</a>). W3C <a href="http://www.w3.org/Consortium/Legal/ipr-notice#Legal_Disclaimer">liability</a>, <a href="http://www.w3.org/Consortium/Legal/ipr-notice#W3C_Trademarks">trademark</a> and <a href="http://www.w3.org/Consortium/Legal/copyright-documents">document use</a> rules apply. </p> | ||
| + <hr title="Separator for header"> | ||
| + </div> | ||
| + <h2 class="no-num no-toc no-ref heading settled" id="abstract"><span class="content">Abstract</span></h2> | ||
| + <div class="p-summary" data-fill-with="abstract"> | ||
| + <p>This specification defines a mechanism by which user agents may verify that a | ||
| + | ||
| +fetched resource has been delivered without unexpected manipulation.</p> | ||
| + </div> | ||
| + <h2 class="no-num no-toc no-ref heading settled" id="status"><span class="content">Status of this document</span></h2> | ||
| + <div data-fill-with="status"> | ||
| + <p> <em>This section describes the status of this document at the time of | ||
| + its publication. Other documents may supersede this document. A list of | ||
| + current W3C publications and the latest revision of this technical report | ||
| + can be found in the <a href="http://www.w3.org/TR/">W3C technical reports | ||
| + index at http://www.w3.org/TR/.</a></em> </p> | ||
| + <p> This document was published by the <a href="http://www.w3.org/2011/webappsec/">Web Application Security Working Group</a> as a Candidate Recommendation. This document is intended to become a W3C Recommendation. | ||
| + This document will remain a Candidate Recommendation at least until <time class="status-deadline" datetime="2015-12-15">15 December 2015</time> in order | ||
| + to ensure the opportunity for wide review. </p> | ||
| + <p> The (<a href="http://lists.w3.org/Archives/Public/public-webappsec/">archived</a>) public mailing list <a href="mailto:[email protected]?Subject=%5BSRI%5D%20PUT%20SUBJECT%20HERE">[email protected]</a> (see <a href="http://www.w3.org/Mail/Request">instructions</a>) | ||
| + is preferred for discussion of this specification. | ||
| + When sending e-mail, | ||
| + please put the text “SRI” in the subject, | ||
| + preferably like this: | ||
| + “[SRI] <em>…summary of comment…</em>” </p> | ||
| + <p> Publication as a Candidate Recommendation does not imply endorsement by the W3C | ||
| + Membership. This is a draft document and may be updated, replaced or | ||
| + obsoleted by other documents at any time. It is inappropriate to cite this | ||
| + document as other than work in progress. </p> | ||
| + <p> The entrance criteria for this document to enter the Proposed Recommendation stage | ||
| + is to have a minimum of two independent and interoperable user agents that | ||
| + implement all the features of this specification, which will be determined by | ||
| + passing the user agent tests defined in the test suite developed by the Working | ||
| + Group. The Working Group will prepare an implementation report to track progress. </p> | ||
| + <p> This document was produced by a group operating under | ||
| + the <a href="http://www.w3.org/Consortium/Patent-Policy-20040205/">5 February 2004 W3C Patent Policy</a>. | ||
| + W3C maintains a <a href="http://www.w3.org/2004/01/pp-impl/49309/status" rel="disclosure">public list of any patent disclosures</a> made in connection with the deliverables of the group; | ||
| + that page also includes instructions for disclosing a patent. | ||
| + An individual who has actual knowledge of a patent which the individual believes contains <a href="http://www.w3.org/Consortium/Patent-Policy-20040205/#def-essential">Essential Claim(s)</a> must disclose the information in accordance with <a href="http://www.w3.org/Consortium/Patent-Policy-20040205/#sec-Disclosure">section 6 of the W3C Patent Policy</a>. </p> | ||
| + <p> This document is governed by the <a href="http://www.w3.org/2015/Process-20150901/" id="w3c_process_revision">1 September 2015 W3C Process Document</a>. </p> | ||
| + <p></p> | ||
| + </div> | ||
| + <div data-fill-with="at-risk"></div> | ||
| + <h2 class="no-num no-toc no-ref heading settled" id="contents"><span class="content">Table of Contents</span></h2> | ||
| + <div data-fill-with="table-of-contents" role="navigation"> | ||
| + <ul class="toc" role="directory"> | ||
| + <li> | ||
| + <a href="#intro"><span class="secno">1</span> <span class="content">Introduction</span></a> | ||
| + <ul class="toc"> | ||
| + <li><a href="#goals"><span class="secno">1.1</span> <span class="content">Goals</span></a> | ||
| + <li> | ||
| + <a href="#examples"><span class="secno">1.2</span> <span class="content">Use Cases/Examples</span></a> | ||
| + <ul class="toc"> | ||
| + <li><a href="#resource-integrity"><span class="secno">1.2.1</span> <span class="content">Resource Integrity</span></a> | ||
| + </ul> | ||
| + </ul> | ||
| + <li> | ||
| + <a href="#terms"><span class="secno">2</span> <span class="content">Key Concepts and Terminology</span></a> | ||
| + <ul class="toc"> | ||
| + <li><a href="#grammar-concepts"><span class="secno">2.1</span> <span class="content">Grammatical Concepts</span></a> | ||
| + </ul> | ||
| + <li> | ||
| + <a href="#framework"><span class="secno">3</span> <span class="content">Framework</span></a> | ||
| + <ul class="toc"> | ||
| + <li><a href="#integrity-metadata-description"><span class="secno">3.1</span> <span class="content">Integrity metadata</span></a> | ||
| + <li> | ||
| + <a href="#hash-functions"><span class="secno">3.2</span> <span class="content">Cryptographic hash functions</span></a> | ||
| + <ul class="toc"> | ||
| + <li><a href="#agility"><span class="secno">3.2.1</span> <span class="content">Agility</span></a> | ||
| + <li><a href="#priority"><span class="secno">3.2.2</span> <span class="content">Priority</span></a> | ||
| + </ul> | ||
| + <li> | ||
| + <a href="#verification-algorithms"><span class="secno">3.3</span> <span class="content">Response verification algorithms</span></a> | ||
| + <ul class="toc"> | ||
| + <li><a href="#apply-algorithm-to-response"><span class="secno">3.3.1</span> <span class="content">Apply <var>algorithm</var> to <var>response</var></span></a> | ||
| + <li><a href="#is-response-eligible"><span class="secno">3.3.2</span> <span class="content">Is <var>response</var> eligible for integrity validation?</span></a> | ||
| + <li><a href="#parse-metadata"><span class="secno">3.3.3</span> <span class="content">Parse <var>metadata</var></span></a> | ||
| + <li><a href="#get-the-strongest-metadata"><span class="secno">3.3.4</span> <span class="content">Get the strongest metadata from <var>set</var></span></a> | ||
| + <li><a href="#does-response-match-metadatalist"><span class="secno">3.3.5</span> <span class="content">Does <var>response</var> match <var>metadataList</var>?</span></a> | ||
| + </ul> | ||
| + <li><a href="#verification-of-html-document-subresources"><span class="secno">3.4</span> <span class="content">Verification of HTML document subresources</span></a> | ||
| + <li><a href="#the-integrity-attribute"><span class="secno">3.5</span> <span class="content">The <code>integrity</code> attribute</span></a> | ||
| + <li> | ||
| + <a href="#interface-extensions"><span class="secno">3.6</span> <span class="content">Element interface extensions</span></a> | ||
| + <ul class="toc"> | ||
| + <li> | ||
| + <a href="#HTMLLinkElement"><span class="secno">3.6.1</span> <span class="content">HTMLLinkElement</span></a> | ||
| + <ul class="toc"> | ||
| + <li><a href="#HTMLLinkElement-Attributes"><span class="secno">3.6.1.1</span> <span class="content">Attributes</span></a> | ||
| + </ul> | ||
| + <li> | ||
| + <a href="#HTMLScriptElement"><span class="secno">3.6.2</span> <span class="content">HTMLScriptElement</span></a> | ||
| + <ul class="toc"> | ||
| + <li><a href="#HTMLScriptElement-Attributes"><span class="secno">3.6.2.1</span> <span class="content">Attributes</span></a> | ||
| + </ul> | ||
| + </ul> | ||
| + <li><a href="#handling-integrity-violations"><span class="secno">3.7</span> <span class="content">Handling integrity violations</span></a> | ||
| + <li> | ||
| + <a href="#elements"><span class="secno">3.8</span> <span class="content">Elements</span></a> | ||
| + <ul class="toc"> | ||
| + <li><a href="#link-element-for-stylesheets"><span class="secno">3.8.1</span> <span class="content">The <code>link</code> element for stylesheets</span></a> | ||
| + <li><a href="#script-element"><span class="secno">3.8.2</span> <span class="content">The <code>script</code> element</span></a> | ||
| + </ul> | ||
| + </ul> | ||
| + <li><a href="#proxies"><span class="secno">4</span> <span class="content">Proxies</span></a> | ||
| + <li> | ||
| + <a href="#security-considerations"><span class="secno">5</span> <span class="content">Security Considerations</span></a> | ||
| + <ul class="toc"> | ||
| + <li><a href="#non-secure-contexts"><span class="secno">5.1</span> <span class="content">Non-secure contexts remain non-secure</span></a> | ||
| + <li><a href="#hash-collision-attacks"><span class="secno">5.2</span> <span class="content">Hash collision attacks</span></a> | ||
| + <li><a href="#cross-origin-data-leakage"><span class="secno">5.3</span> <span class="content">Cross-origin data leakage</span></a> | ||
| + </ul> | ||
| + <li><a href="#acknowledgements"><span class="secno">6</span> <span class="content">Acknowledgements</span></a> | ||
| + <li> | ||
| + <a href="#conformance"><span class="secno"></span> <span class="content">Conformance</span></a> | ||
| + <ul class="toc"> | ||
| + <li><a href="#conventions"><span class="secno"></span> <span class="content">Document conventions</span></a> | ||
| + <li><a href="#conformant-algorithms"><span class="secno"></span> <span class="content">Conformant Algorithms</span></a> | ||
| + </ul> | ||
| + <li> | ||
| + <a href="#index"><span class="secno"></span> <span class="content">Index</span></a> | ||
| + <ul class="toc"> | ||
| + <li><a href="#index-defined-here"><span class="secno"></span> <span class="content">Terms defined by this specification</span></a> | ||
| + <li><a href="#index-defined-elsewhere"><span class="secno"></span> <span class="content">Terms defined by reference</span></a> | ||
| + </ul> | ||
| + <li> | ||
| + <a href="#references"><span class="secno"></span> <span class="content">References</span></a> | ||
| + <ul class="toc"> | ||
| + <li><a href="#normative"><span class="secno"></span> <span class="content">Normative References</span></a> | ||
| + <li><a href="#informative"><span class="secno"></span> <span class="content">Informative References</span></a> | ||
| + </ul> | ||
| + <li><a href="#idl-index"><span class="secno"></span> <span class="content">IDL Index</span></a> | ||
| + </ul> | ||
| + </div> | ||
| + <main> | ||
| + <h2 class="heading settled" data-level="1" id="intro"><span class="secno">1. </span><span class="content">Introduction</span><a class="self-link" href="#intro"></a></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 DNS <a data-link-type="biblio" href="#biblio-rfc1035">[RFC1035]</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 | ||
| +TLS <a data-link-type="biblio" href="#biblio-tls">[TLS]</a>, HSTS <a data-link-type="biblio" href="#biblio-rfc6797">[RFC6797]</a>, and pinned public keys <a data-link-type="biblio" href="#biblio-rfc7469">[RFC7469]</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> | ||
| + <div class="example" id="example-2cf8cb15"> | ||
| + <a class="self-link" href="#example-2cf8cb15"></a> | ||
| +<pre><script src="https://example.com/example-framework.js" | ||
| + integrity="sha384-Li9vy3DqF8tnTXuiaAJuML3ky+er10rcgNR/VqsVpcw+ThHmYcwiB1pbOxEbzJr7" | ||
| + crossorigin="anonymous"></script> | ||
| +</pre> | ||
| + </div> | ||
| + <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> | ||
| + <h3 class="heading settled" data-level="1.1" id="goals"><span class="secno">1.1. </span><span class="content">Goals</span><a class="self-link" href="#goals"></a></h3> | ||
| + <ol> | ||
| + <li data-md=""> | ||
| + <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 data-md=""> | ||
| + <p>The verification mechanism should have error-reporting functionality which | ||
| + would inform the author that an invalid response was received.</p> | ||
| + </ol> | ||
| + <h3 class="heading settled" data-level="1.2" id="examples"><span class="secno">1.2. </span><span class="content">Use Cases/Examples</span><a class="self-link" href="#examples"></a></h3> | ||
| + <h4 class="heading settled" data-level="1.2.1" id="resource-integrity"><span class="secno">1.2.1. </span><span class="content">Resource Integrity</span><a class="self-link" href="#resource-integrity"></a></h4> | ||
| + <ul> | ||
| + <li data-md=""> | ||
| + <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 data-link-type="dfn" href="#integrity-metadata">integrity metadata</a> is added to the <code>link</code> element included on the page:</p> | ||
| + <div class="example" id="example-f65c13cd"> | ||
| + <a class="self-link" href="#example-f65c13cd"></a> | ||
| +<pre><link rel="stylesheet" href="https://site53.example.net/style.css" | ||
| + integrity="sha384-+/M6kredJcxdsqkczBUjMLvqyHb1K/JThDXWsBVxMEeZHEaMKEOEct339VItX1zB" | ||
| + crossorigin="anonymous"> | ||
| +</pre> | ||
| + </div> | ||
| + <li data-md=""> | ||
| + <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 data-link-type="dfn" href="#integrity-metadata">integrity metadata</a> for | ||
| + the script, and adds it to the <code>script</code> element:</p> | ||
| + <div class="example" id="example-dbcf36cc"> | ||
| + <a class="self-link" href="#example-dbcf36cc"></a> | ||
| +<pre><script src="https://analytics-r-us.example.com/v1.0/include.js" | ||
| + integrity="sha384-MBO5IDfYaE6c6Aao94oZrIOiC6CGiSN2n4QUbHNPhzk5Xhm0djZLQqTpL0HzTUxk" | ||
| + crossorigin="anonymous"></script> | ||
| +</pre> | ||
| + </div> | ||
| + <li data-md=""> | ||
| + <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 data-link-type="dfn" href="#integrity-metadata">Integrity metadata</a> mitigates the risk that altered JavaScript will run | ||
| + in these pages' high-privilege contexts.</p> | ||
| + </ul> | ||
| + <h2 class="heading settled" data-level="2" id="terms"><span class="secno">2. </span><span class="content">Key Concepts and Terminology</span><a class="self-link" href="#terms"></a></h2> | ||
| + <p>This section defines several terms used throughout the document.</p> | ||
| + <p>The term <dfn data-dfn-type="dfn" data-noexport="" id="digest">digest<a class="self-link" href="#digest"></a></dfn> refers to the base64 encoded result of | ||
| +executing a cryptographic hash function on an arbitrary block of data.</p> | ||
| + <p>The terms <dfn data-dfn-type="dfn" data-noexport="" id="origin">origin<a class="self-link" href="#origin"></a></dfn>, <dfn data-dfn-type="dfn" data-noexport="" id="cross-origin">cross-origin<a class="self-link" href="#cross-origin"></a></dfn>, and <dfn data-dfn-type="dfn" data-noexport="" id="same-origin">same-origin<a class="self-link" href="#same-origin"></a></dfn> are defined by the Origin specification. <a data-link-type="biblio" href="#biblio-origin">[ORIGIN]</a></p> | ||
| + <p>The <dfn data-dfn-type="dfn" data-noexport="" id="representation-data">representation data<a class="self-link" href="#representation-data"></a></dfn> and <dfn data-dfn-type="dfn" data-noexport="" id="content-encoding">content encoding<a class="self-link" href="#content-encoding"></a></dfn> of a resource | ||
| +are defined by <a href="https://tools.ietf.org/html/rfc7231#section-3">Section 3 | ||
| +of RFC 7231</a>. <a data-link-type="biblio" href="#biblio-rfc7231">[RFC7231]</a></p> | ||
| + <p>A <dfn data-dfn-type="dfn" data-noexport="" id="base64-encoding">base64 encoding<a class="self-link" href="#base64-encoding"></a></dfn> is defined in <a href="https://tools.ietf.org/html/rfc4648#section-4">Section 4 of RFC 4648</a>. <a data-link-type="biblio" href="#biblio-rfc4648">[RFC4648]</a></p> | ||
| + <p>The <a data-link-type="dfn" href="http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf#">SHA-256</a>, <a data-link-type="dfn" href="http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf#">SHA-384</a>, and <a data-link-type="dfn" href="http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf#">SHA-512</a> are part | ||
| +of the <a data-link-type="dfn" href="http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf#">SHA-2</a> set of cryptographic hash functions defined by the | ||
| +NIST. <a data-link-type="biblio" href="#biblio-sha2">[SHA2]</a></p> | ||
| + <h3 class="heading settled" data-level="2.1" id="grammar-concepts"><span class="secno">2.1. </span><span class="content">Grammatical Concepts</span><a class="self-link" href="#grammar-concepts"></a></h3> | ||
| + <p>The Augmented Backus-Naur Form (ABNF) notation used in this document is | ||
| +specified in RFC5234. <a data-link-type="biblio" href="#biblio-abnf">[ABNF]</a></p> | ||
| + <p><a href="https://tools.ietf.org/html/rfc5234#appendix-B.1">Appendix B.1</a> of <a data-link-type="biblio" href="#biblio-abnf">[ABNF]</a> defines <a data-link-type="dfn" href="https://tools.ietf.org/html/rfc5234#appendix-B.1">VCHAR</a> (printing characters).</p> | ||
| + <p><a data-link-type="dfn" href="https://tools.ietf.org/html/rfc5234#appendix-B.1">WSP</a> (white space) characters are defined in <a href="http://www.w3.org/TR/html5/infrastructure.html#space-character">Section 2.4.1 Common parser idioms</a> of the HTML 5 specification as <code>White_Space characters</code>. <a data-link-type="biblio" href="#biblio-html5">[HTML5]</a></p> | ||
| + <h2 class="heading settled" data-level="3" id="framework"><span class="secno">3. </span><span class="content">Framework</span><a class="self-link" href="#framework"></a></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> | ||
| + <h3 class="heading settled" data-level="3.1" id="integrity-metadata-description"><span class="secno">3.1. </span><span class="content">Integrity metadata</span><a class="self-link" href="#integrity-metadata-description"></a></h3> | ||
| + <p>To verify the integrity of a response, a user agent requires <dfn data-dfn-type="dfn" data-noexport="" id="integrity-metadata">integrity | ||
| +metadata<a class="self-link" href="#integrity-metadata"></a></dfn> as part of the <a data-link-type="dfn" href="https://fetch.spec.whatwg.org#concept-request">request</a>. This metadata consists of the | ||
| +following pieces of information:</p> | ||
| + <ul> | ||
| + <li data-md=""> | ||
| + <p>cryptographic hash function ("alg")</p> | ||
| + <li data-md=""> | ||
| + <p><a data-link-type="dfn" href="#digest">digest</a> ("val")</p> | ||
| + <li data-md=""> | ||
| + <p>options ("opt")</p> | ||
| + </ul> | ||
| + <p>The hash function and digest MUST be provided in order to validate a | ||
| +response’s integrity.</p> | ||
| + <p class="note" role="note">Note: At the moment, no options are defined. However, future versions of | ||
| +the spec may define options, such as MIME types <a data-link-type="biblio" href="#biblio-mime-types">[MIME-TYPES]</a>.</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 data-link-type="dfn" href="http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf#">SHA-384</a> as a hash function. <code>H8BRh8j48O9oYatfu5AZzq6A9RINhZO5H16dQZngK7T62em8MUt1FLm52t+eX6xO</code> is the <a data-link-type="dfn" href="#base64-encoding">base64 encoded</a> digest that results. This can be encoded | ||
| +as follows:</p> | ||
| + <div class="example" id="example-da8c6097"> | ||
| + <a class="self-link" href="#example-da8c6097"></a> | ||
| +<pre>sha384-H8BRh8j48O9oYatfu5AZzq6A9RINhZO5H16dQZngK7T62em8MUt1FLm52t+eX6xO | ||
| +</pre> | ||
| + </div> | ||
| + <div class="note" role="note"> | ||
| + 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: | ||
| +<pre>echo -n "alert('Hello, world.');" | openssl dgst -sha384 -binary | openssl base64 -A | ||
| +</pre> | ||
| + </div> | ||
| + <h3 class="heading settled" data-level="3.2" id="hash-functions"><span class="secno">3.2. </span><span class="content">Cryptographic hash functions</span><a class="self-link" href="#hash-functions"></a></h3> | ||
| + <p>Conformant user agents MUST support the <a data-link-type="dfn" href="http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf#">SHA-256</a>, <a data-link-type="dfn" href="http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf#">SHA-384</a>, | ||
| +and <a data-link-type="dfn" href="http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf#">SHA-512</a> cryptographic hash functions for use as part of a | ||
| +request’s <a data-link-type="dfn" href="#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">§5.2 Hash collision attacks</a>.</p> | ||
| + <h4 class="heading settled" data-level="3.2.1" id="agility"><span class="secno">3.2.1. </span><span class="content">Agility</span><a class="self-link" href="#agility"></a></h4> | ||
| + <p>Multiple sets of <a data-link-type="dfn" href="#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> | ||
| + <div class="example" id="example-9e091bdc"> | ||
| + <a class="self-link" href="#example-9e091bdc"></a> | ||
| +<pre>sha384-dOTZf16X8p34q2/kYyEFm0jh89uTjikhnzjeLeF0FHsEaYKb1A1cv+Lyv4Hk8vHd | ||
| +sha512-Q2bFTOhEALkN8hOms2FKTDLy7eugP2zFZ1T8LCvX42Fp3WoNr3bjZSAHeOsHrbV1Fu9/A0EzCinRE7Af1ofPrw== | ||
| +</pre> | ||
| + </div> | ||
| + <p>Authors may choose to specify both, for example:</p> | ||
| + <div class="example" id="example-ffb16d19"> | ||
| + <a class="self-link" href="#example-ffb16d19"></a> | ||
| +<pre><script src="hello_world.js" | ||
| + integrity="sha384-dOTZf16X8p34q2/kYyEFm0jh89uTjikhnzjeLeF0FHsEaYKb1A1cv+Lyv4Hk8vHd | ||
| + sha512-Q2bFTOhEALkN8hOms2FKTDLy7eugP2zFZ1T8LCvX42Fp3WoNr3bjZSAHeOsHrbV1Fu9/A0EzCinRE7Af1ofPrw==" | ||
| + crossorigin="anonymous"></script> | ||
| +</pre> | ||
| + </div> | ||
| + <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">§3.3.3 Parse metadata</a> and <a href="#get-the-strongest-metadata">§3.3.4 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">§3.3.5 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> | ||
| + <h4 class="heading settled" data-level="3.2.2" id="priority"><span class="secno">3.2.2. </span><span class="content">Priority</span><a class="self-link" href="#priority"></a></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 data-dfn-type="dfn" data-noexport="" id="getprioritizedhashfunction">getPrioritizedHashFunction<a class="self-link" href="#getprioritizedhashfunction"></a></dfn>(a, | ||
| +b) 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" role="note">Note: The <a data-link-type="dfn" href="#getprioritizedhashfunction">getPrioritizedHashFunction</a> 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> | ||
| + <h3 class="heading settled" data-level="3.3" id="verification-algorithms"><span class="secno">3.3. </span><span class="content">Response verification algorithms</span><a class="self-link" href="#verification-algorithms"></a></h3> | ||
| + <h4 class="heading settled" data-level="3.3.1" id="apply-algorithm-to-response"><span class="secno">3.3.1. </span><span class="content">Apply <var>algorithm</var> to <var>response</var></span><a class="self-link" href="#apply-algorithm-to-response"></a></h4> | ||
| + <ol> | ||
| + <li data-md=""> | ||
| + <p>Let <var>result</var> be the result of <a href="#apply-algorithm-to-response">§3.3.1 Apply algorithm to response</a> to the <a data-link-type="dfn" href="#representation-data">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 data-link-type="dfn" href="#representation-data">representation data</a>.</p> | ||
| + <li data-md=""> | ||
| + <p>Let <var>encodedResult</var> be result of <a data-link-type="dfn" href="#base64-encoding">base64 encoding</a> <var>result</var>.</p> | ||
| + <li data-md=""> | ||
| + <p>Return <var>encodedResult</var>.</p> | ||
| + </ol> | ||
| + <h4 class="heading settled" data-level="3.3.2" id="is-response-eligible"><span class="secno">3.3.2. </span><span class="content">Is <var>response</var> eligible for integrity validation?</span><a class="self-link" href="#is-response-eligible"></a></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 <a data-link-type="biblio" href="#biblio-cors">[CORS]</a>.</p> | ||
| + <p class="note" role="note">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" role="note">Note: Being in a <a data-link-type="dfn" href=""http://www.w3.org/TR/powerful-features/"#secure-context">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">§5.1 Non-secure contexts remain non-secure</a> for | ||
| +more discussion.</p> | ||
| + <p>The following algorithm details these restrictions:</p> | ||
| + <ol> | ||
| + <li data-md=""> | ||
| + <p>Let <var>response</var> be the response that results from <a data-link-type="dfn" href="https://fetch.spec.whatwg.org#concept-fetch">fetching</a> the <var>resource</var>.</p> | ||
| + <li data-md=""> | ||
| + <p>If the <a data-link-type="dfn" href="https://fetch.spec.whatwg.org#concept-response-type"><var>response</var> type</a> is <code>basic</code>, <code>cors</code> or <code>default</code>, return <code>true</code>.</p> | ||
| + <li data-md=""> | ||
| + <p>Return <code>false</code>.</p> | ||
| + </ol> | ||
| + <div class="note" role="note"> | ||
| + The <a data-link-type="dfn" href="https://fetch.spec.whatwg.org#concept-response-type">response types</a> are defined by the Fetch | ||
| +specification <a data-link-type="biblio" href="#biblio-fetch">[FETCH]</a> and refer to the following: | ||
| + <ul> | ||
| + <li data-md=""> | ||
| + <p><code>basic</code> is a <a data-link-type="dfn" href="#same-origin">same-origin</a> response, and thus the requestor has full access | ||
| +to read the body.</p> | ||
| + <li data-md=""> | ||
| + <p><code>cors</code> is a valid response to a <a data-link-type="dfn" href="#cross-origin">cross-origin</a>, CORS-enabled request, and thus | ||
| +again the requestor has full access to read the body.</p> | ||
| + <li data-md=""> | ||
| + <p><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.</p> | ||
| + </ul> | ||
| + </div> | ||
| + <p class="note" role="note">Note: Since the <a data-link-type="dfn" href="https://fetch.spec.whatwg.org#concept-response-type">response type</a> for data URLs will always be "opaque" for <code>script</code> and <code>link</code> elements, such URLs are never eligible for integrity | ||
| +checks. Blob URLs on the other hand are usually considered <a data-link-type="dfn" href="#same-origin">same-origin</a> and therefore are eligible for integrity checks.</p> | ||
| + <h4 class="heading settled" data-level="3.3.3" id="parse-metadata"><span class="secno">3.3.3. </span><span class="content">Parse <var>metadata</var></span><a class="self-link" href="#parse-metadata"></a></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 data-md=""> | ||
| + <p>Let <var>result</var> be the empty set.</p> | ||
| + <li data-md=""> | ||
| + <p>Let <var>empty</var> be equal to <code>true</code>.</p> | ||
| + <li data-md=""> | ||
| + <p>For each <var>token</var> returned by <a data-link-type="dfn" href="http://www.w3.org/TR/html5/infrastructure.html#split-a-string-on-spaces">splitting <var>metadata</var> on | ||
| + spaces</a>:</p> | ||
| + <ol> | ||
| + <li data-md=""> | ||
| + <p>Set <var>empty</var> to <code>false</code>.</p> | ||
| + <li data-md=""> | ||
| + <p>If <var>token</var> is not a valid metadata, skip the remaining | ||
| + steps, and proceed to the next token.</p> | ||
| + <li data-md=""> | ||
| + <p>Parse <var>token</var> per the grammar in <a data-link-type="dfn" href="#integrity-metadata">integrity metadata</a>.</p> | ||
| + <li data-md=""> | ||
| + <p>Let <var>algorithm</var> be the <var>alg</var> component of <var>token</var>.</p> | ||
| + <li data-md=""> | ||
| + <p>If <var>algorithm</var> is a hash function recognized by the user | ||
| + agent, add the parsed <var>token</var> to <var>result</var>.</p> | ||
| + </ol> | ||
| + <li data-md=""> | ||
| + <p>Return <code>no metadata</code> if <var>empty</var> is <code>true</code>, otherwise return <var>result</var>.</p> | ||
| + </ol> | ||
| + <h4 class="heading settled" data-level="3.3.4" id="get-the-strongest-metadata"><span class="secno">3.3.4. </span><span class="content">Get the strongest metadata from <var>set</var></span><a class="self-link" href="#get-the-strongest-metadata"></a></h4> | ||
| + <ol> | ||
| + <li data-md=""> | ||
| + <p>Let <var>result</var> be the empty set and <var>strongest</var> be the empty | ||
| + string.</p> | ||
| + <li data-md=""> | ||
| + <p>For each <var>item</var> in <var>set</var>:</p> | ||
| + <ol> | ||
| + <li data-md=""> | ||
| + <p>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>.</p> | ||
| + <li data-md=""> | ||
| + <p>Let <var>currentAlgorithm</var> be the <var>alg</var> component of <var>strongest</var>.</p> | ||
| + <li data-md=""> | ||
| + <p>Let <var>newAlgorithm</var> be the <var>alg</var> component of <var>item</var>.</p> | ||
| + <li data-md=""> | ||
| + <p>If the result of <a data-link-type="dfn" href="#getprioritizedhashfunction"> getPrioritizedHashFunction(<var>currentAlgorithm</var>, <var>newAlgorithm</var>)</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>.</p> | ||
| + </ol> | ||
| + <li data-md=""> | ||
| + <p>Return <var>result</var>.</p> | ||
| + </ol> | ||
| + <h4 class="heading settled" data-level="3.3.5" id="does-response-match-metadatalist"><span class="secno">3.3.5. </span><span class="content">Does <var>response</var> match <var>metadataList</var>?</span><a class="self-link" href="#does-response-match-metadatalist"></a></h4> | ||
| + <ol> | ||
| + <li data-md=""> | ||
| + <p>Let <var>parsedMetadata</var> be the result of | ||
| + [parsing <var>metadataList</var>][parse].</p> | ||
| + <li data-md=""> | ||
| + <p>If <var>parsedMetadata</var> is <code>no metadata</code>, return <code>true</code>.</p> | ||
| + <li data-md=""> | ||
| + <p>If <a href="#is-response-eligible"><var>response</var> is not eligible for integrity | ||
| + validation</a>, return <code>false</code>.</p> | ||
| + <li data-md=""> | ||
| + <p>If <var>parsedMetadata</var> is the empty set, return <code>true</code>.</p> | ||
| + <li data-md=""> | ||
| + <p>Let <var>metadata</var> be the result of <a href="#get-the-strongest-metadata"> getting the strongest metadata from <var>parsedMetadata</var></a>.</p> | ||
| + <li data-md=""> | ||
| + <p>For each <var>item</var> in <var>metadata</var>:</p> | ||
| + <ol> | ||
| + <li data-md=""> | ||
| + <p>Let <var>algorithm</var> be the <var>alg</var> component of <var>item</var>.</p> | ||
| + <li data-md=""> | ||
| + <p>Let <var>expectedValue</var> be the <var>val</var> component of <var>item</var>.</p> | ||
| + <li data-md=""> | ||
| + <p>Let <var>actualValue</var> be the result of <a href="#apply-algorithm-to-response">applying <var>algorithm</var> to <var>response</var> </a>.</p> | ||
| + <li data-md=""> | ||
| + <p>If <var>actualValue</var> is a case-sensitive match for <var>expectedValue</var>, return <code>true</code>.</p> | ||
| + </ol> | ||
| + <li data-md=""> | ||
| + <p>Return <code>false</code>.</p> | ||
| + </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> | ||
| + <div class="example" id="example-a26a9f25"> | ||
| + <a class="self-link" href="#example-a26a9f25"></a> | ||
| +<pre><script src="https://example.com/example-framework.js" | ||
| + integrity="sha384-Li9vy3DqF8tnTXuiaAJuML3ky+er10rcgNR/VqsVpcw+ThHmYcwiB1pbOxEbzJr7 | ||
| + sha384-+/M6kredJcxdsqkczBUjMLvqyHb1K/JThDXWsBVxMEeZHEaMKEOEct339VItX1zB" | ||
| + crossorigin="anonymous"></script> | ||
| +</pre> | ||
| + </div> | ||
| + <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" role="note">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" role="note">Note: This algorithm returns <code>false</code> if the response is not <a href="#is-response-eligible">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> | ||
| + <h3 class="heading settled" data-level="3.4" id="verification-of-html-document-subresources"><span class="secno">3.4. </span><span class="content">Verification of HTML document subresources</span><a class="self-link" href="#verification-of-html-document-subresources"></a></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 data-link-type="dfn" 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" role="note">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> | ||
| + <h3 class="heading settled" data-level="3.5" id="the-integrity-attribute"><span class="secno">3.5. </span><span class="content">The <code>integrity</code> attribute</span><a class="self-link" href="#the-integrity-attribute"></a></h3> | ||
| + <p>The <code>integrity</code> attribute represents <a data-link-type="dfn" href="#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><dfn data-dfn-type="grammar" data-export="" id="grammardef-integrity-metadata">integrity-metadata<a class="self-link" href="#grammardef-integrity-metadata"></a></dfn> = *<a data-link-type="grammar" href="https://tools.ietf.org/html/rfc5234#appendix-B.1">WSP</a> <a data-link-type="grammar" href="#grammardef-hash-with-options">hash-with-options</a> *(1*<a data-link-type="grammar" href="https://tools.ietf.org/html/rfc5234#appendix-B.1">WSP</a> <a data-link-type="grammar" href="#grammardef-hash-with-options">hash-with-options</a> ) *<a data-link-type="grammar" href="https://tools.ietf.org/html/rfc5234#appendix-B.1">WSP</a> / *<a data-link-type="grammar" href="https://tools.ietf.org/html/rfc5234#appendix-B.1">WSP</a> | ||
| +<dfn data-dfn-type="grammar" data-export="" id="grammardef-hash-with-options">hash-with-options<a class="self-link" href="#grammardef-hash-with-options"></a></dfn> = <a data-link-type="grammar" href="#grammardef-hash-expression">hash-expression</a> *("?" <a data-link-type="grammar" href="#grammardef-option-expression">option-expression</a>) | ||
| +<dfn data-dfn-type="grammar" data-export="" id="grammardef-option-expression">option-expression<a class="self-link" href="#grammardef-option-expression"></a></dfn> = *<a data-link-type="grammar" href="https://tools.ietf.org/html/rfc5234#appendix-B.1">VCHAR</a> | ||
| +<dfn data-dfn-type="grammar" data-export="" id="grammardef-hash-algo">hash-algo<a class="self-link" href="#grammardef-hash-algo"></a></dfn> = <hash-algo production from [Content Security Policy Level 2, section 4.2]> | ||
| +<dfn data-dfn-type="grammar" data-export="" id="grammardef-base64-value">base64-value<a class="self-link" href="#grammardef-base64-value"></a></dfn> = <base64-value production from [Content Security Policy Level 2, section 4.2]> | ||
| +<dfn data-dfn-type="grammar" data-export="" id="grammardef-hash-expression">hash-expression<a class="self-link" href="#grammardef-hash-expression"></a></dfn> = <a data-link-type="grammar" href="#grammardef-hash-algo">hash-algo</a> "-" <a data-link-type="grammar" href="#grammardef-base64-value">base64-value</a> | ||
| +</pre> | ||
| + <p>The <code>integrity</code> IDL attribute must <a data-link-type="dfn" 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" role="note">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> | ||
| + <h3 class="heading settled" data-level="3.6" id="interface-extensions"><span class="secno">3.6. </span><span class="content">Element interface extensions</span><a class="self-link" href="#interface-extensions"></a></h3> | ||
| + <h4 class="heading settled" data-level="3.6.1" id="HTMLLinkElement"><span class="secno">3.6.1. </span><span class="content">HTMLLinkElement</span><a class="self-link" href="#HTMLLinkElement"></a></h4> | ||
| +<pre class="idl">partial interface <a class="idl-code" data-link-type="interface" href="https://html.spec.whatwg.org/multipage/semantics.html#htmllinkelement">HTMLLinkElement</a> { | ||
| + attribute DOMString <dfn class="idl-code" data-dfn-for="HTMLLinkElement" data-dfn-type="attribute" data-export="" data-type="DOMString " id="dom-htmllinkelement-integrity">integrity<a class="self-link" href="#dom-htmllinkelement-integrity"></a></dfn>; | ||
| +}; | ||
| +</pre> | ||
| + <h5 class="heading settled" data-level="3.6.1.1" id="HTMLLinkElement-Attributes"><span class="secno">3.6.1.1. </span><span class="content">Attributes</span><a class="self-link" href="#HTMLLinkElement-Attributes"></a></h5> | ||
| + <b>integrity</b> of type <code>DOMString</code>: The value of this element’s integrity | ||
| +attribute. | ||
| + <h4 class="heading settled" data-level="3.6.2" id="HTMLScriptElement"><span class="secno">3.6.2. </span><span class="content">HTMLScriptElement</span><a class="self-link" href="#HTMLScriptElement"></a></h4> | ||
| +<pre class="idl">partial interface <a class="idl-code" data-link-type="interface" href="https://html.spec.whatwg.org/multipage/scripting.html#htmlscriptelement">HTMLScriptElement</a> { | ||
| + attribute DOMString <dfn class="idl-code" data-dfn-for="HTMLScriptElement" data-dfn-type="attribute" data-export="" data-type="DOMString " id="dom-htmlscriptelement-integrity">integrity<a class="self-link" href="#dom-htmlscriptelement-integrity"></a></dfn>; | ||
| +}; | ||
| +</pre> | ||
| + <h5 class="heading settled" data-level="3.6.2.1" id="HTMLScriptElement-Attributes"><span class="secno">3.6.2.1. </span><span class="content">Attributes</span><a class="self-link" href="#HTMLScriptElement-Attributes"></a></h5> | ||
| + <b>integrity</b> of type <code>DOMString</code>: The value of this element’s integrity | ||
| +attribute. | ||
| + <h3 class="heading settled" data-level="3.7" id="handling-integrity-violations"><span class="secno">3.7. </span><span class="content">Handling integrity violations</span><a class="self-link" href="#handling-integrity-violations"></a></h3> | ||
| + <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 <a data-link-type="biblio" href="#biblio-fetch">[FETCH]</a>.</p> | ||
| + <p class="note" role="note">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> | ||
| + <h3 class="heading settled" data-level="3.8" id="elements"><span class="secno">3.8. </span><span class="content">Elements</span><a class="self-link" href="#elements"></a></h3> | ||
| + <h4 class="heading settled" data-level="3.8.1" id="link-element-for-stylesheets"><span class="secno">3.8.1. </span><span class="content">The <code>link</code> element for stylesheets</span><a class="self-link" href="#link-element-for-stylesheets"></a></h4> | ||
| + <p>Whenever a user agent attempts to <a data-link-type="dfn" 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 data-link-type="dfn" href="#integrity-metadata">integrity metadata</a> of the request set to | ||
| +the value of the element’s <code>integrity</code> attribute.</p> | ||
| + <h4 class="heading settled" data-level="3.8.2" id="script-element"><span class="secno">3.8.2. </span><span class="content">The <code>script</code> element</span><a class="self-link" href="#script-element"></a></h4> | ||
| + <p>Replace step 14.1 of HTML5’s <a data-link-type="dfn" href="http://www.w3.org/TR/html5/scripting-1.html#prepare-a-script">prepare a script</a> algorithm with:</p> | ||
| + <ol> | ||
| + <li data-md=""> | ||
| + <p>Let <var>src</var> be the value of the element’s <code>src</code> attribute and | ||
| + the request’s associated <a data-link-type="dfn" href="#integrity-metadata">integrity metadata</a> be the value of the | ||
| + element’s <code>integrity</code> attribute.</p> | ||
| + </ol> | ||
| + <h2 class="heading settled" data-level="4" id="proxies"><span class="secno">4. </span><span class="content">Proxies</span><a class="self-link" href="#proxies"></a></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 data-link-type="dfn" href="#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 data-link-type="dfn" href="https://tools.ietf.org/html/rfc7234#section-5.2"><code>Cache-Control</code></a> header | ||
| +with a value of <a data-link-type="dfn" href="https://tools.ietf.org/html/rfc7234#section-5.2.1.6"><code>no-transform</code></a>.</p> | ||
| + <h2 class="heading settled" data-level="5" id="security-considerations"><span class="secno">5. </span><span class="content">Security Considerations</span><a class="self-link" href="#security-considerations"></a></h2> | ||
| + <p><em> This section is not normative.</em></p> | ||
| + <h3 class="heading settled" data-level="5.1" id="non-secure-contexts"><span class="secno">5.1. </span><span class="content">Non-secure contexts remain non-secure</span><a class="self-link" href="#non-secure-contexts"></a></h3> | ||
| + <p><a data-link-type="dfn" href="#integrity-metadata">Integrity metadata</a> delivered by a context that is not a <a data-link-type="dfn" href=""http://www.w3.org/TR/powerful-features/"#secure-context">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 data-link-type="dfn" href=""http://www.w3.org/TR/powerful-features/"#secure-context">Secure Context</a>. See also <a href="http://www.w3.org/2001/tag/doc/web-https ">Securing the Web</a>.</p> | ||
| + <h3 class="heading settled" data-level="5.2" id="hash-collision-attacks"><span class="secno">5.2. </span><span class="content">Hash collision attacks</span><a class="self-link" href="#hash-collision-attacks"></a></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> | ||
| + <h3 class="heading settled" data-level="5.3" id="cross-origin-data-leakage"><span class="secno">5.3. </span><span class="content">Cross-origin data leakage</span><a class="self-link" href="#cross-origin-data-leakage"></a></h3> | ||
| + <p>This specification requires the <a data-link-type="dfn" 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> | ||
| + <div class="example" id="example-7e9bf81f"> | ||
| + <a class="self-link" href="#example-7e9bf81f"></a> | ||
| +<pre>{'status': 'authenticated', 'username': 'admin'} | ||
| +</pre> | ||
| + </div> | ||
| + <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> | ||
| + <h2 class="heading settled" data-level="6" id="acknowledgements"><span class="secno">6. </span><span class="content">Acknowledgements</span><a class="self-link" href="#acknowledgements"></a></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> | ||
| + </main> | ||
| + <h2 class="no-ref no-num heading settled" id="conformance"><span class="content">Conformance</span><a class="self-link" href="#conformance"></a></h2> | ||
| + <h3 class="no-ref no-num heading settled" id="conventions"><span class="content">Document conventions</span><a class="self-link" href="#conventions"></a></h3> | ||
| + <p>Conformance requirements are expressed with a combination of | ||
| + descriptive assertions and RFC 2119 terminology. The key words "MUST", | ||
| + "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", | ||
| + "RECOMMENDED", "MAY", and "OPTIONAL" in the normative parts of this | ||
| + document are to be interpreted as described in RFC 2119. | ||
| + However, for readability, these words do not appear in all uppercase | ||
| + letters in this specification. </p> | ||
| + <p>All of the text of this specification is normative except sections | ||
| + explicitly marked as non-normative, examples, and notes. <a data-link-type="biblio" href="#biblio-rfc2119">[RFC2119]</a></p> | ||
| + <p>Examples in this specification are introduced with the words "for example" | ||
| + or are set apart from the normative text with <code>class="example"</code>, | ||
| + like this: </p> | ||
| + <div class="example" id="example-f839f6c8"> | ||
| + <a class="self-link" href="#example-f839f6c8"></a> | ||
| + <p>This is an example of an informative example.</p> | ||
| + </div> | ||
| + <p>Informative notes begin with the word "Note" and are set apart from the | ||
| + normative text with <code>class="note"</code>, like this: </p> | ||
| + <p class="note" role="note">Note, this is an informative note.</p> | ||
| + <h3 class="no-ref no-num heading settled" id="conformant-algorithms"><span class="content">Conformant Algorithms</span><a class="self-link" href="#conformant-algorithms"></a></h3> | ||
| + <p>Requirements phrased in the imperative as part of algorithms (such as | ||
| + "strip any leading space characters" or "return false and abort these | ||
| + steps") are to be interpreted with the meaning of the key word ("must", | ||
| + "should", "may", etc) used in introducing the algorithm.</p> | ||
| + <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> | ||
| + <h2 class="no-num heading settled" id="index"><span class="content">Index</span><a class="self-link" href="#index"></a></h2> | ||
| + <h3 class="no-num heading settled" id="index-defined-here"><span class="content">Terms defined by this specification</span><a class="self-link" href="#index-defined-here"></a></h3> | ||
| + <ul class="indexlist"> | ||
| + <li><a href="#base64-encoding">base64 encoding</a><span>, in §2</span> | ||
| + <li><a href="#grammardef-base64-value">base64-value</a><span>, in §3.5</span> | ||
| + <li><a href="#content-encoding">content encoding</a><span>, in §2</span> | ||
| + <li><a href="#cross-origin">cross-origin</a><span>, in §2</span> | ||
| + <li><a href="#digest">digest</a><span>, in §2</span> | ||
| + <li><a href="#getprioritizedhashfunction">getPrioritizedHashFunction</a><span>, in §3.2.2</span> | ||
| + <li><a href="#grammardef-hash-algo">hash-algo</a><span>, in §3.5</span> | ||
| + <li><a href="#grammardef-hash-expression">hash-expression</a><span>, in §3.5</span> | ||
| + <li><a href="#grammardef-hash-with-options">hash-with-options</a><span>, in §3.5</span> | ||
| + <li> | ||
| + integrity | ||
| + <ul> | ||
| + <li><a href="#dom-htmllinkelement-integrity">attribute for HTMLLinkElement</a><span>, in §3.6.1</span> | ||
| + <li><a href="#dom-htmlscriptelement-integrity">attribute for HTMLScriptElement</a><span>, in §3.6.2</span> | ||
| + </ul> | ||
| + <li><a href="#grammardef-integrity-metadata">integrity-metadata</a><span>, in §3.5</span> | ||
| + <li><a href="#integrity-metadata">integrity | ||
| +metadata</a><span>, in §3.1</span> | ||
| + <li><a href="#grammardef-option-expression">option-expression</a><span>, in §3.5</span> | ||
| + <li><a href="#origin">origin</a><span>, in §2</span> | ||
| + <li><a href="#representation-data">representation data</a><span>, in §2</span> | ||
| + <li><a href="#same-origin">same-origin</a><span>, in §2</span> | ||
| + </ul> | ||
| + <h3 class="no-num heading settled" id="index-defined-elsewhere"><span class="content">Terms defined by reference</span><a class="self-link" href="#index-defined-elsewhere"></a></h3> | ||
| + <ul class="indexlist"> | ||
| + <li> | ||
| + <a data-link-type="biblio" href="#biblio-abnf">[ABNF]</a> defines the following terms: | ||
| + <ul> | ||
| + <li><a href="https://tools.ietf.org/html/rfc5234#appendix-B.1">vchar</a> | ||
| + <li><a href="https://tools.ietf.org/html/rfc5234#appendix-B.1">wsp</a> | ||
| + </ul> | ||
| + <li> | ||
| + <a data-link-type="biblio" href="#biblio-fetch">[FETCH]</a> defines the following terms: | ||
| + <ul> | ||
| + <li><a href="https://fetch.spec.whatwg.org#concept-fetch">fetch</a> | ||
| + <li><a href="https://fetch.spec.whatwg.org#concept-request">request</a> | ||
| + <li><a href="https://fetch.spec.whatwg.org#concept-response-type">response type</a> | ||
| + </ul> | ||
| + <li> | ||
| + <a data-link-type="biblio" href="#biblio-html5">[html5]</a> defines the following terms: | ||
| + <ul> | ||
| + <li><a href="http://www.w3.org/TR/html5/infrastructure.html#cors-settings-attributes">cors settings attribute</a> | ||
| + <li><a href="http://www.w3.org/TR/html5/document-metadata.html#concept-link-obtain">obtain a resource</a> | ||
| + <li><a href="http://www.w3.org/TR/html5/scripting-1.html#prepare-a-script">prepare a script</a> | ||
| + <li><a href="http://www.w3.org/TR/html5/infrastructure.html#reflect">reflect</a> | ||
| + <li><a href="http://www.w3.org/TR/html5/infrastructure.html#split-a-string-on-spaces">split on spaces</a> | ||
| + </ul> | ||
| + <li> | ||
| + <a data-link-type="biblio" href="#biblio-rfc7234">[rfc7234]</a> defines the following terms: | ||
| + <ul> | ||
| + <li><a href="https://tools.ietf.org/html/rfc7234#section-5.2">cache-control</a> | ||
| + <li><a href="https://tools.ietf.org/html/rfc7234#section-5.2.1.6">no-transform</a> | ||
| + </ul> | ||
| + <li> | ||
| + <a data-link-type="biblio" href="#biblio-secure-contexts">[SECURE-CONTEXTS]</a> defines the following terms: | ||
| + <ul> | ||
| + <li><a href=""http://www.w3.org/TR/powerful-features/"#secure-context">secure context</a> | ||
| + </ul> | ||
| + <li> | ||
| + <a data-link-type="biblio" href="#biblio-sha2">[SHA2]</a> defines the following terms: | ||
| + <ul> | ||
| + <li><a href="http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf#">sha-2</a> | ||
| + <li><a href="http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf#">sha-256</a> | ||
| + <li><a href="http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf#">sha-384</a> | ||
| + <li><a href="http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf#">sha-512</a> | ||
| + </ul> | ||
| + <li> | ||
| + <a data-link-type="biblio" href="#biblio-html">[HTML]</a> defines the following terms: | ||
| + <ul> | ||
| + <li><a href="https://html.spec.whatwg.org/multipage/semantics.html#htmllinkelement">HTMLLinkElement</a> | ||
| + <li><a href="https://html.spec.whatwg.org/multipage/scripting.html#htmlscriptelement">HTMLScriptElement</a> | ||
| + </ul> | ||
| + </ul> | ||
| + <h2 class="no-num heading settled" id="references"><span class="content">References</span><a class="self-link" href="#references"></a></h2> | ||
| + <h3 class="no-num heading settled" id="normative"><span class="content">Normative References</span><a class="self-link" href="#normative"></a></h3> | ||
| + <dl> | ||
| + <dt id="biblio-abnf"><a class="self-link" href="#biblio-abnf"></a>[ABNF] | ||
| + <dd>D. Crocker, Ed.; P. Overell. <a href="https://tools.ietf.org/html/rfc5234">Augmented BNF for Syntax Specifications: ABNF</a>. January 2008. Internet Standard. URL: <a href="https://tools.ietf.org/html/rfc5234">https://tools.ietf.org/html/rfc5234</a> | ||
| + <dt id="biblio-fetch"><a class="self-link" href="#biblio-fetch"></a>[FETCH] | ||
| + <dd>Anne van Kesteren. <a href="https://fetch.spec.whatwg.org/">Fetch Standard</a>. Living Standard. URL: <a href="https://fetch.spec.whatwg.org/">https://fetch.spec.whatwg.org/</a> | ||
| + <dt id="biblio-html"><a class="self-link" href="#biblio-html"></a>[HTML] | ||
| + <dd>Ian Hickson. <a href="https://html.spec.whatwg.org/multipage/">HTML Standard</a>. Living Standard. URL: <a href="https://html.spec.whatwg.org/multipage/">https://html.spec.whatwg.org/multipage/</a> | ||
| + <dt id="biblio-mime-types"><a class="self-link" href="#biblio-mime-types"></a>[MIME-TYPES] | ||
| + <dd>N. Freed; N. Borenstein. <a href="https://tools.ietf.org/html/rfc2046">Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types</a>. November 1996. Draft Standard. URL: <a href="https://tools.ietf.org/html/rfc2046">https://tools.ietf.org/html/rfc2046</a> | ||
| + <dt id="biblio-origin"><a class="self-link" href="#biblio-origin"></a>[ORIGIN] | ||
| + <dd>A. Barth. <a href="https://tools.ietf.org/html/rfc6454">The Web Origin Concept</a>. December 2011. Proposed Standard. URL: <a href="https://tools.ietf.org/html/rfc6454">https://tools.ietf.org/html/rfc6454</a> | ||
| + <dt id="biblio-secure-contexts"><a class="self-link" href="#biblio-secure-contexts"></a>[SECURE-CONTEXTS] | ||
| + <dd>Mike West; Yan Zhu. <a href="https://w3c.github.io/webappsec-secure-contexts/">Secure Contexts</a>. WD. URL: <a href="https://w3c.github.io/webappsec-secure-contexts/">https://w3c.github.io/webappsec-secure-contexts/</a> | ||
| + <dt id="biblio-sha2"><a class="self-link" href="#biblio-sha2"></a>[SHA2] | ||
| + <dd><a href="http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf">FIPS PUB 180-4, Secure Hash Standard</a>. URL: <a href="http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf">http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf</a> | ||
| + <dt id="biblio-cors"><a class="self-link" href="#biblio-cors"></a>[CORS] | ||
| + <dd>Anne van Kesteren. <a href="http://www.w3.org/TR/cors/">Cross-Origin Resource Sharing</a>. 16 January 2014. REC. URL: <a href="http://www.w3.org/TR/cors/">http://www.w3.org/TR/cors/</a> | ||
| + <dt id="biblio-html5"><a class="self-link" href="#biblio-html5"></a>[HTML5] | ||
| + <dd>Ian Hickson; et al. <a href="http://www.w3.org/TR/html5/">HTML5</a>. 28 October 2014. REC. URL: <a href="http://www.w3.org/TR/html5/">http://www.w3.org/TR/html5/</a> | ||
| + <dt id="biblio-rfc2119"><a class="self-link" href="#biblio-rfc2119"></a>[RFC2119] | ||
| + <dd>S. Bradner. <a href="https://tools.ietf.org/html/rfc2119">Key words for use in RFCs to Indicate Requirement Levels</a>. March 1997. Best Current Practice. URL: <a href="https://tools.ietf.org/html/rfc2119">https://tools.ietf.org/html/rfc2119</a> | ||
| + <dt id="biblio-rfc4648"><a class="self-link" href="#biblio-rfc4648"></a>[RFC4648] | ||
| + <dd>S. Josefsson. <a href="https://tools.ietf.org/html/rfc4648">The Base16, Base32, and Base64 Data Encodings</a>. October 2006. Proposed Standard. URL: <a href="https://tools.ietf.org/html/rfc4648">https://tools.ietf.org/html/rfc4648</a> | ||
| + <dt id="biblio-rfc7231"><a class="self-link" href="#biblio-rfc7231"></a>[RFC7231] | ||
| + <dd>R. Fielding, Ed.; J. Reschke, Ed.. <a href="https://tools.ietf.org/html/rfc7231">Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content</a>. June 2014. Proposed Standard. URL: <a href="https://tools.ietf.org/html/rfc7231">https://tools.ietf.org/html/rfc7231</a> | ||
| + <dt id="biblio-rfc7234"><a class="self-link" href="#biblio-rfc7234"></a>[RFC7234] | ||
| + <dd>R. Fielding, Ed.; M. Nottingham, Ed.; J. Reschke, Ed.. <a href="https://tools.ietf.org/html/rfc7234">Hypertext Transfer Protocol (HTTP/1.1): Caching</a>. June 2014. Proposed Standard. URL: <a href="https://tools.ietf.org/html/rfc7234">https://tools.ietf.org/html/rfc7234</a> | ||
| + </dl> | ||
| + <h3 class="no-num heading settled" id="informative"><span class="content">Informative References</span><a class="self-link" href="#informative"></a></h3> | ||
| + <dl> | ||
| + <dt id="biblio-tls"><a class="self-link" href="#biblio-tls"></a>[TLS] | ||
| + <dd>T. Dierks; E. Rescorla. <a href="https://tools.ietf.org/html/rfc5246">The Transport Layer Security (TLS) Protocol Version 1.2</a>. August 2008. Proposed Standard. URL: <a href="https://tools.ietf.org/html/rfc5246">https://tools.ietf.org/html/rfc5246</a> | ||
| + <dt id="biblio-rfc1035"><a class="self-link" href="#biblio-rfc1035"></a>[RFC1035] | ||
| + <dd>P.V. Mockapetris. <a href="https://tools.ietf.org/html/rfc1035">Domain names - implementation and specification</a>. November 1987. Internet Standard. URL: <a href="https://tools.ietf.org/html/rfc1035">https://tools.ietf.org/html/rfc1035</a> | ||
| + <dt id="biblio-rfc6797"><a class="self-link" href="#biblio-rfc6797"></a>[RFC6797] | ||
| + <dd>J. Hodges; C. Jackson; A. Barth. <a href="https://tools.ietf.org/html/rfc6797">HTTP Strict Transport Security (HSTS)</a>. November 2012. Proposed Standard. URL: <a href="https://tools.ietf.org/html/rfc6797">https://tools.ietf.org/html/rfc6797</a> | ||
| + <dt id="biblio-rfc7469"><a class="self-link" href="#biblio-rfc7469"></a>[RFC7469] | ||
| + <dd>C. Evans; C. Palmer; R. Sleevi. <a href="https://tools.ietf.org/html/rfc7469">Public Key Pinning Extension for HTTP</a>. April 2015. Proposed Standard. URL: <a href="https://tools.ietf.org/html/rfc7469">https://tools.ietf.org/html/rfc7469</a> | ||
| + </dl> | ||
| + <h2 class="no-num heading settled" id="idl-index"><span class="content">IDL Index</span><a class="self-link" href="#idl-index"></a></h2> | ||
| +<pre class="idl">partial interface <a class="idl-code" data-link-type="interface" href="https://html.spec.whatwg.org/multipage/semantics.html#htmllinkelement">HTMLLinkElement</a> { | ||
| + attribute DOMString <a data-type="DOMString " href="#dom-htmllinkelement-integrity">integrity</a>; | ||
| +}; | ||
| + | ||
| +partial interface <a class="idl-code" data-link-type="interface" href="https://html.spec.whatwg.org/multipage/scripting.html#htmlscriptelement">HTMLScriptElement</a> { | ||
| + attribute DOMString <a data-type="DOMString " href="#dom-htmlscriptelement-integrity">integrity</a>; | ||
| +}; | ||
| + | ||
| +</pre> | ||
| + </body> | ||
| +</html> |
0 comments on commit
d5b1943