From 29578537c1ad38f29a445237c57a52c373183e75 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Thu, 6 Apr 2017 18:41:50 +0200 Subject: [PATCH] enable Host header check for all requests and sockets reported by @edmorley --- client/index.js | 3 +++ lib/Server.js | 44 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/client/index.js b/client/index.js index b7218069e6..1da6885b71 100644 --- a/client/index.js +++ b/client/index.js @@ -119,6 +119,9 @@ var onSocketMsg = { console.error(strippedErrors[i]); if(useErrorOverlay) overlay.showMessage(errors); }, + error: function(error) { + console.error(error); + }, close: function() { log("error", "[WDS] Disconnected!"); sendMsg("Close"); diff --git a/lib/Server.js b/lib/Server.js index 7a29938b08..e604b9437c 100644 --- a/lib/Server.js +++ b/lib/Server.js @@ -35,6 +35,8 @@ function Server(compiler, options) { this.headers = options.headers; this.clientLogLevel = options.clientLogLevel; this.clientOverlay = options.overlay; + this.disableHostCheck = !!options.disableHostCheck; + this.publicHost = options.public; this.sockets = []; this.contentBaseWatchers = []; @@ -52,6 +54,12 @@ function Server(compiler, options) { // Init express server const app = this.app = new express(); + app.all("*", (req, res, next) => { + if(this.checkHost(req.headers)) + return next(); + res.send("Invalid Host header"); + }); + // middleware for serving webpack bundle this.middleware = webpackDevMiddleware(compiler, options); @@ -389,8 +397,37 @@ Server.prototype.setContentHeaders = function(req, res, next) { next(); } +Server.prototype.checkHost = function(headers) { + // allow user to opt-out this security check, at own risk + if(this.disableHostCheck) return true; + + // get the Host header and extract hostname + // we don't care about port not matching + const hostHeader = headers.host; + if(!hostHeader) return false; + const idx = hostHeader.indexOf(":"); + const hostname = idx >= 0 ? hostHeader.substr(0, idx) : hostHeader; + + // always allow localhost host, for convience + if(hostname === "127.0.0.1" || hostname === "localhost") return true; + + // allow hostname of listening adress + if(hostname === this.listenHostname) return true; + + // also allow public hostname if provided + if(typeof this.publicHost === "string") { + const idxPublic = this.publicHost.indexOf(":"); + const publicHostname = idxPublic >= 0 ? this.publicHost.substr(0, idx) : this.publicHost; + if(hostname === publicHostname) return true; + } + + // disallow + return false; +} + // delegate listen call and init sockjs -Server.prototype.listen = function() { +Server.prototype.listen = function(port, hostname) { + this.listenHostname = hostname; const returnValue = this.listeningApp.listen.apply(this.listeningApp, arguments); const sockServer = sockjs.createServer({ // Use provided up-to-date sockjs-client @@ -404,6 +441,11 @@ Server.prototype.listen = function() { }); sockServer.on("connection", (conn) => { if(!conn) return; + if(!this.checkHost(conn.headers)) { + this.sockWrite([conn], "error", "Invalid Host header"); + conn.close(); + return; + } this.sockets.push(conn); conn.on("close", () => {