feat: Add request rate limiter based on IP address (#8174)

This commit is contained in:
Daniel
2023-01-06 23:39:02 +11:00
committed by GitHub
parent 0eac5dc6d4
commit 6c79f6a69e
13 changed files with 713 additions and 50 deletions

View File

@@ -411,6 +411,13 @@ module.exports.ParseServerOptions = {
'Configuration for push, as stringified JSON. See http://docs.parseplatform.org/parse-server/guide/#push-notifications',
action: parsers.objectParser,
},
rateLimit: {
env: 'PARSE_SERVER_RATE_LIMIT',
help:
"Options to limit repeated requests to Parse Server APIs. This can be used to protect sensitive endpoints such as `/requestPasswordReset` from brute-force attacks or Parse Server as a whole from denial-of-service (DoS) attacks.<br><br>\u2139\uFE0F Mind the following limitations:<br>- rate limits applied per IP address; this limits protection against distributed denial-of-service (DDoS) attacks where many requests are coming from various IP addresses<br>- if multiple Parse Server instances are behind a load balancer or ran in a cluster, each instance will calculate it's own request rates, independent from other instances; this limits the applicability of this feature when using a load balancer and another rate limiting solution that takes requests across all instances into account may be more suitable<br>- this feature provides basic protection against denial-of-service attacks, but a more sophisticated solution works earlier in the request flow and prevents a malicious requests to even reach a server instance; it's therefore recommended to implement a solution according to architecture and user case.",
action: parsers.arrayParser,
default: [],
},
readOnlyMasterKey: {
env: 'PARSE_SERVER_READ_ONLY_MASTER_KEY',
help: 'Read-only key, which has the same capabilities as MasterKey without writes',
@@ -516,6 +523,52 @@ module.exports.ParseServerOptions = {
help: 'Key sent with outgoing webhook calls',
},
};
module.exports.RateLimitOptions = {
errorResponseMessage: {
env: 'PARSE_SERVER_RATE_LIMIT_ERROR_RESPONSE_MESSAGE',
help:
'The error message that should be returned in the body of the HTTP 429 response when the rate limit is hit. Default is `Too many requests.`.',
default: 'Too many requests.',
},
includeInternalRequests: {
env: 'PARSE_SERVER_RATE_LIMIT_INCLUDE_INTERNAL_REQUESTS',
help:
'Optional, if `true` the rate limit will also apply to requests that are made in by Cloud Code, default is `false`. Note that a public Cloud Code function that triggers internal requests may circumvent rate limiting and be vulnerable to attacks.',
action: parsers.booleanParser,
default: false,
},
includeMasterKey: {
env: 'PARSE_SERVER_RATE_LIMIT_INCLUDE_MASTER_KEY',
help:
'Optional, if `true` the rate limit will also apply to requests using the `masterKey`, default is `false`. Note that a public Cloud Code function that triggers internal requests using the `masterKey` may circumvent rate limiting and be vulnerable to attacks.',
action: parsers.booleanParser,
default: false,
},
requestCount: {
env: 'PARSE_SERVER_RATE_LIMIT_REQUEST_COUNT',
help:
'The number of requests that can be made per IP address within the time window set in `requestTimeWindow` before the rate limit is applied.',
action: parsers.numberParser('requestCount'),
},
requestMethods: {
env: 'PARSE_SERVER_RATE_LIMIT_REQUEST_METHODS',
help:
'Optional, the HTTP request methods to which the rate limit should be applied, default is all methods.',
action: parsers.arrayParser,
},
requestPath: {
env: 'PARSE_SERVER_RATE_LIMIT_REQUEST_PATH',
help:
'The path of the API route to be rate limited. Route paths, in combination with a request method, define the endpoints at which requests can be made. Route paths can be strings, string patterns, or regular expression. See: https://expressjs.com/en/guide/routing.html',
required: true,
},
requestTimeWindow: {
env: 'PARSE_SERVER_RATE_LIMIT_REQUEST_TIME_WINDOW',
help:
'The window of time in milliseconds within which the number of requests set in `requestCount` can be made before the rate limit is applied.',
action: parsers.numberParser('requestTimeWindow'),
},
};
module.exports.SecurityOptions = {
checkGroups: {
env: 'PARSE_SERVER_SECURITY_CHECK_GROUPS',

View File

@@ -77,6 +77,7 @@
* @property {ProtectedFields} protectedFields Protected fields that should be treated with extra security when fetching details.
* @property {String} publicServerURL Public URL to your parse server with http:// or https://.
* @property {Any} push Configuration for push, as stringified JSON. See http://docs.parseplatform.org/parse-server/guide/#push-notifications
* @property {RateLimitOptions[]} rateLimit Options to limit repeated requests to Parse Server APIs. This can be used to protect sensitive endpoints such as `/requestPasswordReset` from brute-force attacks or Parse Server as a whole from denial-of-service (DoS) attacks.<br><br> Mind the following limitations:<br>- rate limits applied per IP address; this limits protection against distributed denial-of-service (DDoS) attacks where many requests are coming from various IP addresses<br>- if multiple Parse Server instances are behind a load balancer or ran in a cluster, each instance will calculate it's own request rates, independent from other instances; this limits the applicability of this feature when using a load balancer and another rate limiting solution that takes requests across all instances into account may be more suitable<br>- this feature provides basic protection against denial-of-service attacks, but a more sophisticated solution works earlier in the request flow and prevents a malicious requests to even reach a server instance; it's therefore recommended to implement a solution according to architecture and user case.
* @property {String} readOnlyMasterKey Read-only key, which has the same capabilities as MasterKey without writes
* @property {RequestKeywordDenylist[]} requestKeywordDenylist An array of keys and values that are prohibited in database read and write requests to prevent potential security vulnerabilities. It is possible to specify only a key (`{"key":"..."}`), only a value (`{"value":"..."}`) or a key-value pair (`{"key":"...","value":"..."}`). The specification can use the following types: `boolean`, `numeric` or `string`, where `string` will be interpreted as a regex notation. Request data is deep-scanned for matching definitions to detect also any nested occurrences. Defaults are patterns that are likely to be used in malicious requests. Setting this option will override the default patterns.
* @property {String} restAPIKey Key for REST calls
@@ -96,6 +97,17 @@
* @property {String} webhookKey Key sent with outgoing webhook calls
*/
/**
* @interface RateLimitOptions
* @property {String} errorResponseMessage The error message that should be returned in the body of the HTTP 429 response when the rate limit is hit. Default is `Too many requests.`.
* @property {Boolean} includeInternalRequests Optional, if `true` the rate limit will also apply to requests that are made in by Cloud Code, default is `false`. Note that a public Cloud Code function that triggers internal requests may circumvent rate limiting and be vulnerable to attacks.
* @property {Boolean} includeMasterKey Optional, if `true` the rate limit will also apply to requests using the `masterKey`, default is `false`. Note that a public Cloud Code function that triggers internal requests using the `masterKey` may circumvent rate limiting and be vulnerable to attacks.
* @property {Number} requestCount The number of requests that can be made per IP address within the time window set in `requestTimeWindow` before the rate limit is applied.
* @property {String[]} requestMethods Optional, the HTTP request methods to which the rate limit should be applied, default is all methods.
* @property {String} requestPath The path of the API route to be rate limited. Route paths, in combination with a request method, define the endpoints at which requests can be made. Route paths can be strings, string patterns, or regular expression. See: https://expressjs.com/en/guide/routing.html
* @property {Number} requestTimeWindow The window of time in milliseconds within which the number of requests set in `requestCount` can be made before the rate limit is applied.
*/
/**
* @interface SecurityOptions
* @property {CheckGroup[]} checkGroups The security check groups to run. This allows to add custom security checks or override existing ones. Default are the groups defined in `CheckGroups.js`.

View File

@@ -292,6 +292,29 @@ export interface ParseServerOptions {
/* An array of keys and values that are prohibited in database read and write requests to prevent potential security vulnerabilities. It is possible to specify only a key (`{"key":"..."}`), only a value (`{"value":"..."}`) or a key-value pair (`{"key":"...","value":"..."}`). The specification can use the following types: `boolean`, `numeric` or `string`, where `string` will be interpreted as a regex notation. Request data is deep-scanned for matching definitions to detect also any nested occurrences. Defaults are patterns that are likely to be used in malicious requests. Setting this option will override the default patterns.
:DEFAULT: [{"key":"_bsontype","value":"Code"},{"key":"constructor"},{"key":"__proto__"}] */
requestKeywordDenylist: ?(RequestKeywordDenylist[]);
/* Options to limit repeated requests to Parse Server APIs. This can be used to protect sensitive endpoints such as `/requestPasswordReset` from brute-force attacks or Parse Server as a whole from denial-of-service (DoS) attacks.<br><br> Mind the following limitations:<br>- rate limits applied per IP address; this limits protection against distributed denial-of-service (DDoS) attacks where many requests are coming from various IP addresses<br>- if multiple Parse Server instances are behind a load balancer or ran in a cluster, each instance will calculate it's own request rates, independent from other instances; this limits the applicability of this feature when using a load balancer and another rate limiting solution that takes requests across all instances into account may be more suitable<br>- this feature provides basic protection against denial-of-service attacks, but a more sophisticated solution works earlier in the request flow and prevents a malicious requests to even reach a server instance; it's therefore recommended to implement a solution according to architecture and user case.
:DEFAULT: [] */
rateLimit: ?(RateLimitOptions[]);
}
export interface RateLimitOptions {
/* The path of the API route to be rate limited. Route paths, in combination with a request method, define the endpoints at which requests can be made. Route paths can be strings, string patterns, or regular expression. See: https://expressjs.com/en/guide/routing.html */
requestPath: string;
/* The window of time in milliseconds within which the number of requests set in `requestCount` can be made before the rate limit is applied. */
requestTimeWindow: ?number;
/* The number of requests that can be made per IP address within the time window set in `requestTimeWindow` before the rate limit is applied. */
requestCount: ?number;
/* The error message that should be returned in the body of the HTTP 429 response when the rate limit is hit. Default is `Too many requests.`.
:DEFAULT: Too many requests. */
errorResponseMessage: ?string;
/* Optional, the HTTP request methods to which the rate limit should be applied, default is all methods. */
requestMethods: ?(string[]);
/* Optional, if `true` the rate limit will also apply to requests using the `masterKey`, default is `false`. Note that a public Cloud Code function that triggers internal requests using the `masterKey` may circumvent rate limiting and be vulnerable to attacks.
:DEFAULT: false */
includeMasterKey: ?boolean;
/* Optional, if `true` the rate limit will also apply to requests that are made in by Cloud Code, default is `false`. Note that a public Cloud Code function that triggers internal requests may circumvent rate limiting and be vulnerable to attacks.
:DEFAULT: false */
includeInternalRequests: ?boolean;
}
export interface SecurityOptions {