Added bad login IP blocking cooloff support.
Ylian Saint-Hilaire committed
Nov 19, 2019 at 13:33 UTC
07d4099892266026b6991f2b8a6902978e20448a
5 files changed
+29
-9
meshcentral.js
+1
-2
@@ -2039,8 +2039,7 @@ function mainStart() {
2039
var modules = ['ws', 'cbor', 'nedb', 'https', 'yauzl', 'xmldom', 'ipcheck', 'express', 'archiver', 'multiparty', 'node-forge', 'express-ws', 'compression', 'body-parser', 'connect-redis', 'cookie-session', 'express-handlebars'];
2040
if (require('os').platform() == 'win32') { modules.push('node-windows'); if (sspi == true) { modules.push('node-sspi'); } } // Add Windows modules
2041
if (ldap == true) { modules.push('ldapauth-fork'); }
2042
- //if (config.letsencrypt != null) { modules.push('greenlock@2.8.8'); modules.push('le-store-certbot'); modules.push('le-challenge-fs'); modules.push('le-acme-core'); } // Add Greenlock Modules
2043
- if (config.letsencrypt != null) { if ((nodeVersion < 10) || (require('crypto').generateKeyPair == null)) { console.log("WARNING: Let's Encrypt support requires Node v10.12.0 or higher."); } else { modules.push('greenlock'); } } // Add Greenlock Module
2042
+ if (config.letsencrypt != null) { if ((nodeVersion < 10) || (require('crypto').generateKeyPair == null)) { if (!args.launch) { console.log("WARNING: Let's Encrypt support requires Node v10.12.0 or higher."); } } else { modules.push('greenlock'); } } // Add Greenlock Module
2043
if (config.settings.mqtt != null) { modules.push('aedes'); } // Add MQTT Modules
2044
if (config.settings.mongodb != null) { modules.push('mongodb'); } // Add MongoDB, official driver.
2045
if (config.settings.vault != null) { modules.push('node-vault'); } // Add official HashiCorp's Vault module.
meshuser.js
+13
-2
@@ -693,10 +693,21 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
693
break;
694
}
695
case 'badlogins': {
696
- r = "Max is " + parent.parent.config.settings.maxinvalidlogin.count + " bad login(s) in " + parent.parent.config.settings.maxinvalidlogin.time + " minute(s).\r\n";
696
+ if (typeof parent.parent.config.settings.maxinvalidlogin.coolofftime == 'number') {
697
+ r = "Max is " + parent.parent.config.settings.maxinvalidlogin.count + " bad login(s) in " + parent.parent.config.settings.maxinvalidlogin.time + " minute(s), " + parent.parent.config.settings.maxinvalidlogin.coolofftime + " minute(s) cooloff.\r\n";
698
+ } else {
699
+ r = "Max is " + parent.parent.config.settings.maxinvalidlogin.count + " bad login(s) in " + parent.parent.config.settings.maxinvalidlogin.time + " minute(s).\r\n";
700
+ }
701
var badLoginCount = 0;
702
parent.cleanBadLoginTable();
699
- for (var i in parent.badLoginTable) { badLoginCount++; r += (i + ' - ' + parent.badLoginTable[i].length + " entries\r\n"); }
703
+ for (var i in parent.badLoginTable) {
704
+ badLoginCount++;
705
+ if (typeof parent.badLoginTable[i] == 'number') {
706
+ r += "Cooloff for " + Math.floor((parent.badLoginTable[i] - Date.now()) / 60000) + " minute(s)\r\n";
707
+ } else {
708
+ r += (i + ' - ' + parent.badLoginTable[i].length + " entries\r\n");
709
+ }
710
+ }
711
if (badLoginCount == 0) { r += 'No bad logins.'; }
712
break;
713
}
package.json
+1
-1
@@ -1,6 +1,6 @@
1
{
2
"name": "meshcentral",
3
- "version": "0.4.4-m",
3
+ "version": "0.4.4-o",
4
"keywords": [
5
"Remote Management",
6
"Intel AMT",
sample-config.json
+1
-1
@@ -60,7 +60,7 @@
60
"meshcommander": "https://www.meshcommander.com/"
61
},
62
"__MaxInvalidLogin": "Time in minutes, max amount of bad logins from a source IP in the time before logins are rejected.",
63
- "MaxInvalidLogin": { "time": 10, "count": 10 }
63
+ "MaxInvalidLogin": { "time": 10, "count": 10, "coolofftime": 10 }
64
},
65
"_domains": {
66
"": {
webserver.js
+13
-3
@@ -4038,26 +4038,36 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4038
if (parent.config.settings.maxinvalidlogin == null) { parent.config.settings.maxinvalidlogin = { time: 10, count: 10 }; }
4039
if (typeof parent.config.settings.maxinvalidlogin.time != 'number') { parent.config.settings.maxinvalidlogin.time = 10; }
4040
if (typeof parent.config.settings.maxinvalidlogin.count != 'number') { parent.config.settings.maxinvalidlogin.count = 10; }
4041
+ if ((typeof parent.config.settings.maxinvalidlogin.coolofftime != 'number') || (parent.config.settings.maxinvalidlogin.coolofftime < 1)) { parent.config.settings.maxinvalidlogin.coolofftime = null; }
4042
obj.setbadLogin = function (ip) { // Set an IP address that just did a bad login request
4043
if (typeof ip == 'object') { ip = cleanRemoteAddr(ip.ip); }
4044
if (++obj.badLoginTableLastClean > 100) { obj.cleanBadLoginTable(); }
4045
+ if (typeof obj.badLoginTable[ip] == 'number') { if (obj.badLoginTable[ip] < Date.now()) { delete obj.badLoginTable[ip]; } else { return; } } // Check cooloff period
4046
if (obj.badLoginTable[ip] == null) { obj.badLoginTable[ip] = [Date.now()]; } else { obj.badLoginTable[ip].push(Date.now()); }
4047
+ if ((obj.badLoginTable[ip].length >= parent.config.settings.maxinvalidlogin.count) && (parent.config.settings.maxinvalidlogin.coolofftime != null)) {
4048
+ obj.badLoginTable[ip] = Date.now() + (parent.config.settings.maxinvalidlogin.coolofftime * 60000); // Move to cooloff period
4049
+ }
4050
}
4051
obj.checkAllowLogin = function (ip) { // Check if an IP address is allowed to login
4052
if (typeof ip == 'object') { ip = cleanRemoteAddr(ip.ip); }
4053
var cutoffTime = Date.now() - (parent.config.settings.maxinvalidlogin.time * 60000); // Time in minutes
4054
var ipTable = obj.badLoginTable[ip];
4055
if (ipTable == null) return true;
4056
+ if (typeof ipTable == 'number') { if (obj.badLoginTable[ip] < Date.now()) { delete obj.badLoginTable[ip]; } else { return false; } } // Check cooloff period
4057
while ((ipTable.length > 0) && (ipTable[0] < cutoffTime)) { ipTable.shift(); }
4058
if (ipTable.length == 0) { delete obj.badLoginTable[ip]; return true; }
4059
return (ipTable.length < parent.config.settings.maxinvalidlogin.count); // No more than x bad logins in x minutes
4060
}
4061
obj.cleanBadLoginTable = function () { // Clean up the IP address login blockage table, we do this occasionaly.
4062
var cutoffTime = Date.now() - (parent.config.settings.maxinvalidlogin.time * 60000); // Time in minutes
4057
- for (var i in ipTable) {
4063
+ for (var ip in obj.badLoginTable) {
4064
var ipTable = obj.badLoginTable[ip];
4059
- while ((ipTable.length > 0) && (ipTable[0] < cutoffTime)) { ipTable.shift(); }
4060
- if (ipTable.length == 0) { delete obj.badLoginTable[ip]; }
4065
+ if (typeof ipTable == 'number') {
4066
+ if (obj.badLoginTable[ip] < Date.now()) { delete obj.badLoginTable[ip]; } // Check cooloff period
4067
+ } else {
4068
+ while ((ipTable.length > 0) && (ipTable[0] < cutoffTime)) { ipTable.shift(); }
4069
+ if (ipTable.length == 0) { delete obj.badLoginTable[ip]; }
4070
+ }
4071
}
4072
obj.badLoginTableLastClean = 0;
4073
}