子资源完整性

子资源完整性 (SRI) 是一项安全功能,它使浏览器能够验证它们获取的资源(例如,来自 CDN)是否未经意外修改。它通过允许您提供获取的资源必须匹配的加密哈希来工作。

注意:对于从嵌入其文档的其他来源提供的资源的子资源完整性验证,浏览器还会使用 跨源资源共享 (CORS) 检查资源,以确保提供资源的来源允许将其与请求来源共享。

子资源完整性如何提供帮助

使用 内容分发网络 (CDN) 托管多个站点之间共享的文件(如脚本和样式表)可以提高站点性能并节省带宽。但是,使用 CDN 也存在风险,如果攻击者控制了 CDN,则攻击者可以将任意恶意内容注入 CDN 上的文件(或完全替换文件),从而可能攻击所有从该 CDN 获取文件的站点。

子资源完整性使您能够降低此类攻击的一些风险,方法是确保您的 Web 应用程序或 Web 文档获取的文件(来自 CDN 或任何地方)在没有第三方将任何额外内容注入这些文件的情况下交付——并且没有任何其他任何更改对这些文件进行了更改。

使用子资源完整性

您可以通过在 <script> 元素或 <link> 元素的 integrity 属性的值中指定要告诉浏览器获取的资源(文件)的 base64 编码加密哈希来使用子资源完整性功能,其中带有 rel="stylesheet"rel="preload"rel="modulepreload"

integrity 值以至少一个字符串开头,每个字符串都包含一个指示特定哈希算法的前缀(当前允许的前缀是 sha256sha384sha512),后跟一个连字符,并以实际的 base64 编码哈希结尾。

注意:integrity 值可能包含用空格分隔的多个哈希。如果资源与其中一个哈希匹配,则将加载该资源。

包含 base64 编码 sha384 哈希的示例 integrity 字符串

sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC

因此,oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC 是“哈希”部分,前缀 sha384 表示它是 sha384 哈希。

注意:integrity 值的“哈希”部分严格来说是通过对某些输入(例如,脚本或样式表文件)应用特定哈希函数形成的加密 摘要。但是,使用缩写“哈希”来表示加密 摘要很常见,因此本文中使用了该缩写。

生成 SRI 哈希的工具

SRI 哈希生成器

您可以使用 SRI 哈希生成器(一种在线工具)来生成 SRI 哈希。

使用 OpenSSL

您可以使用以下命令调用 OpenSSL 从命令行生成 SRI 哈希

bash
cat FILENAME.js | openssl dgst -sha384 -binary | openssl base64 -A

在 Windows 环境中,您可以使用以下代码创建一个用于生成 SRI 哈希的工具

batch
@echo off
set bits=384
openssl dgst -sha%bits% -binary %1% | openssl base64 -A > tmp
set /p a= < tmp
del tmp
echo sha%bits%-%a%
pause

要使用该代码

  1. 将该代码保存在环境的 Windows SendTo 文件夹(例如,C:\Users\USER\AppData\Roaming\Microsoft\Windows\SendTo)中名为 sri-hash.bat 的文件中。
  2. 右键单击文件资源管理器中的文件,选择发送到…,然后选择sri-hash。您将在命令框中看到完整性值。
  3. 选择完整性值并右键单击将其复制到剪贴板。
  4. 按任意键关闭命令框。

注意:如果您的系统上未安装 OpenSSL,请访问 OpenSSL 项目网站 获取有关下载和安装的信息。OpenSSL 项目本身不托管 OpenSSL 的二进制分发版,但维护了一个非正式的第三方分发版列表:https://wiki.openssl.org/index.php/Binaries

使用 shasum

您可以使用以下命令调用 shasum 生成 SRI 哈希

bash
shasum -b -a 384 FILENAME.js | awk '{ print $1 }' | xxd -r -p | base64
  • 通过 xxd 的管道步骤将 shasum 的十六进制输出转换为二进制。
  • 通过 awk 的管道步骤是必要的,因为 shasum 将在其输出中传递散列文件名到 xxd。如果文件名碰巧包含有效的十六进制字符,这可能会产生灾难性的后果——因为 xxd 也将对其进行解码并将其传递给 base64

跨源资源共享和子资源完整性

对于从嵌入其文档的其他来源提供的资源的子资源完整性验证,浏览器还会使用 跨源资源共享 (CORS) 检查资源,以确保提供资源的来源允许将其与请求来源共享。因此,资源必须使用 Access-Control-Allow-Origin 标头提供服务,该标头允许资源与请求来源共享;例如

http
Access-Control-Allow-Origin: *

示例

在以下示例中,假设 oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC 已知是特定脚本 example-framework.js 的预期 SHA-384 哈希(摘要),并且在 https://example.com/example-framework.js 处托管了该脚本的副本。

使用 <script> 元素的子资源完整性

您可以使用以下 <script> 元素告诉浏览器,在执行 https://example.com/example-framework.js 脚本之前,浏览器必须首先将脚本与预期哈希进行比较,并验证是否存在匹配项。

html
<script
  src="https://example.com/example-framework.js"
  integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
  crossorigin="anonymous"></script>

注意:有关 crossorigin 属性用途的更多详细信息,请参阅 CORS 设置属性

浏览器如何处理子资源完整性

浏览器通过执行以下操作来处理 SRI

  1. 当浏览器遇到带有 integrity 属性的 <script><link> 元素时,在执行脚本或在应用 <link> 元素指定的任何样式表之前,浏览器必须首先将脚本或样式表与 integrity 值中给出的预期哈希进行比较。对于从嵌入其文档的其他来源提供的资源的子资源完整性验证,浏览器还会使用 跨源资源共享 (CORS) 检查资源,以确保提供资源的来源允许将其与请求来源共享。
  2. 如果脚本或样式表与其关联的 integrity 值不匹配,则浏览器必须拒绝执行脚本或应用样式表,并且必须改为返回网络错误,指示该脚本或样式表的获取失败。

规范

规范
HTML 标准
# attr-link-integrity
子资源完整性
# the-integrity-attribute
HTML 标准
# attr-script-integrity

浏览器兼容性

html.elements.link.integrity

BCD 表格仅在启用 JavaScript 的浏览器中加载。

html.elements.script.integrity

BCD 表格仅在启用 JavaScript 的浏览器中加载。

另请参阅