我有一个由express托管的角度ssr应用程序。我正在使用谷歌分析,现在我想使用头盔.js 来强化我的应用程序。
现在我面临着谷歌分析内联脚本违反了 SCP。
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-xxxxxxx');
</script>
Google 说我应该使用随机数来识别我的脚本,不,我不想使用不安全的内联设置,因为这确实是很糟糕的做法。有人有示例代码吗?
我尝试了很多来自谷歌和聊天gpt的代码。
在高层次上,您将执行以下操作:
res.locals.cspNonce
或同等格式。nonce
HTML 属性添加到相关的 <script>
或 <style>
标签。首先,您需要生成一个随机数并将其保存到
res.locals
。猜测这个随机数应该很困难,因此我们将生成 32 个随机字节(256 个随机位)并将它们转换为十六进制字符串。
import * as crypto from "node:crypto";
// ...
app.use((_req, res, next) => {
// Asynchronously generate a unique nonce for each request.
crypto.randomBytes(32, (err, randomBytes) => {
if (err) {
// If there was a problem, bail.
next(err);
} else {
// Save the nonce, as a hex string, to `res.locals` for later.
res.locals.cspNonce = randomBytes.toString("hex");
next();
}
});
});
接下来,告诉 Helmet 这个随机数。更具体地说,告诉
script-src
指令。
在此示例中,我们计划将此随机数与
<script>
标签一起使用。如果您想使用内联样式,请使用 styleSrc
指令。
app.use(
helmet({
contentSecurityPolicy: {
directives: {
scriptSrc: [
"'self'",
// Include this nonce in the `script-src` directive.
(_req, res) => `'nonce-${res.locals.cspNonce}'`,
],
},
},
}),
);
最后,您需要设置
nonce
或 <script>
标签的 <style>
属性。
您可能正在使用 Pug 或 EJS 等模板引擎,但我们会为此示例做一些更简单的事情,仅内联发送 HTML。
app.get("/", (_req, res) => {
// When rendering the `<script>` tag, include the nonce.
res.send(`
<script nonce="${res.locals.cspNonce}">
console.log("Hello world!");
</script>
`);
});
如果您已正确完成所有操作,您应该会看到“Hello world!”在控制台中。每次刷新页面时,您还应该看到不同的
nonce
值。
这是此示例的完整源代码。
import express from "express";
import helmet from "helmet";
import * as crypto from "node:crypto";
const app = express();
app.use((_req, res, next) => {
// Asynchronously generate a unique nonce for each request.
crypto.randomBytes(32, (err, randomBytes) => {
if (err) {
// If there was a problem, bail.
next(err);
} else {
// Save the nonce, as a hex string, to `res.locals` for later.
res.locals.cspNonce = randomBytes.toString("hex");
next();
}
});
});
app.use(
helmet({
contentSecurityPolicy: {
directives: {
scriptSrc: [
"'self'",
// Include this nonce in the `script-src` directive.
(_req, res) => `'nonce-${res.locals.cspNonce}'`,
],
},
},
}),
);
app.get("/", (_req, res) => {
// When rendering the `<script>` tag, include the nonce.
res.send(`
<script nonce="${res.locals.cspNonce}">
console.log("Hello world!");
</script>
`);
});
app.listen(3000);
有关更多信息,请参阅头盔文档。