Skip to content

Commit 2957853

Browse files
committed
enable Host header check for all requests and sockets
reported by @edmorley
1 parent 60e4727 commit 2957853

File tree

2 files changed

+46
-1
lines changed

2 files changed

+46
-1
lines changed

client/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ var onSocketMsg = {
119119
console.error(strippedErrors[i]);
120120
if(useErrorOverlay) overlay.showMessage(errors);
121121
},
122+
error: function(error) {
123+
console.error(error);
124+
},
122125
close: function() {
123126
log("error", "[WDS] Disconnected!");
124127
sendMsg("Close");

lib/Server.js

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ function Server(compiler, options) {
3535
this.headers = options.headers;
3636
this.clientLogLevel = options.clientLogLevel;
3737
this.clientOverlay = options.overlay;
38+
this.disableHostCheck = !!options.disableHostCheck;
39+
this.publicHost = options.public;
3840
this.sockets = [];
3941
this.contentBaseWatchers = [];
4042

@@ -52,6 +54,12 @@ function Server(compiler, options) {
5254
// Init express server
5355
const app = this.app = new express();
5456

57+
app.all("*", (req, res, next) => {
58+
if(this.checkHost(req.headers))
59+
return next();
60+
res.send("Invalid Host header");
61+
});
62+
5563
// middleware for serving webpack bundle
5664
this.middleware = webpackDevMiddleware(compiler, options);
5765

@@ -389,8 +397,37 @@ Server.prototype.setContentHeaders = function(req, res, next) {
389397
next();
390398
}
391399

400+
Server.prototype.checkHost = function(headers) {
401+
// allow user to opt-out this security check, at own risk
402+
if(this.disableHostCheck) return true;
403+
404+
// get the Host header and extract hostname
405+
// we don't care about port not matching
406+
const hostHeader = headers.host;
407+
if(!hostHeader) return false;
408+
const idx = hostHeader.indexOf(":");
409+
const hostname = idx >= 0 ? hostHeader.substr(0, idx) : hostHeader;
410+
411+
// always allow localhost host, for convience
412+
if(hostname === "127.0.0.1" || hostname === "localhost") return true;
413+
414+
// allow hostname of listening adress
415+
if(hostname === this.listenHostname) return true;
416+
417+
// also allow public hostname if provided
418+
if(typeof this.publicHost === "string") {
419+
const idxPublic = this.publicHost.indexOf(":");
420+
const publicHostname = idxPublic >= 0 ? this.publicHost.substr(0, idx) : this.publicHost;
421+
if(hostname === publicHostname) return true;
422+
}
423+
424+
// disallow
425+
return false;
426+
}
427+
392428
// delegate listen call and init sockjs
393-
Server.prototype.listen = function() {
429+
Server.prototype.listen = function(port, hostname) {
430+
this.listenHostname = hostname;
394431
const returnValue = this.listeningApp.listen.apply(this.listeningApp, arguments);
395432
const sockServer = sockjs.createServer({
396433
// Use provided up-to-date sockjs-client
@@ -404,6 +441,11 @@ Server.prototype.listen = function() {
404441
});
405442
sockServer.on("connection", (conn) => {
406443
if(!conn) return;
444+
if(!this.checkHost(conn.headers)) {
445+
this.sockWrite([conn], "error", "Invalid Host header");
446+
conn.close();
447+
return;
448+
}
407449
this.sockets.push(conn);
408450

409451
conn.on("close", () => {

0 commit comments

Comments
 (0)