摘要

本规范定义了一种机制,用户代理可通过该机制验证获取的资源是否未经预期的操纵而传递。

本文件的状态

本节描述了本文件在发布时的状态。其他文件可能会取代本文件。可以在W3C 技术报告 索引找到当前 W3C 的出版物和此技术报告的最新版本,网址为 http://www.w3.org/TR/。

本文件的变更列表可在 https://github.com/w3c/webappsec-subresource-integrity 找到。

本文件由Web 应用安全工作组作为推荐发布。如果您希望对此文件发表意见,请将其发送至 public-webappsec@w3.org (订阅存档),并在电子邮件主题的开头使用[SRI]。欢迎所有意见。

请参阅工作组的实施报告

本文件已由 W3C 成员、软件开发者及其他 W3C 小组和相关方进行审核,并获得了总监的认可,作为 W3C 推荐。本文件是稳定的,可以用作参考资料或在其他文件中引用。W3C 制定推荐标准的作用是引起对该规范的关注,并推动其广泛部署。这增强了Web的功能性和互操作性。

W3C 预计本推荐中规定的功能不会受到Fetch 的变更影响。工作组将继续跟踪Fetch规范并记录影响本规范的问题。

本文件由依据2004年2月5日 W3C 专利政策 运营的小组制作。 W3C 维护了与该小组交付成果相关的任何专利披露的公开列表;该页面还包含披露专利的说明。任何个人如果确知某专利包含 必要声明,必须根据W3C专利政策第6节披露信息。

本文件受2015年9月1日 W3C 流程文件的管理。

1. 介绍

本节是非规范性的。

网络上的站点和应用很少仅由单一来源的资源组成。例如,作者从各种服务和内容交付网络(CDN)中提取脚本和样式,必须信任所交付的内容确实是他们预期加载的内容。如果攻击者通过DNS欺骗或其他手段,诱使用户从恶意服务器下载内容,作者将无能为力。同样,攻击者如果能替换CDN服务器上的文件,也可以注入任意内容。

通过安全通道交付资源可以减轻这种风险:通过TLSHSTS固定公钥,用户代理可以相当确定它确实在与它认为的服务器通信。然而,这些机制仅验证了服务器,验证内容。拥有服务器访问权限的攻击者(或管理员)可以随意操纵内容。理想情况下,作者不仅能够固定服务器的密钥,还能固定内容,确保只加载和执行特定资源的精确表示。

本文档定义了这样一个验证方案,扩展了两个HTML元素,添加了一个包含作者期望加载的资源表示的加密哈希的integrity属性。例如,作者可能希望从共享服务器而不是自己的来源加载某个框架。指定预期的SHA-384哈希为https://example.com/example-framework.jsLi9vy3DqF8tnTXuiaAJuML3ky+er10rcgNR/VqsVpcw+ThHmYcwiB1pbOxEbzJr7,这意味着用户代理可以在执行JavaScript之前,验证从该URL加载的数据是否与该预期哈希匹配。这种完整性验证显著降低了攻击者替换恶意内容的风险。

此示例可以通过在script元素中添加哈希传达给用户代理,如下所示:

示例 1
<script src="https://example.com/example-framework.js"
        integrity="sha384-Li9vy3DqF8tnTXuiaAJuML3ky+er10rcgNR/VqsVpcw+ThHmYcwiB1pbOxEbzJr7"
        crossorigin="anonymous"></script>

当然,脚本并不是唯一可以从完整性验证中受益的响应类型。此处指定的方案也适用于link,未来的版本可能会扩展到更多的类型。

1.1 目标

  1. 第三方服务的妥协不应自动意味着每个包含其脚本的站点都受到威胁。内容作者将有机制指定他们加载的内容期望,例如,他们可以加载特定的脚本,而不是碰巧具有特定URL的任何脚本。

  2. 验证机制应具有错误报告功能,通知作者接收到的响应无效。

1.2 用例/示例

1.2.1 资源完整性

  • 作者希望使用内容交付网络(CDN)提高全球用户的性能。然而,确保CDN服务器只交付作者期望的代码非常重要。为了减轻CDN妥协(或意外的恶意行为)导致站点发生不利变化的风险,以下完整性元数据被添加到页面的link元素中:

    示例 2
    <link rel="stylesheet" href="https://site53.example.net/style.css"
          integrity="sha384-+/M6kredJcxdsqkczBUjMLvqyHb1K/JThDXWsBVxMEeZHEaMKEOEct339VItX1zB"
          crossorigin="anonymous">
    
  • 作者希望包含第三方分析服务提供的JavaScript。为了确保只有经过仔细审核的代码被执行,作者为脚本生成了完整性元数据,并将其添加到script元素中:

    示例 3
    <script src="https://analytics-r-us.example.com/v1.0/include.js"
            integrity="sha384-MBO5IDfYaE6c6Aao94oZrIOiC6CGiSN2n4QUbHNPhzk5Xhm0djZLQqTpL0HzTUxk"
            crossorigin="anonymous"></script>
    
  • 用户代理希望确保在高权限HTML上下文(例如,浏览器的新标签页)中运行的JavaScript代码在显示之前未被篡改。完整性元数据减轻了在这些页面的高权限上下文中运行被修改的JavaScript的风险。

2. 一致性

除了标记为非规范的章节外,本规范中的所有编写指南、图表、示例和注释都是非规范性的。本规范中的其他内容均为规范性内容。

关键词 MAYMUSTSHOULD 按照 [RFC2119] 中的描述进行解释。

以算法或特定步骤表达的一致性要求可以以任何方式实现,只要最终结果等效即可。特别是,本规范中定义的算法旨在便于理解,而不是为了性能。建议实现者进行优化。

2.1 关键概念与术语

本节定义了文档中使用的几个术语。

术语摘要指的是对任意数据块执行加密哈希函数后生成的base64编码结果。

术语在源规范中定义。[RFC6454]

表示数据内容编码RFC7231,第3节定义。[RFC7231]

Base64编码定义在RFC 4648,第4节中。[RFC4648]

SHA-256SHA-384SHA-512是由NIST定义的SHA-2加密哈希函数集的一部分,参见“FIPS PUB 180-4: Secure Hash Standard (SHS)”

2.2 语法概念

本文件中使用的增强型巴科斯-瑙尔形式(ABNF)符号在RFC5234中规定。[ABNF]

[ABNF]的附录B.1定义了VCHAR(打印字符)。

WSP(空白字符)在HTML 5规范的“2.4.1 公共解析器惯例”中定义为White_Space characters

3. 框架

此处指定的完整性验证机制归结为为资源生成足够强的加密摘要,并将该摘要传输给用户代理,以便其用于验证响应。

3.1 完整性元数据

为了验证响应的完整性,用户代理需要完整性元数据作为请求的一部分。此元数据包含以下信息:

必须提供哈希函数和摘要,才能验证响应的完整性。

注意

目前尚未定义任何选项。然而,规范的未来版本可能会定义选项,例如MIME类型 [MIMETYPE]。

此元数据必须按照内容安全策略第2级规范第4.2节中的hash-source(不带单引号)相同的格式进行编码。

