子资源完整性
子资源完整性 (SRI) 是一项安全功能,它使浏览器能够验证它们获取的资源(例如,来自 CDN)是否未经意外修改。它通过允许您提供获取的资源必须匹配的加密哈希来工作。
注意:对于从嵌入其文档的其他来源提供的资源的子资源完整性验证,浏览器还会使用 跨源资源共享 (CORS) 检查资源,以确保提供资源的来源允许将其与请求来源共享。
子资源完整性如何提供帮助
使用 内容分发网络 (CDN) 托管多个站点之间共享的文件(如脚本和样式表)可以提高站点性能并节省带宽。但是,使用 CDN 也存在风险,如果攻击者控制了 CDN,则攻击者可以将任意恶意内容注入 CDN 上的文件(或完全替换文件),从而可能攻击所有从该 CDN 获取文件的站点。
子资源完整性使您能够降低此类攻击的一些风险,方法是确保您的 Web 应用程序或 Web 文档获取的文件(来自 CDN 或任何地方)在没有第三方将任何额外内容注入这些文件的情况下交付——并且没有任何其他任何更改对这些文件进行了更改。
使用子资源完整性
您可以通过在 <script>
元素或 <link>
元素的 integrity
属性的值中指定要告诉浏览器获取的资源(文件)的 base64 编码加密哈希来使用子资源完整性功能,其中带有 rel="stylesheet"
、rel="preload"
或 rel="modulepreload"
。
integrity
值以至少一个字符串开头,每个字符串都包含一个指示特定哈希算法的前缀(当前允许的前缀是 sha256
、sha384
和 sha512
),后跟一个连字符,并以实际的 base64 编码哈希结尾。
注意:integrity
值可能包含用空格分隔的多个哈希。如果资源与其中一个哈希匹配,则将加载该资源。
包含 base64 编码 sha384 哈希的示例 integrity
字符串
sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC
因此,oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC
是“哈希”部分,前缀 sha384
表示它是 sha384 哈希。
注意:integrity
值的“哈希”部分严格来说是通过对某些输入(例如,脚本或样式表文件)应用特定哈希函数形成的加密 摘要。但是,使用缩写“哈希”来表示加密 摘要很常见,因此本文中使用了该缩写。
生成 SRI 哈希的工具
SRI 哈希生成器
您可以使用 SRI 哈希生成器(一种在线工具)来生成 SRI 哈希。
使用 OpenSSL
您可以使用以下命令调用 OpenSSL 从命令行生成 SRI 哈希
cat FILENAME.js | openssl dgst -sha384 -binary | openssl base64 -A
在 Windows 环境中,您可以使用以下代码创建一个用于生成 SRI 哈希的工具
@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
要使用该代码
- 将该代码保存在环境的 Windows SendTo 文件夹(例如,
C:\Users\USER\AppData\Roaming\Microsoft\Windows\SendTo
)中名为sri-hash.bat
的文件中。 - 右键单击文件资源管理器中的文件,选择发送到…,然后选择
sri-hash
。您将在命令框中看到完整性值。 - 选择完整性值并右键单击将其复制到剪贴板。
- 按任意键关闭命令框。
注意:如果您的系统上未安装 OpenSSL,请访问 OpenSSL 项目网站 获取有关下载和安装的信息。OpenSSL 项目本身不托管 OpenSSL 的二进制分发版,但维护了一个非正式的第三方分发版列表:https://wiki.openssl.org/index.php/Binaries。
使用 shasum
您可以使用以下命令调用 shasum 生成 SRI 哈希
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
标头提供服务,该标头允许资源与请求来源共享;例如
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
脚本之前,浏览器必须首先将脚本与预期哈希进行比较,并验证是否存在匹配项。
<script
src="https://example.com/example-framework.js"
integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
crossorigin="anonymous"></script>
注意:有关 crossorigin
属性用途的更多详细信息,请参阅 CORS 设置属性。
浏览器如何处理子资源完整性
浏览器通过执行以下操作来处理 SRI
- 当浏览器遇到带有
integrity
属性的<script>
或<link>
元素时,在执行脚本或在应用<link>
元素指定的任何样式表之前,浏览器必须首先将脚本或样式表与integrity
值中给出的预期哈希进行比较。对于从嵌入其文档的其他来源提供的资源的子资源完整性验证,浏览器还会使用 跨源资源共享 (CORS) 检查资源,以确保提供资源的来源允许将其与请求来源共享。 - 如果脚本或样式表与其关联的
integrity
值不匹配,则浏览器必须拒绝执行脚本或应用样式表,并且必须改为返回网络错误,指示该脚本或样式表的获取失败。
规范
规范 |
---|
HTML 标准 # attr-link-integrity |
子资源完整性 # the-integrity-attribute |
HTML 标准 # attr-script-integrity |
浏览器兼容性
html.elements.link.integrity
BCD 表格仅在启用 JavaScript 的浏览器中加载。
html.elements.script.integrity
BCD 表格仅在启用 JavaScript 的浏览器中加载。