静态资源完整性校验
最近,用于兼容旧浏览器的 JS 静态资源服务 Polyfill.io CDN 被新的域名所有者修改脚本内容,在没有任何预警的情况下,向引入该资源的网站注入了恶意代码,导致大量站点出现自动跳转或被当作垃圾内容分发的风险。
研究员发现,这类问题的根源,是开发者默认信任了一个外部静态资源的内容,即便网站代码没动,用户访问时执行的脚本已经不再是原本安全的版本。
当你靠 <script src="..."> 引入第三方静态资源时,必须对内容完整性进行验证,否则无防护地信任 CDN 返回的脚本,等于把网站安全交给了外部服务的善意。通常,静态资源完整性校验通过在 HTML 文件中使用 Subresource Integrity (SRI) 实现。
SRI 允许浏览器在加载资源时验证资源的完整性,这是一种安全特性,通过为资源提供哈希值,浏览器在加载资源时可以验证资源是否未被篡改。
如何使用 SRI
- 生成哈希值
要使用 SRI,首先需要为静态资源生成哈希值。可以使用 openssl 工具来生成这些哈希值,常见的哈希算法有 SHA-256、SHA-384 和 SHA-512。
openssl dgst -sha384 -binary your-file.js | openssl base64 -A
例如,对于一个名为 main.js 的文件,可以使用以下命令生成哈希值:
openssl dgst -sha384 -binary main.js | openssl base64 -A
- 在 HTML 中使用 SRI
生成哈希值后,可以将其添加到 HTML 文件中对应的资源链接中。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="styles.css" integrity="sha384-<generated-hash-value>" crossorigin="anonymous">
</head>
<body>
<script src="main.js" integrity="sha384-<generated-hash-value>" crossorigin="anonymous"></script>
</body>
</html>
- 自动化生成 SRI 哈希值
对于大型项目,手动生成和管理 SRI 哈希值可能不现实,可以使用一些工具和插件来自动化这个过程。
使用 sri-hash 工具
sri-hash 是一个方便的命令行工具,可以自动生成 SRI 哈希值。
安装:
npm install -g sri-hash
使用:
sri-hash main.js
使用 webpack 插件
如果使用 webpack 进行项目构建,可以使用 webpack-subresource-integrity 插件来自动生成和注入 SRI 哈希值。
安装:
npm install webpack-subresource-integrity --save-dev
在 webpack 配置中使用:
const SriPlugin = require('webpack-subresource-integrity');
module.exports = {
// 其他配置...
output: {
crossOriginLoading: 'anonymous'
},
plugins: [
new SriPlugin({
hashFuncNames: ['sha256', 'sha384'],
enabled: process.env.NODE_ENV === 'production',
}),
],
};
- 验证 SRI 功能
完成上述配置后,部署应用并加载页面时,可以在浏览器开发者工具中查看网络请求。如果资源的哈希值不匹配,浏览器将拒绝加载该资源,并在控制台中显示错误信息。
注意事项
- 跨域资源:如果资源是跨域的,需要确保资源服务器设置了 CORS 头,以允许跨域请求。
- 缓存:确保生成 SRI 哈希值时资源是最终版本,避免由于缓存导致的哈希值不匹配问题。
- 兼容性:并非所有浏览器都支持 SRI,主要支持现代浏览器。