[NEW] Rate limiting for user registering (#23732)

* users.register setting + rate limiting

* refact rate limiting strategy

* remove empty line

* method rate limiting + description + i18n

* update + settings.watch on rest api

* removed duplicated setting

* fixed update setting value on rest api

* refresh registerUser method on setting update + i18n

* removed useless object

* removed empty method

* fixed exception in server launch

* renamed setting

* updated numRequestsAllowed in users.register

* i18n update

* lint

* moved settings.watch to endpoint

* created a new settings.watch for methods + improved rate limiter dictionary method
pull/23769/head
Leonardo Ostjen Couto 4 years ago committed by GitHub
parent 9305434ba1
commit 0cf8e8b7e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 11
      app/api/server/api.js
  2. 13
      app/api/server/v1/users.js
  3. 8
      app/lib/server/startup/settings.ts
  4. 5
      packages/rocketchat-i18n/i18n/en.i18n.json
  5. 7
      packages/rocketchat-i18n/i18n/pt-BR.i18n.json
  6. 18
      server/methods/registerUser.js

@ -4,8 +4,8 @@ import { DDPCommon } from 'meteor/ddp-common';
import { DDP } from 'meteor/ddp';
import { Accounts } from 'meteor/accounts-base';
import { Restivus } from 'meteor/nimble:restivus';
import { RateLimiter } from 'meteor/rate-limit';
import _ from 'underscore';
import { RateLimiter } from 'meteor/rate-limit';
import { Logger } from '../../../server/lib/logger/Logger';
import { getRestPayload } from '../../../server/lib/logger/logPayloads';
@ -447,6 +447,14 @@ export class APIClass extends Restivus {
});
}
updateRateLimiterDictionaryForRoute(route, numRequestsAllowed, intervalTimeInMS) {
if (rateLimiterDictionary[route]) {
rateLimiterDictionary[route].options.numRequestsAllowed = numRequestsAllowed ?? rateLimiterDictionary[route].options.numRequestsAllowed;
rateLimiterDictionary[route].options.intervalTimeInMS = intervalTimeInMS ?? rateLimiterDictionary[route].options.intervalTimeInMS;
API.v1.reloadRoutesToRefreshRateLimiter();
}
}
_initAuth() {
const loginCompatibility = (bodyParams, request) => {
// Grab the username or email that the user is logging in with
@ -771,6 +779,7 @@ settings.watch('API_Enable_Rate_Limiter_Limit_Calls_Default', (value) => {
API.v1.reloadRoutesToRefreshRateLimiter();
});
settings.watch('Prometheus_API_User_Agent', (value) => {
prometheusAPIUserAgent = value;
});

@ -27,6 +27,7 @@ import { setUserStatus } from '../../../../imports/users-presence/server/activeU
import { resetTOTP } from '../../../2fa/server/functions/resetTOTP';
import { Team } from '../../../../server/sdk';
API.v1.addRoute('users.create', { authRequired: true }, {
post() {
check(this.bodyParams, {
@ -283,7 +284,11 @@ API.v1.addRoute('users.list', { authRequired: true }, {
},
});
API.v1.addRoute('users.register', { authRequired: false }, {
API.v1.addRoute('users.register', { authRequired: false,
rateLimiterOptions: {
numRequestsAllowed: settings.get('Rate_Limiter_Limit_RegisterUser'),
intervalTimeInMS: settings.get('API_Enable_Rate_Limiter_Limit_Time_Default'),
} }, {
post() {
if (this.userId) {
return API.v1.failure('Logged in users can not register again.');
@ -944,3 +949,9 @@ API.v1.addRoute('users.logout', { authRequired: true }, {
});
},
});
settings.watch('Rate_Limiter_Limit_RegisterUser', (value) => {
const userRegisterRoute = '/api/v1/users.registerpost';
API.v1.updateRateLimiterDictionaryForRoute(userRegisterRoute, value);
});

@ -2977,7 +2977,7 @@ settingsRegistry.addGroup('Setup_Wizard', function() {
});
settingsRegistry.addGroup('Rate Limiter', function() {
this.section('DDP Rate Limiter', function() {
this.section('DDP_Rate_Limiter', function() {
this.add('DDP_Rate_Limit_IP_Enabled', true, { type: 'boolean' });
this.add('DDP_Rate_Limit_IP_Requests_Allowed', 120000, { type: 'int', enableQuery: { _id: 'DDP_Rate_Limit_IP_Enabled', value: true } });
this.add('DDP_Rate_Limit_IP_Interval_Time', 60000, { type: 'int', enableQuery: { _id: 'DDP_Rate_Limit_IP_Enabled', value: true } });
@ -2999,12 +2999,16 @@ settingsRegistry.addGroup('Rate Limiter', function() {
this.add('DDP_Rate_Limit_Connection_By_Method_Interval_Time', 10000, { type: 'int', enableQuery: { _id: 'DDP_Rate_Limit_Connection_By_Method_Enabled', value: true } });
});
this.section('API Rate Limiter', function() {
this.section('API_Rate_Limiter', function() {
this.add('API_Enable_Rate_Limiter', true, { type: 'boolean' });
this.add('API_Enable_Rate_Limiter_Dev', true, { type: 'boolean', enableQuery: { _id: 'API_Enable_Rate_Limiter', value: true } });
this.add('API_Enable_Rate_Limiter_Limit_Calls_Default', 10, { type: 'int', enableQuery: { _id: 'API_Enable_Rate_Limiter', value: true } });
this.add('API_Enable_Rate_Limiter_Limit_Time_Default', 60000, { type: 'int', enableQuery: { _id: 'API_Enable_Rate_Limiter', value: true } });
});
this.section('Feature_Limiting', function() {
this.add('Rate_Limiter_Limit_RegisterUser', 1, { type: 'int', enableQuery: { _id: 'API_Enable_Rate_Limiter', value: true } });
});
});
settingsRegistry.addGroup('Troubleshoot', function() {

@ -372,6 +372,8 @@
"API_Enable_Rate_Limiter_Dev": "Enable Rate Limiter in development",
"API_Enable_Rate_Limiter_Dev_Description": "Should limit the amount of calls to the endpoints in the development environment?",
"API_Enable_Rate_Limiter_Limit_Calls_Default": "Default number calls to the rate limiter",
"Rate_Limiter_Limit_RegisterUser": "Default number calls to the rate limiter for registering a user",
"Rate_Limiter_Limit_RegisterUser_Description": "Number of default calls for user registering endpoints(REST and real-time API's), allowed within the time range defined in the API Rate Limiter section.",
"API_Enable_Rate_Limiter_Limit_Calls_Default_Description": "Number of default calls for each endpoint of the REST API, allowed within the time range defined below",
"API_Enable_Rate_Limiter_Limit_Time_Default": "Default time limit for the rate limiter (in ms)",
"API_Enable_Rate_Limiter_Limit_Time_Default_Description": "Default timeout to limit the number of calls at each endpoint of the REST API(in ms)",
@ -387,6 +389,7 @@
"API_Personal_Access_Tokens_Regenerate_Modal": "If you lost or forgot your token, you can regenerate it, but remember that all applications that use this token should be updated",
"API_Personal_Access_Tokens_Remove_Modal": "Are you sure you wish to remove this personal access token?",
"API_Personal_Access_Tokens_To_REST_API": "Personal access tokens to REST API",
"API_Rate_Limiter": "API Rate Limiter",
"API_Shield_Types": "Shield Types",
"API_Shield_Types_Description": "Types of shields to enable as a comma separated list, choose from `online`, `channel` or `*` for all",
"API_Shield_user_require_auth": "Require authentication for users shields",
@ -1345,6 +1348,7 @@
"Days": "Days",
"DB_Migration": "Database Migration",
"DB_Migration_Date": "Database Migration Date",
"DDP_Rate_Limit": "DDP Rate Limit",
"DDP_Rate_Limit_Connection_By_Method_Enabled": "Limit by Connection per Method: enabled",
"DDP_Rate_Limit_Connection_By_Method_Interval_Time": "Limit by Connection per Method: interval time",
"DDP_Rate_Limit_Connection_By_Method_Requests_Allowed": "Limit by Connection per Method: requests allowed",
@ -1845,6 +1849,7 @@
"Favorites": "Favorites",
"Feature_depends_on_selected_call_provider_to_be_enabled_from_administration_settings": "This feature depends on the above selected call provider to be enabled from the administration settings.",
"Feature_Depends_on_Livechat_Visitor_navigation_as_a_message_to_be_enabled": "This feature depends on \"Send Visitor Navigation History as a Message\" to be enabled.",
"Feature_Limiting": "Feature Limiting",
"Features": "Features",
"Features_Enabled": "Features Enabled",
"Feature_Disabled": "Feature Disabled",

@ -370,7 +370,9 @@
"API_Enable_Rate_Limiter_Dev": "Ativar limitador de taxa em desenvolvimento",
"API_Enable_Rate_Limiter_Dev_Description": "Deve limitar a quantidade de chamadas para os endpoints no ambiente de desenvolvimento?",
"API_Enable_Rate_Limiter_Limit_Calls_Default": "Número padrão de chamadas para o limitador de taxa",
"API_Enable_Rate_Limiter_Limit_Calls_Default_Description": "Número de chamadas padrão para cada endpoint da API REST, permitido dentro do intervalo de tempo definido abaixo",
"Rate_Limiter_Limit_RegisterUser": "Número de chamadas para as endpoint de registro de usuário",
"Rate_Limiter_Limit_RegisterUser_Description": "Número de chamadas padrão para as endpoints de registro de usuário(API REST e real-time), permitido dentro do intervalo de tempo definido abaixo",
"API_Enable_Rate_Limiter_Limit_Calls_Default_Description": "Número de chamadas padrão para cada endpoint da API REST, permitido dentro do intervalo de tempo definido na seção de limitação de taxa.",
"API_Enable_Rate_Limiter_Limit_Time_Default": "Limite de tempo padrão para o limitador de taxa (em ms)",
"API_Enable_Rate_Limiter_Limit_Time_Default_Description": "Tempo limite padrão para limitar o número de chamadas em cada endpoint da API REST (em ms)",
"API_Enable_Shields": "Ativar Protetores",
@ -385,6 +387,7 @@
"API_Personal_Access_Tokens_Regenerate_Modal": "Se perdeu ou esqueceu o seu código, pode recuperá-lo, mas lembre-se de que todos os aplicativos que usam esse código devem ser atualizados",
"API_Personal_Access_Tokens_Remove_Modal": "Tem certeza de que deseja remover este código de acesso pessoal?",
"API_Personal_Access_Tokens_To_REST_API": "Código de acesso pessoal para API REST",
"API_Rate_Limiter": "Limitação de Taxa de API",
"API_Shield_Types": "Tipos de escudo",
"API_Shield_Types_Description": "Tipos de escudos para habilitar como uma lista separada por vírgulas, escolha entre `online`, `channel` ou `*` para todos",
"API_Shield_user_require_auth": "Exigir autenticaçāo para escudos de usuários",
@ -1340,6 +1343,7 @@
"Days": "Dias",
"DB_Migration": "Migração de Banco de Dados",
"DB_Migration_Date": "Data da migração do banco de dados",
"DDP_Rate_Limit": "Limitação de Taxa de DDP",
"DDP_Rate_Limit_Connection_By_Method_Enabled": "Limite por Conexão por Método: Habilitado",
"DDP_Rate_Limit_Connection_By_Method_Interval_Time": "Limite por Conexão por Método: Intervalo de tempo",
"DDP_Rate_Limit_Connection_By_Method_Requests_Allowed": "Limite por Conexão por Método: Solicitações permitidas",
@ -1838,6 +1842,7 @@
"Favorites": "Favoritos",
"Feature_Depends_on_Livechat_Visitor_navigation_as_a_message_to_be_enabled": "Esse recurso depende de \"Enviar histórico de navegação do visitante como uma mensagem\" para ser ativado.",
"Features": "Funcionalidades",
"Feature_Limiting": "Limitação de funcionalidades",
"Features_Enabled": "Funcionalidades habilitadas",
"Feature_Disabled": "Funcionalidade desabilitada",
"Federation": "Federação",

@ -2,10 +2,11 @@ import { Meteor } from 'meteor/meteor';
import { Match, check } from 'meteor/check';
import { Accounts } from 'meteor/accounts-base';
import s from 'underscore.string';
import { DDPRateLimiter } from 'meteor/ddp-rate-limiter';
import { Users } from '../../app/models';
import { settings } from '../../app/settings';
import { validateEmailDomain, passwordPolicy } from '../../app/lib';
import { validateEmailDomain, passwordPolicy, RateLimiter } from '../../app/lib';
import { validateInviteToken } from '../../app/invites/server/functions/validateInviteToken';
Meteor.methods({
@ -97,3 +98,18 @@ Meteor.methods({
return userId;
},
});
let registerUserRuleId = RateLimiter.limitMethod('registerUser',
settings.get('Rate_Limiter_Limit_RegisterUser'),
settings.get('API_Enable_Rate_Limiter_Limit_Time_Default'), {
userId() { return true; },
});
settings.watch('Rate_Limiter_Limit_RegisterUser', (value) => {
// remove old DDP rate limiter rule and create a new one with the updated setting value
DDPRateLimiter.removeRule(registerUserRuleId);
registerUserRuleId = RateLimiter.limitMethod('registerUser', value, settings.get('API_Enable_Rate_Limiter_Limit_Time_Default'), {
userId() { return true; },
});
});

Loading…
Cancel
Save