JS `Subresource Integrity` (SRI) `Hash Algorithm` 选择与碰撞风险

admin
Thu, 17 Jul 2025 09:51:27 +0000
Javascript, integrity, js, subresource

嘿，大家好！欢迎来到今天的“前端安全脱口秀”！我是你们的老朋友，专门负责把那些枯燥的安全概念，嚼碎了喂给你们，保证消化良好，还能举一反三！ 今天我们要聊的是Subresource Integrity（SRI），以及它背后藏着的Hash Algorithm选择和碰撞风险。这玩意儿，说白了，就是给你的外部资源文件（比如CDN上的JS、CSS）加个“身份证”，防止它们被人偷偷换掉，给你搞个大新闻！ Part 1：SRI 是个啥？ 为什么要用它？ 想象一下，你辛辛苦苦写了个网站，用了很多第三方库，比如jQuery、Bootstrap，为了速度，你把它们放在了CDN上。但是，万一CDN被黑了，或者CDN供应商自己“手滑”了，把这些库的文件内容改了，你的网站就可能出现各种奇奇怪怪的问题，甚至被植入恶意代码！ SRI就是来解决这个问题的。它通过计算资源文件的Hash值，然后把这个Hash值放在你的HTML标签里。浏览器在加载资源的时候，会重新计算资源文件的Hash值，如果和HTML标签里声明的Hash值不一样，就说明文件被篡改了，浏览器就会拒绝加载这个文件。 就像你去超市买东西，包装上都有个条形码。 …

继续阅读“JS `Subresource Integrity` (SRI) `Hash Algorithm` 选择与碰撞风险”

The post JS `Subresource Integrity` (SRI) `Hash Algorithm` 选择与碰撞风险 first appeared on 智猿学院-前后端，数据库，人工智能，云计算等领域前沿技术讲座.

嘿，大家好！欢迎来到今天的“前端安全脱口秀”！我是你们的老朋友，专门负责把那些枯燥的安全概念，嚼碎了喂给你们，保证消化良好，还能举一反三！

今天我们要聊的是Subresource Integrity（SRI），以及它背后藏着的Hash Algorithm选择和碰撞风险。这玩意儿，说白了，就是给你的外部资源文件（比如CDN上的JS、CSS）加个“身份证”，防止它们被人偷偷换掉，给你搞个大新闻！

Part 1：SRI 是个啥？ 为什么要用它？

想象一下，你辛辛苦苦写了个网站，用了很多第三方库，比如jQuery、Bootstrap，为了速度，你把它们放在了CDN上。但是，万一CDN被黑了，或者CDN供应商自己“手滑”了，把这些库的文件内容改了，你的网站就可能出现各种奇奇怪怪的问题，甚至被植入恶意代码！

SRI就是来解决这个问题的。它通过计算资源文件的Hash值，然后把这个Hash值放在你的HTML标签里。浏览器在加载资源的时候，会重新计算资源文件的Hash值，如果和HTML标签里声明的Hash值不一样，就说明文件被篡改了，浏览器就会拒绝加载这个文件。

就像你去超市买东西，包装上都有个条形码。收银员扫一下条形码，就知道你买的是什么东西，价格是多少。如果有人偷偷把条形码换了，收银员扫出来的东西就不对了。SRI就是给你的资源文件加了个“条形码”，浏览器就是那个收银员，用来验证文件是否被篡改。

Part 2：Hash Algorithm 的选择： 选哪个？怎么选？

SRI的核心就是Hash算法。Hash算法有很多种，比如MD5、SHA-1、SHA-256、SHA-384、SHA-512等等。那么问题来了，我们应该选哪个呢？

首先，MD5和SHA-1已经被认为是不安全的了。它们太老了，容易发生碰撞（后面会讲到什么是碰撞）。所以，千万不要用MD5和SHA-1！ 这就像你还用着大哥大，别人都用上智能手机了，太Out了！

目前推荐使用的是SHA-256、SHA-384和SHA-512。这三个都是SHA-2家族的成员，安全性较高。它们的区别在于Hash值的长度不同：

SHA-256：Hash值长度为256位（32字节），通常表示为64个十六进制字符。

SHA-384：Hash值长度为384位（48字节），通常表示为96个十六进制字符。

SHA-512：Hash值长度为512位（64字节），通常表示为128个十六进制字符。

Hash值越长，安全性越高，但同时也会增加HTML文件的大小。一般来说，SHA-384是一个比较好的折中方案，既保证了安全性，又不会让HTML文件变得太大。当然，如果你的网站对安全性要求非常高，也可以选择SHA-512。

选择建议：

算法 | Hash值长度 | 安全性 | 性能 (相对) | 推荐程度
MD5 | 128位 | 低 | 高 | 不推荐
SHA-1 | 160位 | 低 | 中 | 不推荐
SHA-256 | 256位 | 中 | 中 | 推荐
SHA-384 | 384位 | 高 | 低 | 强烈推荐
SHA-512 | 512位 | 高 | 低 | 推荐

Part 3： 碰撞风险： 撞衫不可怕， 撞Hash就完蛋了！

