子资源完整性
子资源完整性 (SRI) 是一项安全功能,它允许浏览器验证它们获取的资源(例如,从 CDN)在交付过程中未被意外篡改。它的工作原理是允许您提供一个加密哈希,获取的资源必须与之匹配。
注意: 对于从与嵌入它的文档不同源提供的资源的子资源完整性验证,浏览器还会使用 跨域资源共享 (CORS) 来额外检查该资源,以确保提供该资源的源允许它与请求的源共享。
子资源完整性如何提供帮助
网站有时会选择依赖第三方(例如 内容分发网络 (CDN))来托管其部分资源,而不是完全自行托管所有资源。例如,从 https://example.com 提供的文档可能包含来自另一个位置的资源。
<script src="https://not-example.com/script.js"></script>
这存在风险,即如果攻击者控制了第三方主机,攻击者就可以在其文件中注入任意恶意内容(或完全替换文件),从而也可以潜在地攻击从它那里获取文件的网站。
子资源完整性使您能够通过确保您的 Web 应用程序或 Web 文档获取的文件在没有攻击者注入任何额外内容的情况下交付,并且这些文件没有任何其他更改,来减轻此类攻击的某些风险。
使用子资源完整性
您通过在 <script> 元素或带有 rel="stylesheet"、rel="preload" 或 rel="modulepreload" 的 <link> 元素的 integrity 属性值中,指定一个 base64 编码的加密哈希,来使用子资源完整性功能,告诉浏览器获取该资源(文件)。
integrity 值至少包含一个字符串,每个字符串都包含一个指示特定哈希算法的前缀(目前允许的前缀是 sha256、sha384 和 sha512),后跟一个连字符,最后是实际的 base64 编码哈希。
注意: integrity 值可能包含多个由空格分隔的哈希。如果资源匹配其中一个哈希,它就会被加载。
带有 base64 编码 sha384 哈希的 integrity 字符串示例
sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC
因此,oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC 是“哈希”部分,前缀 sha384 表明这是一个 sha384 哈希。
注意: 严格来说,integrity 值的“哈希”部分是应用特定哈希函数到某个输入(例如,脚本或样式表文件)形成的**加密摘要**。但通常使用“哈希”的简写来表示加密摘要,因此本文档中也这样使用。
生成 SRI 哈希的工具
SRI 哈希生成器
SRI Hash Generator 是一个在线工具,可用于生成 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 文件夹中,文件名为
sri-hash.bat(例如,C:\Users\USER\AppData\Roaming\Microsoft\Windows\SendTo)。 - 在文件资源管理器中右键单击一个文件,选择“发送到…”(Send to…),然后选择
sri-hash。您将在命令框中看到完整性值。 - 选中完整性值,然后右键单击进行复制到剪贴板。
- 按任意键关闭命令框。
注意: 如果您的系统未安装 OpenSSL,请访问 OpenSSL 项目网站了解下载和安装信息。OpenSSL 项目本身不托管 OpenSSL 的二进制分发版,但维护着一个非正式的第三方分发版列表:https://github.com/openssl/openssl/wiki/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: *
浏览器如何处理子资源完整性
浏览器通过执行以下操作来处理 SRI:
-
当浏览器遇到带有
integrity属性的<script>或<link>元素时,在执行脚本或应用<link>元素指定的任何样式表之前,浏览器必须首先将脚本或样式表与integrity值中提供的预期哈希进行比较。对于从与嵌入它的文档不同源提供的资源的子资源完整性验证,浏览器还会使用 跨域资源共享 (CORS) 来额外检查该资源,以确保提供该资源的源允许它与请求的源共享。
-
如果脚本或样式表与其关联的
integrity值不匹配,浏览器必须拒绝执行脚本或应用样式表,而应返回一个网络错误,表明获取该脚本或样式表失败。
完整性策略
Integrity-Policy 和 Integrity-Policy-Report-Only HTTP 头部允许文档强制执行有关加载的脚本和样式表子资源的完整性元数据要求的策略。
当指定 Integrity-Policy 头部时,浏览器会阻止发出 no-cors 模式或没有 integrity 属性的请求,并且如果指定了有效的报告端点,还会报告违规行为。当指定 Integrity-Policy-Report-Only 头部时,浏览器允许违规策略的请求,但会将违规行为报告给报告端点(如果指定了有效的报告端点)。
开发者通常会在其完整性策略的实现过程中,首先使用 Integrity-Policy-Report-Only 作为第一步部署,以确保其文档中加载的所有脚本和样式表都具有相应的完整性元数据。一旦他们看到没有收到违规报告,他们就知道可以使用 Integrity-Policy 头部启用阻止功能,而不会冒用户界面中断的风险。
头值被定义为具有以下键的结构化字段字典
blocked-destinations-
定义了一组要阻止的 请求目标。唯一允许的值是
script和style。 sources可选-
定义了一组完整性源。默认且目前唯一支持的值是
inline。因此,将sources=(inline)添加到头部与省略sources的效果类似。 endpoints可选-
定义了一组 报告端点。报告端点需要在
Reporting-Endpoints头部中定义。
在完整性策略阻止请求的情况下,会创建一个类型为 integrity-violation 的 Reporting API 违规报告,其主体类型为 IntegrityViolationReportBody,其中包含有关文档 URL 和被阻止资源等信息。
典型的报告可能如下所示:
{
"type": "integrity-violation",
"url": "https://example.com",
"body": {
"documentURL": "https://example.com",
"blockedURL": "https://example.com/main.js",
"destination": "script",
"reportOnly": false
}
}
示例
在以下示例中,假设 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"
crossorigin="anonymous"></script>
注意:有关 crossorigin 属性用途的更多详细信息,请参阅 CORS 设置属性。
使用 Integrity-Policy 头部执行完整性
您可以将 Integrity-Policy 头部添加到您的文档中,以确保它加载的外部资源(在此例中是脚本)具有完整性(并且不是以 no-cors 模式加载)
Integrity-Policy: blocked-destinations=(script), endpoints=(integrity-endpoint, some-other-integrity-endpoint)
如果您不确定所有外部脚本是否都具有完整性元数据,您可以启用该功能的报告模式版本,并开始接收违规报告。您可以使用 Integrity-Policy-Report-Only 头部来做到这一点。
Integrity-Policy-Report-Only: blocked-destinations=(script), endpoints=(integrity-endpoint, some-other-integrity-endpoint)
规范
| 规范 |
|---|
| HTML # attr-link-integrity |
| HTML # attr-script-integrity |
| 子资源完整性 # the-integrity-attribute |
浏览器兼容性
html.elements.link.integrity
加载中…
html.elements.script.integrity
加载中…