例如,给定一个仅包含字符串alert(\'Hello, world.\');的脚本资源,作者可能会选择SHA-384作为哈希函数。 结果的base64编码摘要为H8BRh8j48O9oYatfu5AZzq6A9RINhZO5H16dQZngK7T62em8MUt1FLm52t+eX6xO。可以如下编码:

示例 4
sha384-H8BRh8j48O9oYatfu5AZzq6A9RINhZO5H16dQZngK7T62em8MUt1FLm52t+eX6xO
注意

可以使用许多工具生成摘要。例如,OpenSSL相当常见。本节中的示例是通过以下命令行生成的结果:

echo -n "alert('Hello, world.');" | openssl dgst -sha384 -binary | openssl base64 -A

3.2 加密哈希函数

符合要求的用户代理必须支持SHA-256SHA-384SHA-512加密哈希函数,用作请求的完整性元数据的一部分,并且可以支持其他哈希函数。

用户代理应当拒绝支持已知的弱哈希函数,如MD5或SHA-1,并且应当将支持的哈希函数限制为已知的抗碰撞哈希函数。此外,用户代理应当定期重新评估其支持的哈希函数,并弃用那些已变得不安全的函数。参见哈希碰撞攻击

3.2.1 灵活性

可以将多个完整性元数据集与单个资源关联,以便在面对未来加密发现时提供灵活性。例如,前一节中描述的资源可以通过以下任一哈希表达式进行描述:

示例 5
sha384-dOTZf16X8p34q2/kYyEFm0jh89uTjikhnzjeLeF0FHsEaYKb1A1cv+Lyv4Hk8vHd
sha512-Q2bFTOhEALkN8hOms2FKTDLy7eugP2zFZ1T8LCvX42Fp3WoNr3bjZSAHeOsHrbV1Fu9/A0EzCinRE7Af1ofPrw==

作者可以选择同时指定两者,例如:

示例 6
<script src="hello_world.js"
   integrity="sha384-dOTZf16X8p34q2/kYyEFm0jh89uTjikhnzjeLeF0FHsEaYKb1A1cv+Lyv4Hk8vHd
              sha512-Q2bFTOhEALkN8hOms2FKTDLy7eugP2zFZ1T8LCvX42Fp3WoNr3bjZSAHeOsHrbV1Fu9/A0EzCinRE7Af1ofPrw=="
   crossorigin="anonymous"></script>

在这种情况下,用户代理将选择列表中最强的哈希函数,并使用该元数据来验证响应(如下面“解析元数据”和“从集合中获取最强的元数据”算法中所述)。

当哈希函数被确定为不安全时,用户代理应当弃用并最终移除使用不安全哈希函数的完整性验证支持。用户代理可以检查基于已弃用函数的响应的有效性。

为了让作者能够在不受旧版用户代理阻碍的情况下切换到更强的哈希函数,使用不支持的哈希函数进行验证的行为与未提供完整性值时相同(参见下文的“响应是否匹配元数据列表”算法)。鼓励作者使用强哈希函数,并在更强的哈希函数可用时开始迁移。

3.2.2 优先级

用户代理必须提供一种机制,用于确定两个哈希函数的相对优先级,如果优先级相等,则返回空字符串。也就是说,如果用户代理实现了一个类似于getPrioritizedHashFunction(a, b)的函数,它将返回用户代理认为最具抗碰撞性的哈希函数。例如,getPrioritizedHashFunction('sha256', 'sha512')将返回'sha512',而getPrioritizedHashFunction('sha256', 'sha256')将返回空字符串。

注意

getPrioritizedHashFunction是一个内部实现细节。它不是实现者提供给Web应用的API。它仅用于简化本文档中的算法描述。

3.3 响应验证算法

3.3.1 算法应用于响应

  1. 结果应用算法表示数据的结果,不应用任何内容编码,除非用户代理打算以应用内容编码的方式使用该内容。在后一种情况下,令结果为应用算法表示数据的结果。
  2. 编码结果结果的base64编码。
  3. 返回编码结果

3.3.2 响应是否符合完整性验证

为了减轻攻击者通过完整性检查暴力破解值来跨源读取数据的能力,只有当响应是同源的或通过跨源资源共享明确授予加载源访问权限时,响应才有资格进行此类检查 [CORS]。

注意

RFC6454,第4节所述,某些用户代理对每个文件URI使用全局唯一标识符。这意味着通过file方案URL访问的资源可能不符合完整性检查的资格。

注意

处于安全上下文(例如,通过HTTPS传输的文档)并不是使用完整性验证的必要条件。由于资源完整性仅是应用级别的安全工具,它不会改变用户代理的安全状态,因此安全上下文不是必须的。然而,如果在非安全上下文中使用完整性验证(例如,通过HTTP传输的文档),作者应意识到完整性验证根本不提供任何安全保证。因此,作者应仅在安全上下文中传递完整性元数据。有关更多讨论,请参见非安全上下文仍然不安全

以下算法详细说明了这些限制:

  1. 响应获取资源的结果。
  2. 如果响应类型basiccorsdefault,返回true
  3. 返回false
注意

响应类型由Fetch规范定义 [FETCH],并指以下内容:

  • basic是同源响应,因此请求者可以完全读取其主体。
  • cors是对跨源、启用CORS的请求的有效响应,因此请求者也可以完全读取其主体。
  • default是由Service Worker生成的对请求的有效响应,因此其主体也可以被请求者完全读取。

3.3.3 解析元数据

此算法接受一个字符串,并返回无元数据或一组用户代理能够理解的有效哈希表达式。

  1. 结果为一个空集合。
  2. 等于true
  3. 对于每个通过按空格拆分元数据返回的令牌
    1. 设置为false
    2. 如果令牌不是有效的元数据,跳过剩余步骤,并继续下一个令牌
    3. 根据完整性元数据中的语法解析令牌
    4. 算法令牌alg组件。
    5. 如果算法是用户代理识别的哈希函数,则将解析的令牌添加到结果中。
  4. 如果true,返回无元数据,否则返回结果

3.3.4 集合中获取最强的元数据。

  1. 结果为一个空集合,最强为一个空字符串。
  2. 对于集合中的每个
    1. 如果结果是空集合,将添加到结果中,并将最强设置为,跳到下一个
    2. 当前算法最强alg组件。
    3. 新算法alg组件。
    4. 如果getPrioritizedHashFunction(currentAlgorithm, newAlgorithm)的结果为空字符串,将添加到结果中。如果结果为新算法,将最强设置为,将结果设置为空集合,并将添加到结果中。
  3. 返回结果

3.3.5 响应是否匹配元数据列表

  1. 解析元数据解析元数据列表的结果。
  2. 如果解析元数据无元数据,返回true
  3. 如果响应不符合完整性验证,返回false
  4. 如果解析元数据为空集合,返回true
  5. 元数据解析元数据中获取最强元数据的结果。
  6. 对于元数据中的每个
    1. 算法alg组件。
    2. 期望值val组件。
    3. 实际值应用算法响应的结果。
    4. 如果实际值期望值区分大小写匹配,返回true
  7. 返回false

该算法允许用户代理接受多个有效的强哈希函数。例如,开发者可以编写如下的script元素:

示例 7
<script src="https://example.com/example-framework.js"
        integrity="sha384-Li9vy3DqF8tnTXuiaAJuML3ky+er10rcgNR/VqsVpcw+ThHmYcwiB1pbOxEbzJr7
                   sha384-+/M6kredJcxdsqkczBUjMLvqyHb1K/JThDXWsBVxMEeZHEaMKEOEct339VItX1zB"
        crossorigin="anonymous"></script>

这将允许用户代理接受两个不同的内容有效负载,一个匹配第一个SHA384哈希值,另一个匹配第二个SHA384哈希值。

注意

用户代理可以允许用户通过用户偏好、书签、第三方对用户代理的扩展等机制修改该算法的结果。例如,由类似HTTPS Everywhere的扩展生成的重定向可以正确加载和执行,即使资源的HTTPS版本与HTTP版本不同。

注意

如果响应不符合完整性验证的资格,该算法返回false,因为子资源完整性(SRI)需要CORS,尝试在没有CORS的情况下使用它是一个逻辑错误。此外,用户代理应当在开发者控制台报告警告信息,以解释该失败。

3.4 验证HTML文档子资源

各种HTML元素会导致请求将资源嵌入到文档中,或在其上下文中执行。为了支持其中一些元素的完整性元数据,integrity属性被添加到linkscript元素的内容属性列表中。

一个对应的integrity IDL属性,它反映了每个元素的integrity内容属性的值,被添加到HTMLLinkElementHTMLScriptElement接口中。

注意

本规范的未来修订版本可能会包括对所有可能子资源的完整性支持,即aaudioembediframeimglinkobjectscriptsourcetrackvideo元素。

3.5 integrity属性

integrity属性表示元素的完整性元数据。属性的值必须是空字符串或至少一个有效的元数据,如以下ABNF语法所描述:

integrity-metadata = *WSP hash-with-options *( 1*WSP hash-with-options ) *WSP / *WSP
hash-with-options  = hash-expression *("?" option-expression)
option-expression  = *VCHAR
hash-algo          = <hash-algo production from [Content Security Policy Level 2, section 4.2]>
base64-value       = <base64-value production from [Content Security Policy Level 2, section 4.2]>
hash-expression    = hash-algo "-" base64-value

integrity IDL属性必须反映integrity内容属性的值。

option-expression与每个hash-expression关联,并且仅应用于其前面的hash-expression

为了确保用户代理完全向未来的选项兼容,用户代理必须忽略所有无法识别的option-expression

注意

请注意,虽然option-expression已在语法中保留,但尚未定义任何选项。很可能在未来的版本中会为选项定义更具体的语法,因此在此定义为尽可能广泛。

3.6 元素接口扩展

3.6.1 HTMLLinkElement

partial interface HTMLLinkElement {
                    attribute DOMString integrity;
};
3.6.1.1 属性
integrity类型为DOMString
integrity

3.6.2 HTMLScriptElement

partial interface HTMLScriptElement {
                    attribute DOMString integrity;
};
3.6.2.1 属性
integrity类型为DOMString
integrity

3.7 处理完整性违规

用户代理将拒绝渲染或执行未通过完整性检查的响应,而是返回Fetch中定义的网络错误 [FETCH]。

注意

在完整性检查失败时,会触发error事件。希望提供规范备用资源(例如,未从CDN提供的资源,可能来自二级、受信任但较慢的源)的开发人员可以捕获此error事件,并提供适当的处理程序以将失败的资源替换为另一个资源。

3.8 元素

每当用户代理尝试获取link元素指向的资源时,如果其rel属性包含stylesheet关键字,请修改步骤4为:

对生成的绝对URL进行潜在的启用CORS的获取,模式为元素crossorigin内容属性的当前状态,源为link元素文档的源,默认源行为设置为污染,并将请求的完整性元数据设置为元素integrity属性的值。

3.8.2 script元素

将HTML5中“准备脚本”算法的步骤14.1替换为:

  1. src为元素src属性的值,请求的关联完整性元数据为元素integrity属性的值。

4. 代理

优化代理和其他修改响应的中间服务器必须确保与这些响应相关的摘要与新内容保持同步。一种选择是确保与资源相关的完整性元数据已更新。另一种选择是仅传送页面作者请求完整性验证的资源的规范版本。

为了帮助通知中间服务器,提供资源的服务器应当与资源一起发送带有Cache-Control标头,并将其值设置为no-transform

5. 安全性考虑

本节为非规范性内容。

5.1 非安全上下文仍然不安全

由非安全上下文(例如HTTP页面)传递的完整性元数据仅能保护原点免受托管外部资源的服务器被入侵的情况。网络攻击者可以在传输过程中更改摘要(或完全删除它,或对文档做任何其他更改),正如他们可以更改哈希试图验证的响应一样。因此,建议作者仅将完整性元数据传递到安全上下文。另见保护网络安全

5.2 哈希碰撞攻击

摘要的强度取决于用于生成它们的哈希函数。建议用户代理拒绝支持已知弱的哈希函数,并将支持的算法限制为已知的抗碰撞算法。不推荐的哈希函数示例包括MD5和SHA-1。在撰写本文时,SHA-384是一个不错的基准。

此外,建议用户代理定期重新评估其支持的哈希函数,并弃用已被证明不安全的函数。随着时间的推移,哈希函数可能被证明比预期的要弱得多,甚至在某些情况下被破解,因此用户代理需要关注这些进展。

5.3 跨源数据泄漏

本规范要求跨源请求的CORS设置属性存在于受完整性保护的跨源请求中。如果省略了这一要求,攻击者可能会违反同源策略,并确定跨源资源是否具有特定内容。

攻击者可能会尝试使用已知摘要加载资源,并观察加载失败情况。如果加载失败,攻击者可以推断出响应与哈希不匹配,从而获得其内容的一些信息。例如,这可能会揭示用户是否已登录到某个特定服务。

此外,攻击者还可以通过蛮力破解特定值来攻击一个基本静态的资源。考虑如下的JSON响应:

示例 8
{'status': 'authenticated', 'username': 'admin'}

攻击者可以为响应中的常见用户名预计算哈希,并在反复尝试加载文档时指定这些哈希。成功的加载将确认攻击者已正确猜出了用户名。

6. 致谢

本内容的许多部分深受Gervase Markham的Link Fingerprints概念以及WHATWG的Link Hashes的启发。

特别感谢Google公司的Mike West对本规范初始版本的宝贵贡献。此外,Brad Hill、Anne van Kesteren、Jonathan Kingston、Mark Nottingham、Dan Veditz、Eduardo Vela、Tanvi Vyas和Michal Zalewski也提供了非常宝贵的反馈意见。

A. 参考文献

A.1 规范性参考文献

[ABNF]
D. Crocker, Ed.; P. Overell. IETF. 增强的BNF语法规范:ABNF。2008年1月。互联网标准。URL: https://tools.ietf.org/html/rfc5234
[CORS]
Anne van Kesteren. W3C. 跨源资源共享。2014年1月16日。W3C推荐。URL: http://www.w3.org/TR/cors/
[FETCH]
Anne van Kesteren. WHATWG. Fetch标准。现行标准。URL: https://fetch.spec.whatwg.org/
[MIMETYPE]
Ned Freed; Nathaniel S. Borenstein. IETF. 多用途互联网邮件扩展(MIME)第二部分:媒体类型。草案标准。URL: https://tools.ietf.org/html/rfc2046
[RFC2119]
S. Bradner. IETF. 用于指示要求级别的关键字。1997年3月。最佳当前实践。URL: https://tools.ietf.org/html/rfc2119
[RFC4648]
Simon Josefsson. IETF. Base16、Base32和Base64数据编码。建议标准。URL: https://tools.ietf.org/html/rfc4648
[RFC6454]
A. Barth. IETF. Web原点概念。2011年12月。建议标准。URL: https://tools.ietf.org/html/rfc6454
[RFC7231]
R. Fielding, Ed.; J. Reschke, Ed.. IETF. 超文本传输协议(HTTP/1.1):语义和内容。2014年6月。建议标准。URL: https://tools.ietf.org/html/rfc7231