From f70b3249a5847929cc7cbe389439eb7101dca107 Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Sat, 5 Jan 2019 14:15:14 -0800 Subject: [PATCH] Fixed user IP filtering when using reverse-proxy + updated Let's Encrypt URLs. --- letsEncrypt.js | 2 +- mpsserver.js | 11 +++++++++-- package.json | 2 +- webserver.js | 52 +++++++++++++++++++++++++++++++------------------- 4 files changed, 43 insertions(+), 24 deletions(-) diff --git a/letsEncrypt.js b/letsEncrypt.js index a7154a58..c486e5d8 100644 --- a/letsEncrypt.js +++ b/letsEncrypt.js @@ -42,7 +42,7 @@ module.exports.CreateLetsEncrypt = function (parent) { // Create the main GreenLock code module. var greenlockargs = { version: 'draft-12', - server: (obj.parent.config.letsencrypt.production === true) ? greenlock.productionServerUrl : greenlock.stagingServerUrl, + server: (obj.parent.config.letsencrypt.production === true) ? 'https://acme-v02.api.letsencrypt.org/directory' : 'https://acme-staging-v02.api.letsencrypt.org/directory', store: leStore, challenges: { 'http-01': leHttpChallenge }, challengeType: 'http-01', diff --git a/mpsserver.js b/mpsserver.js index 92ab5d57..f209040b 100644 --- a/mpsserver.js +++ b/mpsserver.js @@ -21,15 +21,22 @@ module.exports.CreateMpsServer = function (parent, db, args, certificates) { obj.args = args; obj.certificates = certificates; obj.ciraConnections = {}; + var tlsSessionStore = {}; // Store TLS session information for quick resume. + var tlsSessionStoreCount = 0; // Number of cached TLS session information in store. + const constants = require('constants'); const common = require("./common.js"); const net = require("net"); const tls = require("tls"); - const MAX_IDLE = 90000; // 90 seconds max idle time, higher than the typical KEEP-ALIVE periode of 60 seconds + const MAX_IDLE = 90000; // 90 seconds max idle time, higher than the typical KEEP-ALIVE periode of 60 seconds if (obj.args.mpstlsoffload) { obj.server = net.createServer(onConnection); } else { - obj.server = tls.createServer({ key: certificates.mps.key, cert: certificates.mps.cert, requestCert: true, rejectUnauthorized: false }, onConnection); + obj.server = tls.createServer({ key: certificates.mps.key, cert: certificates.mps.cert, requestCert: true, rejectUnauthorized: false, ciphers: "HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!SRP:!CAMELLIA", secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION }, onConnection); + //obj.server.on('secureConnection', function () { /*console.log('tlsServer secureConnection');*/ }); + //obj.server.on('error', function () { console.log('MPS tls server error'); }); + obj.server.on('newSession', function (id, data, cb) { if (tlsSessionStoreCount > 1000) { tlsSessionStoreCount = 0; tlsSessionStore = {}; } tlsSessionStore[id.toString('hex')] = data; tlsSessionStoreCount++; cb(); }); + obj.server.on('resumeSession', function (id, cb) { cb(null, tlsSessionStore[id.toString('hex')] || null); }); } obj.server.listen(args.mpsport, function () { console.log("MeshCentral Intel(R) AMT server running on " + certificates.AmtMpsName + ":" + args.mpsport + ((args.mpsaliasport != null) ? (", alias port " + args.mpsaliasport) : "") + "."); }).on("error", function (err) { console.error("ERROR: MeshCentral Intel(R) AMT server port " + args.mpsport + " is not available."); if (args.exactports) { process.exit(); } }); diff --git a/package.json b/package.json index ac379f71..44b516f4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "meshcentral", - "version": "0.2.5-s", + "version": "0.2.5-t", "keywords": [ "Remote Management", "Intel AMT", diff --git a/webserver.js b/webserver.js index 58d3ce7e..2cc0ff7a 100644 --- a/webserver.js +++ b/webserver.js @@ -49,7 +49,6 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { obj.net = require('net'); obj.tls = require('tls'); obj.path = require('path'); - obj.constants = require('constants'); obj.bodyParser = require('body-parser'); obj.session = require('cookie-session'); obj.exphbs = require('express-handlebars'); @@ -60,6 +59,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { obj.meshRelayHandler = require('./meshrelay.js'); obj.meshUserHandler = require('./meshuser.js'); obj.interceptor = require('./interceptor'); + const constants = require('constants'); // Variables obj.parent = parent; @@ -140,14 +140,16 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { // Main lists obj.wsagents = {}; - obj.wssessions = {}; // UserId --> Array Of Sessions - obj.wssessions2 = {}; // "UserId + SessionRnd" --> Session (Note that the SessionId is the UserId + / + SessionRnd) - obj.wsPeerSessions = {}; // ServerId --> Array Of "UserId + SessionRnd" - obj.wsPeerSessions2 = {}; // "UserId + SessionRnd" --> ServerId - obj.wsPeerSessions3 = {}; // ServerId --> UserId --> [ SessionId ] - obj.sessionsCount = {}; // Merged session counters, used when doing server peering. UserId --> SessionCount - obj.wsrelays = {}; // Id -> Relay - obj.wsPeerRelays = {}; // Id -> { ServerId, Time } + obj.wssessions = {}; // UserId --> Array Of Sessions + obj.wssessions2 = {}; // "UserId + SessionRnd" --> Session (Note that the SessionId is the UserId + / + SessionRnd) + obj.wsPeerSessions = {}; // ServerId --> Array Of "UserId + SessionRnd" + obj.wsPeerSessions2 = {}; // "UserId + SessionRnd" --> ServerId + obj.wsPeerSessions3 = {}; // ServerId --> UserId --> [ SessionId ] + obj.sessionsCount = {}; // Merged session counters, used when doing server peering. UserId --> SessionCount + obj.wsrelays = {}; // Id -> Relay + obj.wsPeerRelays = {}; // Id -> { ServerId, Time } + var tlsSessionStore = {}; // Store TLS session information for quick resume. + var tlsSessionStoreCount = 0; // Number of cached TLS session information in store. // Setup randoms obj.crypto.randomBytes(48, function (err, buf) { obj.httpAuthRandom = buf; }); @@ -177,12 +179,14 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { // Setup the HTTP server without TLS obj.expressWs = require('express-ws')(obj.app); } else { - // Setup the HTTP server with TLS, use only TLS 1.2 and higher. - var tlsOptions = { cert: obj.certificates.web.cert, key: obj.certificates.web.key, ca: obj.certificates.web.ca, rejectUnauthorized: true, secureOptions: obj.constants.SSL_OP_NO_SSLv2 | obj.constants.SSL_OP_NO_SSLv3 | obj.constants.SSL_OP_NO_COMPRESSION | obj.constants.SSL_OP_CIPHER_SERVER_PREFERENCE | obj.constants.SSL_OP_NO_TLSv1 | obj.constants.SSL_OP_NO_TLSv11 }; + // Setup the HTTP server with TLS, use only TLS 1.2 and higher with perfect forward secrecy (PFS). + const tlsOptions = { cert: obj.certificates.web.cert, key: obj.certificates.web.key, ca: obj.certificates.web.ca, rejectUnauthorized: true, ciphers: "HIGH:!aNULL:!eNULL:!EXPORT:!RSA:!DES:!RC4:!MD5:!PSK:!SRP:!CAMELLIA", secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION | constants.SSL_OP_CIPHER_SERVER_PREFERENCE | constants.SSL_OP_NO_TLSv1 | constants.SSL_OP_NO_TLSv1_1 }; if (obj.tlsSniCredentials != null) { tlsOptions.SNICallback = TlsSniCallback; } // We have multiple web server certificate used depending on the domain name obj.tlsServer = require('https').createServer(tlsOptions, obj.app); obj.tlsServer.on('secureConnection', function () { /*console.log('tlsServer secureConnection');*/ }); obj.tlsServer.on('error', function () { console.log('tlsServer error'); }); + obj.tlsServer.on('newSession', function (id, data, cb) { if (tlsSessionStoreCount > 1000) { tlsSessionStoreCount = 0; tlsSessionStore = {}; } tlsSessionStore[id.toString('hex')] = data; tlsSessionStoreCount++; cb(); }); + obj.tlsServer.on('resumeSession', function (id, cb) { cb(null, tlsSessionStore[id.toString('hex')] || null); }); obj.expressWs = require('express-ws')(obj.app, obj.tlsServer); } @@ -288,13 +292,21 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { function checkUserIpAddressEx(req, res, allowedIpList) { if (allowedIpList == null) { return true; } try { - var ip, type = 0; - if (req.connection) { type = 1; ip = req.ip; } // HTTP(S) request - else if (req._socket) { type = 2; ip = req._socket.remoteAddress; } // WebSocket request - if (!ip) return false; - for (var i = 0; i < allowedIpList.length; i++) { if (require('ipcheck').match(ip, allowedIpList[i])) { return true; } } - if (type == 1) { res.sendStatus(401); } - else if (type == 2) { try { req.close(); } catch (e) { } } + var ip; + if (req.connection) { // HTTP(S) request + ip = req.ip; + if (ip) { for (var i = 0; i < allowedIpList.length; i++) { if (require('ipcheck').match(ip, allowedIpList[i])) { return true; } } } + res.sendStatus(401); + } else if (req._socket) { // WebSocket request + ip = req._socket.remoteAddress; + + // If a trusted reverse-proxy is sending us the remote IP address, use it. + // This is not done automatically for web socket like it's done for HTTP requests. + if ((obj.args.tlsoffload) && (res.headers['x-forwarded-for']) && ((obj.args.tlsoffload === true) || (obj.args.tlsoffload === ip) || (('::ffff:') + obj.args.tlsoffload === ip))) { ip = res.headers['x-forwarded-for']; } + + if (ip) { for (var i = 0; i < allowedIpList.length; i++) { if (require('ipcheck').match(ip, allowedIpList[i])) { return true; } } } + try { req.close(); } catch (e) { } + } } catch (e) { console.log(e); } return false; } @@ -1219,7 +1231,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { // TLSSocket to encapsulate TLS communication, which then tunneled via SerialTunnel an then wrapped through CIRA APF const TLSSocket = require('tls').TLSSocket; - const tlsoptions = { secureProtocol: ((req.query.tls1only == 1) ? 'TLSv1_method' : 'SSLv23_method'), ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: obj.constants.SSL_OP_NO_SSLv2 | obj.constants.SSL_OP_NO_SSLv3 | obj.constants.SSL_OP_NO_COMPRESSION | obj.constants.SSL_OP_CIPHER_SERVER_PREFERENCE, rejectUnauthorized: false }; + const tlsoptions = { secureProtocol: ((req.query.tls1only == 1) ? 'TLSv1_method' : 'SSLv23_method'), ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION | constants.SSL_OP_CIPHER_SERVER_PREFERENCE, rejectUnauthorized: false }; const tlsock = new TLSSocket(ser, tlsoptions); tlsock.on('error', function (err) { Debug(1, "CIRA TLS Connection Error ", err); }); tlsock.on('secureConnect', function () { Debug(2, "CIRA Secure TLS Connection"); ws._socket.resume(); }); @@ -1340,7 +1352,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) { ws._socket.resume(); } else { // If TLS is going to be used, setup a TLS socket - var tlsoptions = { secureProtocol: ((req.query.tls1only == 1) ? 'TLSv1_method' : 'SSLv23_method'), ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: obj.constants.SSL_OP_NO_SSLv2 | obj.constants.SSL_OP_NO_SSLv3 | obj.constants.SSL_OP_NO_COMPRESSION | obj.constants.SSL_OP_CIPHER_SERVER_PREFERENCE, rejectUnauthorized: false }; + var tlsoptions = { secureProtocol: ((req.query.tls1only == 1) ? 'TLSv1_method' : 'SSLv23_method'), ciphers: 'RSA+AES:!aNULL:!MD5:!DSS', secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3 | constants.SSL_OP_NO_COMPRESSION | constants.SSL_OP_CIPHER_SERVER_PREFERENCE, rejectUnauthorized: false }; ws.forwardclient = obj.tls.connect(port, node.host, tlsoptions, function () { // The TLS connection method is the same as TCP, but located a bit differently. Debug(2, 'TLS connected to ' + node.host + ':' + port + '.');