开发者工具 · SHA 哈希计算器
子资源完整性:浏览器如何使用 SHA-384 检查脚本
· 背景
sha-256 base64 浏览器 API 安全
完整性属性允许浏览器拒绝字节已更改的 CDN 脚本。这篇文章解释了属性的格式、为什么 base64 中的 SHA-384 是常见的选择,以及 SRI 无法防范的内容。
可以为任何事物提供服务的 CDN — SRI 的设计目的是为了应对供应链风险
网页上的脚本标记可以携带完整性属性:`<script src="https://cdn.example.com/lib.js" integrity="sha384-..."></script>`。完整性值是脚本字节的加密摘要。当浏览器下载脚本时,它会计算接收到的字节的摘要并与完整性属性进行比较。如果它们匹配,则加载脚本。如果它们不匹配,浏览器将拒绝加载它并在控制台中报告失败。这可以防止受损的 CDN 提供修改后的代码,或防止网络攻击者拦截和更改响应。
子资源完整性 (SRI) 是适用于脚本和样式表的 W3C 规范。这是浏览器可以对跨源资源的内容做出的唯一加密保证:字节必须与摘要匹配,否则资源将被拒绝。这并不能证明谁创建了该资源,只是证明自计算摘要以来该资源没有发生变化。对于从信誉良好的 CDN 通过 HTTPS 提供的资源,摘要提供了一种保护措施,防止 CDN 受到损害或专门向您提供过时的缓存内容。
完整性属性 — 算法前缀、连字符、base64 摘要和对多个哈希的支持
完整性属性具有特定的格式:算法名称、连字符、base64 格式的摘要。示例:`integrity="sha384-JZDdQnrrAMe+sxxpn47in+PwhkxrCrt4SNvt+xWqV3zPJUkeFF0Qq/wNtuvNqPP5"`。算法名称可以是 SHA-256、SHA-384 或 SHA-512。 Base64是编码,不是十六进制;这是 SRI 规范有意选择的。 Base64 比十六进制更紧凑(对于相同的摘要,大约短 33%),这在嵌入 HTML 属性时很重要。连字符将算法名称与摘要分开。可以列出多个完整性值,以空格分隔:如果其中任何一个匹配,则资源被接受。
为什么SHA-384? SRI 规范允许 SHA-256、SHA-384 和 SHA-512。 SHA-384 成为社区默认值,因为它提供了 /security 余额。 SHA-256 更小(32 字节,base64 中的 44 字符),但 SHA-384 更宽(48 字节,base64 中的 64 字符),并且与 SHA-256 相比,并没有显着增加属性大小。 SHA-512 可用,但很少使用,因为它的较大摘要对于此用例来说似乎没有必要。 SHA-384 的选择是历史性和实用性的,而不是高级安全属性的反映(为此目的,所有三个都具有强大的加密功能)。
SHA-384并生成所需的base64材料;社区偏好不是从该工具推断出来的
SRI中的Base64编码是标准base64,而不是base64url。标准 base64 使用 + 和 / 字符,它们在没有百分比编码的 HTML 属性中有效,尽管它们在 URL 和表单数据中具有特殊含义。 SRI 格式是为 HTML 属性而不是 URL 设计的,因此标准的 base64 是合适的。如果您手动构建完整性值,则计算 SHA-384 摘要(字节序列),然后将这些字节编码为标准 base64,然后在前面添加 `sha384-` 并粘贴到完整性属性中。
浏览器反向执行相同的步骤:从完整性属性中提取 base64,解码为字节以恢复摘要,计算下载的脚本字节的 SHA-384 并比较两个摘要值。它们必须完全匹配;摘要中的单个位差异会导致拒绝。不存在模糊匹配或部分信用:完整性是二元的。
跨域 SRI 行为需要除此哈希计算器之外的浏览器文档
SRI 要求跨域响应使用 CORS。如果您从不同的源加载脚本,服务器必须使用 `Access-Control-Allow-Origin: *` 或包含您的源标头的特定源标头进行响应。如果没有 CORS 标头,浏览器就无法检查 SRI,因为如果没有 CORS,浏览器就无法确认响应正文是否与服务器打算发送的内容相匹配。 CORS 标头是服务器的声明,表明此响应可以安全检查; SRI 用于检查字节是否正确。它们共同构成了供应链承诺:服务器允许您验证内容,您也可以这样做。
如果跨源脚本缺少 CORS 标头并具有完整性属性,则浏览器将下载它(如果站点的 CSP 允许来自该源的脚本),但不会验证完整性。该脚本将被加载,就好像完整性属性不存在一样。这并不是 SRI 的失败;而是 SRI 的失败。这是一个安全边界:您无法验证您无法读取的响应。
不匹配时会发生什么 - 浏览器阻止资源并在控制台中报告
当浏览器检测到完整性不匹配时,它会拒绝执行脚本并在浏览器控制台中记录一条消息。该消息通常会命名 URL、预期哈希值和计算出的哈希值。失败是原子性的:资源要么按原样加载,要么被完全拒绝。没有部分加载或回退。如果网站依赖该脚本并且被拒绝,则该网站可能会崩溃。这是故意的:提供错误的代码比不提供代码更糟糕,并且无声的故障使攻击无限期地持续下去。
测试 SRI 设置非常简单:打开浏览器控制台,加载页面并查找有关完整性不匹配的消息。如果您发现不匹配,请将控制台中显示的计算出的哈希值与完整性属性中的哈希值进行比较。如果它们不匹配,请重新计算:脚本可能已更新,您需要新的摘要。
工作示例 — 计算脚本摘要并将其格式化为完整性值,包括 base64 步骤
手动计算 SRI 摘要仅需要脚本字节和哈希工具。下载脚本,将其粘贴到 ToolAcre SHA 哈希计算器中,选择 SHA-384,复制 Base64 输出(不是十六进制),在前面加上 `sha384-` 并粘贴到完整性属性中。如果脚本很大,使用curl或wget将其保存到文件然后读取文件比粘贴更快。对于内联脚本(在 HTML 中的 `<script>` 标记中而不是来自 URL),SRI 不适用;根据定义,内联脚本始终是可信的。 SRI 用于外部资源。
一个有效的示例:假设您想使用 SRI 从 CDN 加载 jQuery。找到脚本 URL,下载它(或使用curl 获取它),将字节粘贴到计算器中或在命令行上使用 `sha384sum`,获取 SHA-384 摘要为 base64,并将格式设置为 `sha384-[base64-digest]`。粘贴到脚本标记的完整性属性中。加载页面并验证没有出现控制台错误。
这不包括什么 - 有意更改的脚本,以及像 ToolAcre 这样根本不加载外部脚本的网站,因此没有什么可固定的
SRI 不能防御所有供应链攻击。它可以防止在计算摘要后字节发生更改,但不能防止从受损代码开始计算摘要。如果在计算摘要之前 CDN 遭到破坏,SRI 将无法提供帮助。摘要的可信度取决于计算它的来源。为了获得最大程度的保证,请从原始源(例如,库的 GitHub 版本)计算摘要,并在从 CDN 加载时使用这些摘要。摘要在发布过程中成为维护者的承诺。
SRI 也无法在您计算摘要时防止网络受损,或开发机器受损。它仅防止在创建摘要和浏览器加载脚本之间对脚本进行更改。为了持续保证,除了 SRI 之外,某些部署还使用版本签名:版本由维护者的密钥进行签名,您验证签名,根据已验证的字节计算摘要并在 SRI 中使用它。
本文并未从哈希源断言 ToolAcre 的站点范围外部脚本清单
ToolAcre SHA 哈希计算器直接以标准 base64 发出摘要(作为 `toBase64()` 函数的 `base64` 输出)。要转换为 SRI 格式,请在前面添加算法名称和连字符:`sha256-`、`sha384-` 或 `sha512-`。计算器不会自动应用该前缀,因为哈希出现在许多上下文(git、Docker、npm、URL)中,其中算法名称是单独的或编码不同的。边界很明确:计算器对您粘贴的 UTF-8 文本进行哈希处理,而不是对文件或二进制密钥进行哈希处理。它输出十六进制和base64。您可以根据您的上下文选择使用哪个。对于 SRI,规范要求使用 base64。对于 git 和其他工具来说,十六进制是常规的。对于 npm 和 Go,使用 base64。编码选择由您决定;摘要字节是相同的。
SRI 仍然是浏览器可以在没有集中权限的情况下在客户端执行的少数加密检查之一。使用 ToolAcre 的 SHA 计算器等值得信赖的工具进行计算,并根据加载的资源验证它们是强化网站抵御某些供应链攻击的一种可行方法。保护效果取决于摘要;每次更新外部资源后重新计算,并测试浏览器加载脚本而不拒绝它。