diff --git a/CHANGELOG.md b/CHANGELOG.md index b9cc377c5e..e8552f75af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## [2.4.1](https://github.com/socketio/socket.io/compare/2.4.0...2.4.1) (2021-01-07) + + +### Reverts + +* fix(security): do not allow all origins by default ([a169050](https://github.com/socketio/socket.io/commit/a1690509470e9dd5559cec4e60908ca6c23e9ba0)) + + # [2.4.0](https://github.com/socketio/socket.io/compare/2.3.0...2.4.0) (2021-01-04) diff --git a/lib/index.js b/lib/index.js index 3cae6c10de..5287e4ead0 100644 --- a/lib/index.js +++ b/lib/index.js @@ -54,7 +54,7 @@ function Server(srv, opts){ this.parser = opts.parser || parser; this.encoder = new this.parser.Encoder(); this.adapter(opts.adapter || Adapter); - this.origins(opts.origins || []); + this.origins(opts.origins || '*:*'); this.sockets = this.of('/'); if (srv) this.attach(srv, opts); } @@ -67,18 +67,31 @@ function Server(srv, opts){ */ Server.prototype.checkRequest = function(req, fn) { - const origin = req.headers.origin; + var origin = req.headers.origin || req.headers.referer; - if (typeof this._origins === 'function') { - return this._origins(origin, fn); - } + // file:// URLs produce a null Origin which can't be authorized via echo-back + if ('null' == origin || null == origin) origin = '*'; + if (!!origin && typeof(this._origins) == 'function') return this._origins(origin, fn); + if (this._origins.indexOf('*:*') !== -1) return fn(null, true); if (origin) { - fn(null, this._origins.includes(origin)); - } else { - const noOriginIsValid = this._origins.length === 0; - fn(null, noOriginIsValid); + try { + var parts = url.parse(origin); + var defaultPort = 'https:' == parts.protocol ? 443 : 80; + parts.port = parts.port != null + ? parts.port + : defaultPort; + var ok = + ~this._origins.indexOf(parts.protocol + '//' + parts.hostname + ':' + parts.port) || + ~this._origins.indexOf(parts.hostname + ':' + parts.port) || + ~this._origins.indexOf(parts.hostname + ':*') || + ~this._origins.indexOf('*:' + parts.port); + debug('origin %s is %svalid', origin, !!ok ? '' : 'not '); + return fn(null, !!ok); + } catch (ex) { + } } + fn(null, false); }; /** @@ -224,7 +237,7 @@ Server.prototype.adapter = function(v){ Server.prototype.origins = function(v){ if (!arguments.length) return this._origins; - this._origins = typeof v === 'string' ? [v] : v; + this._origins = v; return this; }; diff --git a/package-lock.json b/package-lock.json index 940796ad51..ca0df4d6d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "socket.io", - "version": "2.4.0", + "version": "2.4.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 6309ee7aad..fb79d512f9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "socket.io", - "version": "2.4.0", + "version": "2.4.1", "description": "node.js realtime framework server", "keywords": [ "realtime", diff --git a/test/socket.io.js b/test/socket.io.js index 7252bb78e7..6cc085b798 100644 --- a/test/socket.io.js +++ b/test/socket.io.js @@ -73,7 +73,7 @@ describe('socket.io', function(){ it('should be able to set origins to engine.io', function() { var srv = io(http()); srv.set('origins', 'http://hostname.com:*'); - expect(srv.origins()).to.eql(['http://hostname.com:*']); + expect(srv.origins()).to.be('http://hostname.com:*'); }); it('should be able to set authorization and send error packet', function(done) { @@ -262,6 +262,17 @@ describe('socket.io', function(){ }); }); + it('should allow request when origin defined an the same is specified', function(done) { + var sockets = io({ origins: 'http://foo.example:*' }).listen('54015'); + request.get('http://localhost:54015/socket.io/default/') + .set('origin', 'http://foo.example') + .query({ transport: 'polling' }) + .end(function (err, res) { + expect(res.status).to.be(200); + done(); + }); + }); + it('should allow request when origin defined as function and same is supplied', function(done) { var sockets = io({ origins: function(origin,callback){ if (origin == 'http://foo.example') { @@ -296,7 +307,7 @@ describe('socket.io', function(){ it('should allow request when origin defined as function and no origin is supplied', function(done) { var sockets = io({ origins: function(origin,callback){ - if (origin === undefined) { + if (origin == '*') { return callback(null, true); } return callback(null, false); @@ -309,6 +320,17 @@ describe('socket.io', function(){ }); }); + it('should default to port 443 when protocol is https', function(done) { + var sockets = io({ origins: 'https://foo.example:443' }).listen('54036'); + request.get('http://localhost:54036/socket.io/default/') + .set('origin', 'https://foo.example') + .query({ transport: 'polling' }) + .end(function (err, res) { + expect(res.status).to.be(200); + done(); + }); + }); + it('should allow request if custom function in opts.allowRequest returns true', function(done){ var sockets = io(http().listen(54022), { allowRequest: function (req, callback) { return callback(null, true); @@ -345,17 +367,6 @@ describe('socket.io', function(){ done(); }); }); - - it('should disallow any origin by default', (done) => { - io().listen('54025'); - request.get('http://localhost:54025/socket.io/default/') - .set('origin', 'https://foo.example') - .query({ transport: 'polling' }) - .end((err, res) => { - expect(res.status).to.be(403); - done(); - }); - }); }); describe('close', function(){
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: