如何在style和script src中添加nonce?通过Webpack适配严格CSP
如何在Angular CLI 1.6.3 + Angular 5.2.0中为script/style的src添加nonce以适配严格CSP规则
针对你当前的技术栈,要实现给外部引入的script和style标签添加nonce属性来满足严格的内容安全策略(CSP)要求,我们可以通过自定义Webpack配置结合模板改造来完成,具体步骤如下:
1. 暴露Webpack配置文件(可选,不想eject可看替代方案)
Angular CLI 1.6.3默认隐藏Webpack配置,你可以通过eject命令把配置文件导出到项目根目录:
ng eject
执行后会生成webpack.config.js,注意此操作不可逆,之后部分Angular CLI命令可能无法使用。
2. 生成并传递nonce到Webpack配置
在webpack.config.js顶部引入Node的crypto模块生成安全的随机nonce,然后将其传递给HtmlWebpackPlugin:
// 在文件顶部添加 const crypto = require('crypto'); // 生成16字节的base64格式nonce(安全度较高) const nonce = crypto.randomBytes(16).toString('base64'); // 找到HtmlWebpackPlugin的配置项,修改为: new HtmlWebpackPlugin({ template: './src/index.ejs', // 后续会将html改为ejs模板 inject: false, // 关闭自动注入,我们手动在模板中处理资源引入 nonce: nonce, // 保留原有的filename、hash、chunks等配置项 })
3. 修改index.html为ejs模板,手动注入带nonce的资源
把src/index.html重命名为src/index.ejs,通过ejs语法循环生成带nonce属性的script和style标签:
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>你的应用名称</title> <base href="/"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" type="image/x-icon" href="favicon.ico"> <!-- 生成带nonce的style标签 --> <% for (const cssPath of Object.values(htmlWebpackPlugin.files.css)) { %> <link href="<%= cssPath %>" rel="stylesheet" nonce="<%= htmlWebpackPlugin.options.nonce %>"> <% } %> </head> <body> <app-root></app-root> <!-- 生成带nonce的script标签 --> <% for (const chunk of Object.values(htmlWebpackPlugin.files.chunks)) { %> <script src="<%= chunk.entry %>" nonce="<%= htmlWebpackPlugin.options.nonce %>"></script> <% } %> </body> </html>
4. 配置服务器端的CSP头部
最后要在你的服务器(如Nginx、Express等)设置Content-Security-Policy头部,允许带有该nonce的脚本和样式:
- 如果是Express服务器,示例代码:
app.use((req, res, next) => { const nonce = crypto.randomBytes(16).toString('base64'); // 注意:这里的nonce要和Webpack生成的保持一致,建议将Webpack生成的nonce传递到服务器端 res.setHeader( 'Content-Security-Policy', `default-src 'self'; script-src 'nonce-${nonce}'; style-src 'nonce-${nonce}';` ); next(); });
- 如果是Nginx,在配置中添加:
add_header Content-Security-Policy "default-src 'self'; script-src 'nonce-<你的nonce值>'; style-src 'nonce-<你的nonce值>';";
注意:动态生成nonce时,必须确保Webpack和服务器使用同一个nonce值,否则CSP会拦截资源加载。
不eject的替代方案(可选)
如果你不想执行ng eject,可以使用@angular-builders/custom-webpack(对应5.x版本,适配Angular 5)扩展Webpack配置:
- 安装依赖:
npm install @angular-builders/custom-webpack@5 --save-dev
- 修改
.angular-cli.json,将defaults.build.builder改为:
"builder": "@angular-builders/custom-webpack:browser"
并添加自定义Webpack配置的路径:
"customWebpackConfig": { "path": "./webpack.custom.js" }
- 创建
webpack.custom.js,写入之前Webpack配置中关于nonce和HtmlWebpackPlugin的修改逻辑即可。
内容的提问来源于stack exchange,提问作者user3300741
相关产品推荐
相关产品推荐

