Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/395.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript node.js-使用Healmet为socket.io(web套接字)更正内容安全策略_Javascript_Node.js_Websocket_Socket.io_Content Security Policy - Fatal编程技术网

Javascript node.js-使用Healmet为socket.io(web套接字)更正内容安全策略

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

我试图在节点服务器中实现内容安全策略(CSP),但在设置socket.io时遇到问题。看起来我在下面的代码中错误地设置了
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”
匹配具有相同主机、端口和方案的请求。由于您的原始页面加载了scheme
http://
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);
});