Javascript node.js-使用Healmet为socket.io(web套接字)更正内容安全策略
我试图在节点服务器中实现内容安全策略(CSP),但在设置socket.io时遇到问题。看起来我在下面的代码中错误地设置了Javascript node.js-使用Healmet为socket.io(web套接字)更正内容安全策略,javascript,node.js,websocket,socket.io,content-security-policy,Javascript,Node.js,Websocket,Socket.io,Content Security Policy,我试图在节点服务器中实现内容安全策略(CSP),但在设置socket.io时遇到问题。看起来我在下面的代码中错误地设置了connectSrc。有人能建议正确的方法来设置头盔,以便浏览器允许web套接字连接吗?提前谢谢 我正在使用头盔模块生成CSP;以下是设置CSP的代码: securitySetup = function(app) { var connectSources, helmet, scriptSources, styleSources; helmet = require("he
connectSrc
。有人能建议正确的方法来设置头盔,以便浏览器允许web套接字连接吗?提前谢谢
我正在使用头盔模块生成CSP;以下是设置CSP的代码:
securitySetup = function(app) {
var connectSources, helmet, scriptSources, styleSources;
helmet = require("helmet");
app.use(helmet());
app.use(helmet.hidePoweredBy());
app.use(helmet.noSniff());
app.use(helmet.crossdomain());
scriptSources = ["'self'", "'unsafe-inline'", "'unsafe-eval'", "ajax.googleapis.com"];
styleSources = ["'self'", "'unsafe-inline'", "ajax.googleapis.com"];
connectSources = ["'self'"];
return app.use(helmet.contentSecurityPolicy({
defaultSrc: ["'self'"],
scriptSrc: scriptSources,
styleSrc: styleSources,
connectSrc: connectSources,
reportUri: '/report-violation',
reportOnly: false,
setAllHeaders: false,
safari5: false
}));
};
这对于所有HTTP/AJAX流量都可以正常工作,但对于ws://协议则不行。在进行socket.io连接时,我在chrome调试器中遇到此错误:
Refused to connect to 'ws://localhost:3000/socket.io/1/websocket/ubexeZHZiAHwAV53WQ7u' because it violates the following Content Security Policy directive: "connect-src 'self'".
添加指定协议的地址为我解决了问题
connectSources = ["'self'", "ws://localhost:3000"]
仔细阅读说明了为什么“self”
不起作用:
“self”
匹配具有相同主机、端口和方案的请求。由于您的原始页面加载了schemehttp://
或https://
,'self'
将与使用ws://
的连接不匹配
这使得
“self”
对于websocket连接来说毫无用处。除非我遗漏了什么,否则我认为这是规范中的一个bug。您可以使用ws:或wss:作为websocket的关键字,下面是我的代码用法
app.use(helmet.csp({
'default-src': ["'self'"],
'connect-src': [
"'self'" , "blob:",
'wss:',
'websocket.domain',
],
'font-src': ["'self'",'s3.amazonaws.com',"maxcdn.bootstrapcdn.com"],
'img-src': ["'self'", 'data:'],
'style-src': ["'self'","maxcdn.bootstrapcdn.com",'s3.amazonaws.com',"'unsafe-inline'"],
'script-src': ["'self'","'unsafe-inline'","'unsafe-eval'",'blob:'],
reportOnly: false,
setAllHeaders: false,
safari5: false
}))
与wss://websocket.domain 是websocket的域,因此如果您可以将其用于localhost,这里有一种在express中自动添加当前主机和端口的方法(es6语法):
晚会有点晚了,但我想我会在这个问题上加入一些东西@Ed4是非常正确的,
'self'
实际上只会匹配相同的主机、端口和方案。一种解决方法是将其包括在一种或多种形式中:
connectsrc:wss:
-允许连接到整个wss
方案-基本上任何web套接字(可能不理想)
connectsrc:wss://yoursite.domain.com
-将其限制到特定端点。这是最理想的,但如果您的子域在部署之间发生更改(就像我们的子域一样),则可能会受到限制
connectsrc:wss://*.domain.com
-可以在其中使用通配符来加强安全性。这就是我们要做的
TL;DR-使用通配符使事情更加具体,而不必向任何web套接字敞开大门/
参考谷歌开发者的这段话:
每个指令中的源列表都是灵活的。您可以按方案(数据:,https:)指定源,或者指定范围从仅主机名(example.com,它匹配该主机上的任何源:任何方案,任何端口)到完全限定的URI(,它仅匹配https,仅example.com,仅匹配端口443)。通配符可以接受,但只能作为方案、端口或主机名最左边的位置:://.example.com:*将匹配example.com的所有子域(但不是example.com本身),在任何端口上使用任何方案
我认为你的
连接源代码
规则是有责任的。为您的应用程序提供服务的Web服务器是否也在端口3000上运行?在源列表引用“self”下表示:允许从同一来源(相同的方案、主机和端口)加载资源。@marco:是的,web套接字服务器与web应用程序的http服务器是同一服务器。看起来问题出在同一个“方案”部分(ws://vs http://),那么我认为Patrik Simek的答案也应该适用于您。也许你可以对此发表评论,或者如果它有效的话,你可以接受它作为正确的答案?是的,我们可以这样做,但是这样做违背了“自我”关键字的目的,不是吗?如果我们需要添加确切的服务器名称、端口等,那么为什么我们需要这种自营业务呢?如果能够以某种方式解决这一问题,尤其是对于部署到内部网络的SPA来说,这是一个麻烦(在这些网络中,域可能并不总是已知或可能经常更改)。似乎这在Chrome中不再是一个问题('self'按预期工作),但在Safari中,我必须连接src:wss://*.domain.com,它可以工作。
import csp from 'helmet-csp';
app.use((req, res, next) => {
let wsSrc = (req.protocol === 'http' ? 'ws://' : 'wss://') + req.get('host');
csp({
connectSrc: ['\'self\'', wsSrc],
})(req, res, next);
});