dont allow login with invalid ip, escape ip display on user/info page

v1.18.x
Barış Soner Uşaklı 7 years ago
parent da5997a06e
commit a7a3f3619b

@ -6,6 +6,7 @@ var passport = require('passport');
var nconf = require('nconf'); var nconf = require('nconf');
var validator = require('validator'); var validator = require('validator');
var _ = require('lodash'); var _ = require('lodash');
var ipaddr = require('ipaddr.js');
var db = require('../database'); var db = require('../database');
var meta = require('../meta'); var meta = require('../meta');
@ -289,26 +290,30 @@ authenticationController.doLogin = function (req, uid, callback) {
authenticationController.onSuccessfulLogin = function (req, uid, callback) { authenticationController.onSuccessfulLogin = function (req, uid, callback) {
var uuid = utils.generateUUID(); var uuid = utils.generateUUID();
req.session.meta = {};
delete req.session.forceLogin;
// Associate IP used during login with user account
user.logIP(uid, req.ip);
req.session.meta.ip = req.ip;
// Associate metadata retrieved via user-agent
req.session.meta = _.extend(req.session.meta, {
uuid: uuid,
datetime: Date.now(),
platform: req.useragent.platform,
browser: req.useragent.browser,
version: req.useragent.version,
});
async.waterfall([ async.waterfall([
async.apply(meta.blacklist.test, req.ip),
function (next) { function (next) {
meta.blacklist.test(req.ip, next);
},
function (next) {
user.logIP(uid, req.ip, next);
},
function (next) {
req.session.meta = {};
delete req.session.forceLogin;
// Associate IP used during login with user account
req.session.meta.ip = req.ip;
// Associate metadata retrieved via user-agent
req.session.meta = _.extend(req.session.meta, {
uuid: uuid,
datetime: Date.now(),
platform: req.useragent.platform,
browser: req.useragent.browser,
version: req.useragent.version,
});
async.parallel([ async.parallel([
function (next) { function (next) {
user.auth.addSession(uid, req.sessionID, next); user.auth.addSession(uid, req.sessionID, next);

@ -68,7 +68,12 @@ Blacklist.test = function (clientIp, callback) {
// clientIp = '127.0.15.1:3443'; // IPv4 with port strip port to not fail // clientIp = '127.0.15.1:3443'; // IPv4 with port strip port to not fail
clientIp = clientIp.split(':').length === 2 ? clientIp.split(':')[0] : clientIp; clientIp = clientIp.split(':').length === 2 ? clientIp.split(':')[0] : clientIp;
var addr = ipaddr.parse(clientIp); var addr;
try {
addr = ipaddr.parse(clientIp);
} catch (err) {
return callback(err);
}
if ( if (
Blacklist._rules.ipv4.indexOf(clientIp) === -1 && // not explicitly specified in ipv4 list Blacklist._rules.ipv4.indexOf(clientIp) === -1 && // not explicitly specified in ipv4 list
@ -88,11 +93,7 @@ Blacklist.test = function (clientIp, callback) {
analytics.increment('blacklist'); analytics.increment('blacklist');
} }
if (typeof callback === 'function') { callback(err);
callback(err);
} else {
return !!err;
}
}); });
} else { } else {
var err = new Error('[[error:blacklisted-ip]]'); var err = new Error('[[error:blacklisted-ip]]');
@ -100,11 +101,7 @@ Blacklist.test = function (clientIp, callback) {
analytics.increment('blacklist'); analytics.increment('blacklist');
if (typeof callback === 'function') { setImmediate(callback, err);
setImmediate(callback, err);
} else {
return true;
}
} }
}; };

@ -2,21 +2,41 @@
'use strict'; 'use strict';
var async = require('async'); var async = require('async');
var winston = require('winston');
var validator = require('validator');
var db = require('../database'); var db = require('../database');
var plugins = require('../plugins'); var plugins = require('../plugins');
var winston = require('winston');
module.exports = function (User) { module.exports = function (User) {
User.logIP = function (uid, ip) { User.logIP = function (uid, ip, callback) {
var now = Date.now(); var now = Date.now();
db.sortedSetAdd('uid:' + uid + ':ip', now, ip || 'Unknown'); async.waterfall([
if (ip) { function (next) {
db.sortedSetAdd('ip:' + ip + ':uid', now, uid); db.sortedSetAdd('uid:' + uid + ':ip', now, ip || 'Unknown', next);
} },
function (next) {
if (ip) {
db.sortedSetAdd('ip:' + ip + ':uid', now, uid, next);
} else {
next();
}
},
], callback);
}; };
User.getIPs = function (uid, stop, callback) { User.getIPs = function (uid, stop, callback) {
db.getSortedSetRevRange('uid:' + uid + ':ip', 0, stop, callback); async.waterfall([
function (next) {
db.getSortedSetRevRange('uid:' + uid + ':ip', 0, stop, next);
},
function (ips, next) {
ips = ips.map(function (ip) {
return validator.escape(String(ip));
});
next(null, ips);
},
], callback);
}; };
User.getUsersCSV = function (callback) { User.getUsersCSV = function (callback) {

@ -2,6 +2,7 @@
var async = require('async'); var async = require('async');
var winston = require('winston'); var winston = require('winston');
var validator = require('validator');
var db = require('../database'); var db = require('../database');
var meta = require('../meta'); var meta = require('../meta');
var events = require('../events'); var events = require('../events');
@ -126,12 +127,15 @@ module.exports = function (User) {
next(err, sessions); next(err, sessions);
}); });
}, },
], function (err, sessions) { function (sessions, next) {
callback(err, sessions ? sessions.map(function (sessObj) { sessions = sessions.map(function (sessObj) {
sessObj.meta.datetimeISO = new Date(sessObj.meta.datetime).toISOString(); sessObj.meta.datetimeISO = new Date(sessObj.meta.datetime).toISOString();
return sessObj.meta; sessObj.meta.ip = validator.escape(String(sessObj.meta.ip));
}) : undefined); return sessObj.meta;
}); });
next(null, sessions);
},
], callback);
}; };
User.auth.addSession = function (uid, sessionId, callback) { User.auth.addSession = function (uid, sessionId, callback) {

@ -235,6 +235,36 @@ describe('authentication', function () {
}); });
}); });
it('should fail to login if ip address if invalid', function (done) {
var jar = request.jar();
request({
url: nconf.get('url') + '/api/config',
json: true,
jar: jar,
}, function (err, response, body) {
if (err) {
return done(err);
}
request.post(nconf.get('url') + '/login', {
form: {
username: 'regular',
password: 'regularpwd',
},
json: true,
jar: jar,
headers: {
'x-csrf-token': body.csrf_token,
'x-forwarded-for': '<script>alert("xss")</script>',
},
}, function (err, response, body) {
assert.ifError(err);
assert.equal(response.statusCode, 500);
done();
});
});
});
it('should fail to login if user does not exist', function (done) { it('should fail to login if user does not exist', function (done) {
loginUser('doesnotexist', 'nopassword', function (err, response, body) { loginUser('doesnotexist', 'nopassword', function (err, response, body) {
assert.ifError(err); assert.ifError(err);

@ -49,32 +49,24 @@ describe('blacklist', function () {
}); });
}); });
it('should pass ip test against blacklist async', function (done) { it('should pass ip test against blacklist', function (done) {
blacklist.test('3.3.3.3', function (err) { blacklist.test('3.3.3.3', function (err) {
assert.ifError(err); assert.ifError(err);
done(); done();
}); });
}); });
it('should pass ip test against blacklist sync', function (done) { it('should fail ip test against blacklist', function (done) {
assert(!blacklist.test('3.3.3.3'));
done();
});
it('should fail ip test against blacklist async', function (done) {
blacklist.test('1.1.1.1', function (err) { blacklist.test('1.1.1.1', function (err) {
assert.equal(err.message, '[[error:blacklisted-ip]]'); assert.equal(err.message, '[[error:blacklisted-ip]]');
done(); done();
}); });
}); });
it('should fail ip test against blacklist sync', function (done) {
assert(blacklist.test('1.1.1.1'));
done();
});
it('should pass ip test and not crash with ipv6 address', function (done) { it('should pass ip test and not crash with ipv6 address', function (done) {
assert(!blacklist.test('2001:db8:85a3:0:0:8a2e:370:7334')); blacklist.test('2001:db8:85a3:0:0:8a2e:370:7334', function (err) {
done(); assert.ifError(err);
done();
});
}); });
}); });

Loading…
Cancel
Save