perf: Improved IP validation performance for masterKeyIPs, maintenanceKeyIPs (#8510)
This commit is contained in:
@@ -75,6 +75,8 @@ class ParseServer {
|
||||
const allControllers = controllers.getControllers(options);
|
||||
options.state = 'initialized';
|
||||
this.config = Config.put(Object.assign({}, options, allControllers));
|
||||
this.config.masterKeyIpsStore = new Map();
|
||||
this.config.maintenanceKeyIpsStore = new Map();
|
||||
logging.setLogger(allControllers.loggerController);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,9 +10,9 @@ import PostgresStorageAdapter from './Adapters/Storage/Postgres/PostgresStorageA
|
||||
import rateLimit from 'express-rate-limit';
|
||||
import { RateLimitOptions } from './Options/Definitions';
|
||||
import { pathToRegexp } from 'path-to-regexp';
|
||||
import ipRangeCheck from 'ip-range-check';
|
||||
import RedisStore from 'rate-limit-redis';
|
||||
import { createClient } from 'redis';
|
||||
import { BlockList, isIPv4 } from 'net';
|
||||
|
||||
export const DEFAULT_ALLOWED_HEADERS =
|
||||
'X-Parse-Master-Key, X-Parse-REST-API-Key, X-Parse-Javascript-Key, X-Parse-Application-Id, X-Parse-Client-Version, X-Parse-Session-Token, X-Requested-With, X-Parse-Revocable-Session, X-Parse-Request-Id, Content-Type, Pragma, Cache-Control';
|
||||
@@ -23,6 +23,46 @@ const getMountForRequest = function (req) {
|
||||
return req.protocol + '://' + req.get('host') + mountPath;
|
||||
};
|
||||
|
||||
const getBlockList = (ipRangeList, store) => {
|
||||
if (store.get('blockList')) return store.get('blockList');
|
||||
const blockList = new BlockList();
|
||||
ipRangeList.forEach(fullIp => {
|
||||
if (fullIp === '::/0' || fullIp === '::') {
|
||||
store.set('allowAllIpv6', true);
|
||||
return;
|
||||
}
|
||||
if (fullIp === '0.0.0.0/0' || fullIp === '0.0.0.0') {
|
||||
store.set('allowAllIpv4', true);
|
||||
return;
|
||||
}
|
||||
const [ip, mask] = fullIp.split('/');
|
||||
if (!mask) {
|
||||
blockList.addAddress(ip, isIPv4(ip) ? 'ipv4' : 'ipv6');
|
||||
} else {
|
||||
blockList.addSubnet(ip, Number(mask), isIPv4(ip) ? 'ipv4' : 'ipv6');
|
||||
}
|
||||
});
|
||||
store.set('blockList', blockList);
|
||||
return blockList;
|
||||
};
|
||||
|
||||
export const checkIp = (ip, ipRangeList, store) => {
|
||||
const incomingIpIsV4 = isIPv4(ip);
|
||||
const blockList = getBlockList(ipRangeList, store);
|
||||
|
||||
if (store.get(ip)) return true;
|
||||
if (store.get('allowAllIpv4') && incomingIpIsV4) return true;
|
||||
if (store.get('allowAllIpv6') && !incomingIpIsV4) return true;
|
||||
const result = blockList.check(ip, incomingIpIsV4 ? 'ipv4' : 'ipv6');
|
||||
|
||||
// If the ip is in the list, we store the result in the store
|
||||
// so we have a optimized path for the next request
|
||||
if (ipRangeList.includes(ip) && result) {
|
||||
store.set(ip, result);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
// Checks that the request is authorized for this app and checks user
|
||||
// auth too.
|
||||
// The bodyparser should run before this middleware.
|
||||
@@ -183,7 +223,7 @@ export function handleParseHeaders(req, res, next) {
|
||||
const isMaintenance =
|
||||
req.config.maintenanceKey && info.maintenanceKey === req.config.maintenanceKey;
|
||||
if (isMaintenance) {
|
||||
if (ipRangeCheck(clientIp, req.config.maintenanceKeyIps || [])) {
|
||||
if (checkIp(clientIp, req.config.maintenanceKeyIps || [], req.config.maintenanceKeyIpsStore)) {
|
||||
req.auth = new auth.Auth({
|
||||
config: req.config,
|
||||
installationId: info.installationId,
|
||||
@@ -199,7 +239,8 @@ export function handleParseHeaders(req, res, next) {
|
||||
}
|
||||
|
||||
let isMaster = info.masterKey === req.config.masterKey;
|
||||
if (isMaster && !ipRangeCheck(clientIp, req.config.masterKeyIps || [])) {
|
||||
|
||||
if (isMaster && !checkIp(clientIp, req.config.masterKeyIps || [], req.config.masterKeyIpsStore)) {
|
||||
const log = req.config?.loggerController || defaultLogger;
|
||||
log.error(
|
||||
`Request using master key rejected as the request IP address '${clientIp}' is not set in Parse Server option 'masterKeyIps'.`
|
||||
|
||||
Reference in New Issue
Block a user