node.js – 使用头盔修正socket.io(web套接字)的内容安全策略

我试图在节点服务器中实现内容安全策略(CSP),并且在设置socket.io时遇到困难。 它看起来像我在下面的代码中设置不正确的connectSrc 。 有人可以build议正确的方式来设置头盔,以便浏览器允许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 / AJAXstream量,但对ws://协议失败。 在socket.io连接时,在chromedebugging器中出现这个错误:

 Refused to connect to 'ws://localhost:3000/socket.io/1/websocket/ubexeZHZiAHwAV53WQ7u' because it violates the following Content Security Policy directive: "connect-src 'self'". 

Chrome控制台错误

       

网上收集的解决方案 "node.js – 使用头盔修正socket.io(web套接字)的内容安全策略"

用指定的协议添加地址解决了我的问题。

 connectSources = ["'self'", "ws://localhost:3000"] 

仔细阅读内容安全策略规范解释了为什么'self'不起作用:

'self'使用相同的主机,端口和scheme匹配请求。 由于您的原始页面使用schemehttp://https://'self'加载,将不会使用ws://匹配连接。

这使得'self'对websocket连接而言毫无用处。 除非我错过了一些东西,我认为这是规范中的一个错误。

你可以使用ws:或者wss:as关键字作为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的域名,所以如果你可以使用它的本地主机

晚会晚了,但认为我会在这个问题上投入一些东西。 @ Ed4是相当正确的, 'self'确实只能匹配相同的主机,端口和scheme。 解决方法是将其包含在一个或多个表单中:

connect-src: wss: – 允许连接到整个wssscheme – 基本上任何 web套接字(可能都不是理想的)

connect-src: wss://yoursite.domain.com – 将其限制为特定的端点。 这是最理想的,但是如果你的子域在部署之间改变(如我们的那样)

connect-src: wss://*.domain.com – 可以使用通配符来提高安全性。 这就是我们所做的

TL; DR – 使用通配符使事情更具体,而不需要打开自己的网站,

请参阅Google开发者的这段话:

每个指令中的源列表是灵活的。 您可以通过scheme(data :, https :)指定源,或者仅从主机名(example.com,匹配该主机上的任何源:任何scheme,任何端口)到特定URI( https: /example.com:443 ,仅匹配HTTPS,仅匹配example.com,仅匹配443端口)。 通配符被接受,但只作为scheme,端口或主机名的最左边位置:// .example.com:*将匹配example.com的所有子域(但不是example.com本身),使用任何计划,在任何港口。

https://developers.google.com/web/fundamentals/security/csp/

这是一种自动添加当前主机和端口的方式(es6语法):

 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); });