当我尝试此操作时,作为头盔.js 设置的一部分,我收到错误。
'script-src': ["'self'", (req, res) => `'nonce-${res.locals.cspNonce}'`],
它可以通过
http://127.0.0.1:3000/
提供服务,但是在 https://www.example.com/
生产服务器上,在 Firefox 中,我得到:
Content Security Policy: The page's settings blocked the loading of a resource at inline ("script-src").
在 Chrome 中,它提供了更多信息:
Refused to execute inline script because it violates the following Content Security Policy directive:
"script-src 'self' 'nonce-b6c07d77ebd0956f28936386c1abef1b'".
Either the 'unsafe-inline' keyword, a hash ('sha256-YiQnvxxxnwHItf/iksvxxxxKGGMABdQbOU='), or a nonce ('nonce-...') is required to enable inline execution.
每次重新加载时nonce值都会改变,这符合我的理解。我假设如果需要的话,hellipjs 会自动将此随机数插入到 js 文件的标头中?我已按照 https://helmetjs.github.io/#reference 中显示的配置进行操作,但没有发现我必须执行的任何其他配置。
如果我将
"'strict-dynamic'",
添加到列表中,两个浏览器仍然会抱怨,但它们现在会抱怨特定文件:例如https://www.example.com/js/mylib.js
(即使它与加载的页面具有相同的域)我们不从第3方服务器加载JS,它始终由该服务器提供服务。 (但我们确实有一个兄弟域,https://auth.example.com/
运行一个框架。)
如果我更改为这个,那么一切都会正常:
'script-src': ["'self'", "'unsafe-inline'"],
如果我为每个 JS 文件添加
sha256-YiQn...
到 CSP,这意味着每次我们将新的错误修复推送到它所服务的任何网站时都需要修改生产服务器配置。那不是那样的。我一定错过了什么??
我也很好奇为什么它在 http://127.0.0.1:3000/
上运行良好(但框架并连接到制作
https://auth.example.com/
和 https://db.example.com/
)。有没有办法可以在本地测试一下,这样会更切合实际?
顺便说一句,最近的浏览器版本,所以我认为我们可以期待完整的 CSP3 支持;我们不需要支持 IE11 或任何旧版本。参考完整的非工作头盔配置:
const helmet = require('helmet')
const crypto = require('crypto')
...
app.use((req, res, next) => {
res.locals.cspNonce = crypto.randomBytes(16).toString('hex')
next()
})
app.use(helmet({
xFrameOptions: { action: 'deny' },
contentSecurityPolicy: {
directives: {
'script-src': ["'self'", (req, res) => `'nonce-${res.locals.cspNonce}'`],
'frame-src': ["'self'", 'auth.example.com'],
'connect-src': [
"'self'",
'auth.example.com',
'db.example.com',
],
'worker-src': ["'self'"]
},
},
}),
头盔版本7.1。
”)在开发和生产环境中应该以相同的方式工作。事实上,它适用于 localhost
但不适用于您的生产服务器,这表明环境或脚本包含在 HTML 中的方式存在差异。
<script>
标签。
例如,在像 EJS 这样的 Express.js 视图引擎中,您应该包含这样的随机数:
<script nonce="<%= res.locals.cspNonce %>">
// Your inline script here
</script>
此外,由于更严格的安全标准,CSP 策略在 HTTPS 下的行为可能会有所不同。这可以解释为什么它可以在
localhost
(HTTP) 上运行,但不能在生产服务器 (HTTPS) 上运行。确保您的 CSP 标头在两种环境中均已正确设置。
将'strict-dynamic'
(支持
Helmet 3.9.0+,2017 年第 4 季度)有时会有所帮助,但应谨慎使用,因为它允许脚本加载其他脚本。这可能不适合您的安全要求。 警告:虽然使用
'unsafe-inline'
可以使其工作,但它违背了严格 CSP 的目的。不建议用于生产,因为它允许所有内联脚本,使您的网站容易受到 XSS 攻击。
要以更实际的方式进行本地测试,请考虑在本地服务器上设置 HTTPS。 ngrok、localtunnel 等工具或设置自签名 SSL 证书可以帮助模拟类似生产的环境。
const helmet = require('helmet');
const crypto = require('crypto');
const express = require('express');
const app = express();
app.use((req, res, next) => {
res.locals.cspNonce = crypto.randomBytes(16).toString('hex');
next();
});
app.use(helmet({
xFrameOptions: { action: 'deny' },
contentSecurityPolicy: {
directives: {
'script-src': ["'self'", (req, res) => `'nonce-${res.locals.cspNonce}'`],
'frame-src': ["'self'", 'auth.example.com'],
'connect-src': ["'self'", 'auth.example.com', 'db.example.com'],
'worker-src': ["'self'"]
},
},
}));
// Rest of your express app setup...
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
请在脚本标签中正确包含随机数,如上所示。