Node.js http как установить ограничение скорости http-запросов?

Я хочу создать промежуточное ПО для ограничения скорости для моей экспресс-обработки HTTP, примерно так:

app.post("/v1/authentication/login", rateLimiter(5, 20), require('./api/v1-login'));

Промежуточное ПО разрешит только 5 запросов в течение 20 секунд.

Я могу использовать для этого плагин, но я также работаю с кластерами / процессами, и я читал, что плагин не поддерживает процессы.

Я знаю, что могу обмениваться данными между процессами с помощью БД - MongoDB или Redis.

Кроме того, я хотел бы установить собственный предел скорости - это означает, что для функции A я хочу, чтобы пользователю John было разрешено запрашивать 5 раз каждые 20 секунд, например, однако для той же функции я хочу, чтобы Дэни было разрешено отправлять 10 запросов за 20 секунд.

Мне также нужно, чтобы это применялось во всех процессах, как я упоминал ранее.

Подумал написать свой скрипт сохранения данных запрашивающего пользователя, но не знаю, что именно сохранять - его IP? его хромированный серийный номер или что там такое ..?

Должен ли я хранить это в Redis DB или Mongo? Может быть, есть встроенный в память Node.js, который лучше хранить там данные?

Что вы порекомендуете?

Чтобы поддерживать несколько процессов на одном компьютере, вы, вероятно, захотите использовать базу данных в памяти, такую ​​как Redis, для отслеживания запросов. Как именно реализовать ограничение скорости - это очень длинная тема (на эту тему, наверное, можно было бы написать целую книгу). IP-адрес - это самый простой ключ для отслеживания того, кто запрашивает, но он не идеален из-за корпоративных прокси, которые могут случайно засчитать много пользователей как одного и того же пользователя и активировать ограничение скорости, когда вы этого не хотите. Если ваша служба требует аутентификации, тогда учетные данные аутентификации будут хорошим ключом для идентификации пользователя для ограничения.

jfriend00 10.09.2018 08:26

IP-адреса также могут быть заблокированы ботом, который может чередоваться между множеством разных IP-адресов, тем самым используя больше ваших услуг, чем вы хотите, но не попасть в ограничение скорости. Учетные данные для авторизации в качестве ключа, как правило, лучше всего. Это одна из причин, по которой многие службы (например, Google) требуют, чтобы вы зарегистрировались и получили какие-то учетные данные для использования с их службой, даже если она бесплатна.

jfriend00 10.09.2018 08:27

Честно говоря, ваш вопрос действительно широкий, и на него довольно сложно ответить по поводу переполнения стека.

jfriend00 10.09.2018 08:28

Что, если я хочу защитить логин с помощью ограничения скорости? Таким образом, у пользователя все еще нет токенов.

Raz 11.09.2018 22:25

Вы можете измерить ограничение скорости на основе имени пользователя, которое предлагается для входа в систему. Это, по крайней мере, удержит кого-то от попыток угадать пароль для этого имени пользователя при повторных попытках входа в систему. Вы также можете использовать IP-адрес и просто принять его ограничения. Если вы пытаетесь защитить себя от браузера, вы можете cookie получателя, а также использовать это значение cookie (но боты могут удалить cookie, чтобы от них не было ничего полезного). По этой теме написано очень много. Я бы посоветовал вам много читать. Это хорошо изученная тема, гораздо больше, чем мы можем здесь передать.

jfriend00 11.09.2018 22:35
3
5
5 045
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Я бы рекомендовал реализовать аутентификацию на основе токенов, очень похожую на API Facebook. Таким образом вы можете отслеживать, кто использует API, и идентифицировать каждого пользователя.

Когда это будет реализовано, вы можете начать ограничивать вызовы в зависимости от пользователя (того, кто владеет токеном), который вызывает API, в нужный вам период времени.

Ответ принят как подходящий

Нет ничего плохого в использовании плагина. Возьмите express-rate-limit с Redis Store, например, вы можете ограничить скорость всего приложения для каждого IP-адреса пользователя и сохранить это в Redis:

const rateLimit = require("express-rate-limit");
const RedisStore = require('rate-limit-redis');
app.use(rateLimit({
  store: new RedisStore({ /* ... config */ });
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100 // limit each IP to 100 requests per windowMs
});

Или вы можете ограничить только данную конечную точку:

const someApiLimiter = rateLimit({
  windowMs: 5 * 60 * 1000,
  max: 12,
});
app.use('/api/some', someApiLimiter);

По умолчанию используется req.ip, но вы можете предоставить функцию keyGenerator и использовать что-то вроде, скажем, комбинации req.ip и req.user._id. Итак, вы прикрыты по всем статьям.

Я рекомендую Redis для этих целей, так как это очень много небольших данных, которые вам нужны быстро, Redis делает это хорошо.

Что вы имеете в виду под функцией keyGenerator?

Raz 11.09.2018 22:45

А также не могли бы вы предоставить пример конфигурации в tore: new RedisStore ({/ * ... config * /}); ?

Raz 11.09.2018 22:46

@Raz в документации много информации: npmjs.com/package/express-rate-limit. По сути, keyGenerator - это если вы хотите отслеживать что-то еще, кроме IP-адреса пользователя - может быть, пользовательский агент или что-то еще.

Zlatko 12.09.2018 08:49

Конфигурация в Redis Store также описана в документации: npmjs.com/package/rate-limit-redis. Но вот краткий список свойств: expiry (по умолчанию 60 секунд), resetExpiryOnChange (по умолчанию false), prefix - префикс для ключей в Redis и client - клиент Redis, который вы, возможно, уже настроили (по умолчанию require('redis').createClient();).

Zlatko 12.09.2018 08:52

ограничитель скорости гибкий позволяет устанавливать разные лимиты для разных пользователей.

Он работает в кластере без каких-либо БД, MongoDB или Redis.

Прочтите о защите конечных точек входа здесь защита конечных точек входа здесь

Другие вопросы по теме