什么是碰撞？简单来说，就是两个不同的文件，计算出来的Hash值是一样的。这就像两个人穿了完全一样的衣服，走在大街上，很容易让人认错。

虽然SHA-2家族的Hash算法碰撞的概率非常低，但是理论上是存在的。如果发生了碰撞，就意味着攻击者可以制作一个恶意文件，它的Hash值和你的合法文件的Hash值一样，然后替换掉你的合法文件，浏览器就无法检测到篡改了！

碰撞概率：

碰撞概率取决于Hash值的长度。Hash值越长，碰撞的概率越低。以下是一些理论上的碰撞概率：

SHA-256：在生成2^128个不同的Hash值后，碰撞的概率约为50%。

SHA-384：在生成2^192个不同的Hash值后，碰撞的概率约为50%。

SHA-512：在生成2^256个不同的Hash值后，碰撞的概率约为50%。

看起来这些概率非常低，但是要知道，互联网上的文件数量非常庞大，攻击者可以通过大量的计算，来寻找碰撞。

如何降低碰撞风险？

1. 选择更长的Hash算法： SHA-384和SHA-512比SHA-256更安全，因为它们的Hash值更长，碰撞的概率更低。

2. 定期更新Hash值： 即使没有发生碰撞，也应该定期更新Hash值。这可以降低攻击者利用旧的碰撞结果来攻击你的网站的风险。

3. 使用多个Hash算法： 可以同时使用多个Hash算法来计算同一个文件的Hash值。这样，即使其中一个Hash算法发生了碰撞，其他的Hash算法仍然可以检测到篡改。

Part 4： 如何使用 SRI？ 代码示例！

说了这么多理论，现在我们来看看如何在HTML中使用SRI。其实很简单，只需要在 和 标签里添加integrity属性即可。

1. 计算Hash值：

首先，你需要计算资源文件的Hash值。可以使用各种工具来计算，比如OpenSSL、在线Hash计算器等等。这里以OpenSSL为例：

openssl dgst -sha384 your-file.js -binary | openssl base64 -A

这个命令会计算your-file.js文件的SHA-384 Hash值，并将结果以Base64编码输出。

2. 添加到HTML标签：

然后，把计算出来的Hash值添加到 或 标签的integrity属性中。

<script src="https://cdn.example.com/your-file.js"
        integrity="sha384-YOUR_HASH_VALUE"
crossorigin="anonymous">

<link rel="stylesheet"
      href="https://cdn.example.com/your-file.css"
      integrity="sha384-YOUR_HASH_VALUE"
      crossorigin="anonymous">

注意：

integrity属性的值必须以算法名称-Hash值的格式。

crossorigin属性是必须的，用于解决跨域资源共享（CORS）问题。通常设置为anonymous。

3. 多个Hash值：

如果你想使用多个Hash算法，可以在integrity属性中添加多个Hash值，用空格分隔。

<script src="https://cdn.example.com/your-file.js"
        integrity="sha384-SHA384_HASH sha512-SHA512_HASH"
crossorigin="anonymous">

Part 5： 常见问题和注意事项

动态生成的资源文件： 如果你的资源文件是动态生成的，每次内容都会变化，那么SRI就无法使用了。因为你无法提前知道Hash值。

CDN 故障： 如果CDN挂了，浏览器就无法加载资源文件，你的网站就会出错。所以，你需要做好CDN故障的应对措施，比如使用多个CDN，或者在本地备份资源文件。

浏览器兼容性： SRI的兼容性还是不错的，主流浏览器都支持。但是，一些老版本的浏览器可能不支持，所以你需要做好兼容性处理。

Hash值计算错误： 一定要确保你计算出来的Hash值是正确的。如果Hash值计算错误，浏览器就无法加载资源文件。

版本更新： 当 CDN 上的文件更新时，记得更新你 HTML 中的 integrity 值。

代码示例：使用 Node.js 计算 SRI Hash

如果你想在你的构建流程中自动计算 SRI Hash，可以使用 Node.js 的 crypto 模块。

const crypto = require('crypto');
const fs = require('fs');

function generateSRIHash(filePath, algorithm = 'sha384') {
  const fileBuffer = fs.readFileSync(filePath);
  const hash = crypto.createHash(algorithm);
  hash.update(fileBuffer);
  const sriHash = `${algorithm}-${hash.digest('base64')}`;
  return sriHash;
}

const jsFilePath = 'path/to/your/file.js';
const cssFilePath = 'path/to/your/file.css';

const jsSRI = generateSRIHash(jsFilePath);
const cssSRI = generateSRIHash(cssFilePath);

console.log(`JS SRI Hash: ${jsSRI}`);
console.log(`CSS SRI Hash: ${cssSRI}`);

// Example usage in HTML:
//
//

总结：

SRI是一个非常有用的安全机制，可以帮助你防止恶意代码注入。虽然它不能解决所有安全问题，但是它可以提高你的网站的安全性。选择合适的Hash算法，定期更新Hash值，做好CDN故障的应对措施，就可以最大程度地降低安全风险。

今天就到这里了，希望大家有所收获！记住，网络安全，人人有责！下次再见！