[英]node.js - correct content security policy for socket.io (web sockets) using helmet
I am trying to implement content security policies (CSP) in a node server, and am having trouble setting up socket.io. 我正在尝试在节点服务器中实现内容安全策略(CSP),并且在设置socket.io时遇到问题。 It looks like I am setting up the
connectSrc
incorrectly in the code below. 看起来我在下面的代码中错误地设置了
connectSrc
。 Could someone suggest the correct way to set up helmet so that web socket connections are allowed by the browser? 有人建议设置头盔的正确方法,以便浏览器允许Web套接字连接吗? Thanks in advance!
提前致谢!
I am using helmet module for generation of CSP; 我使用头盔模块生成CSP; the following is the code that sets up 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
}));
};
This works fine for all HTTP/AJAX traffic, but fails for ws:// protocol. 这适用于所有HTTP / AJAX流量,但对于ws://协议失败。 I get this error in chrome debugger when socket.io connection is made:
当进行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'".
A close reading of the Content Security Policy spec explains why 'self'
doesn't work: 仔细阅读内容安全政策规范可以解释为什么
'self'
不起作用:
'self'
matches requests with the same host, port, and scheme . 'self'
匹配具有相同主机,端口和方案的请求。 Since your original page loaded with the scheme http://
or https://
, 'self'
won't match connections using ws://
. 由于您的原始页面加载了方案
http://
或https://
,因此'self'
与使用ws://
连接不匹配。
This makes 'self'
rather useless for websocket connections. 这使得
'self'
对于websocket连接毫无用处。 Unless I'm missing something, I think this is a bug in the spec. 除非我遗漏了什么,否则我认为这是规范中的一个错误。
添加指定协议的地址解决了我的问题。
connectSources = ["'self'", "ws://localhost:3000"]
Bit late to the party, but thought I'd throw something into the mix on this subject. 派对迟到了,但我想我会在这个主题上加入一些东西。 @Ed4 is quite right,
'self'
will indeed only match the same host, port and scheme. @ Ed4非常正确,
'self'
确实只会匹配相同的主机,端口和方案。 A way around it is to include it in one or more forms: 解决它的方法是将其包含在一种或多种形式中:
connect-src: wss:
- to allow a connection to the whole wss
scheme - basically any web socket (probably not ideal) connect-src: wss:
- 允许连接到整个wss
方案 - 基本上任何 web套接字(可能不理想)
connect-src: wss://yoursite.domain.com
- to restrict it to a specific endpoint. connect-src: wss://yoursite.domain.com
- 将其限制为特定端点。 This is most ideal, but might be restrictive if your subdomain changes between deployments (as ours do) 这是最理想的,但如果您的子域在部署之间发生更改(如我们所做的那样),则可能会受到限制
connect-src: wss://*.domain.com
- can use wildcards in there to tighten security up a bit. connect-src: wss://*.domain.com
- 可以在那里使用通配符来加强安全性。 This is what we do 这就是我们的工作
TL;DR - use wildcards to make things more specific without just opening yourself up to any web sockets out there/ TL; DR - 使用通配符使事情变得更具体,而不仅仅是打开任何网络套接字/
Refer to this passage from Google devs: 请参阅Google开发者的这篇文章:
The source list in each directive is flexible.
每个指令中的源列表都是灵活的。 You can specify sources by scheme (data:, https:), or ranging in specificity from hostname-only (example.com, which matches any origin on that host: any scheme, any port) to a fully qualified URI ( https://example.com:443 , which matches only HTTPS, only example.com, and only port 443).
您可以按方案(data:,https :)指定源,或者从仅限主机名(example.com,与该主机上的任何源匹配:任何方案,任何端口)的特定范围指定为完全限定的URI( https:/ /example.com:443 ,仅匹配HTTPS,仅匹配example.com,仅匹配端口443)。 Wildcards are accepted, but only as a scheme, a port, or in the leftmost position of the hostname: :// .example.com:* would match all subdomains of example.com (but not example.com itself), using any scheme, on any port.
接受通配符,但仅作为方案,端口或主机名的最左侧位置:: // .example.com:*将匹配example.com的所有子域(但不是example.com本身),使用任何计划,在任何港口。
https://developers.google.com/web/fundamentals/security/csp/ https://developers.google.com/web/fundamentals/security/csp/
Here's a way to automatically add the current host and port in express (es6 syntax): 这是一种在express(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);
});
you can use ws: or wss: as keyword for websocket, here is my code use 你可以使用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
}))
with wss://websocket.domain is domain for websocket so if you can use it for localhost 使用wss://websocket.domain是websocket的域名,所以如果你可以将它用于localhost
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.