Ограничить пользователя, чтобы сделать ограниченный запрос в секунду - PullRequest
5 голосов
/ 04 января 2012

Окружающая среда:
Веб-приложение на основе Java-EE


Задача
Необходимо ограничить пользователя, чтобы сделать более 5 (например) запрос в течение одной секунды (в основном BOT)


Решение :
В качестве базового проекта я планирую иметь 2 синхронизированных Map в области применения

Map<String, Map<Long, Integer>>

String для sessionId запроса

Long для текущего второго представления

Integer для хранения количества запросов


Процесс:

Шаг 0:

Настройка Filter для перехвата каждого запроса

Шаг 1:

определить карту Я посмотрю, если текущий minute нечетный, тогда я добавлю данные на mapOne, и я очищу mapTwo

Шаг 2:

карта процесса

int requestNoForThisSecond = mapXX.get(request.getSession().getId()).get(currentSecondRepresantationInLong);
if(requestNoForThisSecond <= 5){
          requestNoForThisSecond++; 
          mapXX.get(request.getSession().getId()).put(currentSecondRepresantationInLong, requestNoForThisSecond);
}else{
         response.sendRedirect();// redirect to some captcha page
    } 

Шаг 4:

также удаляет запись сеанса, если сеанс истекает / пользователь выходит из системы


Это очень простой дизайн для проблемы

У кого-нибудь из вас есть идея или предложение получше?

Ответы [ 5 ]

3 голосов
/ 04 января 2012

Прежде всего, я думаю, что вы должны забыть идею идентификатора сеанса и использовать вместо этого IP-адреса. Вы не ожидаете, что бот отправит вам необходимые файлы cookie, чтобы вы могли отслеживать его сеанс, не так ли?

Во-вторых, я думаю, что ваш подход излишне сложен. Все, что вам нужно, - это сопоставление IP-адреса с массивом времени [N], где N - это фиксированное число, то количество запросов, которое вы планируете разрешить в секунду. (Я предполагаю, что он будет относительно низким.) Таким образом, каждый раз, когда у вас есть запрос с данного IP, вы смещаете содержимое массива на единицу и добавляете время нового запроса в конец массива. , Затем вы вычитаете время по индексу 0 вашего массива из времени по последнему индексу, и это дает вам количество времени, которое потребовалось этому IP для отправки вам N запросов, которые вы можете тривиально преобразовать в количество запросов в секунду.

Кроме того, вам может понравиться это обсуждение: https://softwareengineering.stackexchange.com/questions/126700/development-of-a-bot-web-crawler-detection-system

1 голос
/ 04 января 2012

Существует шаблон токена синхронизатора .Этот шаблон был предложен для предотвращения двойной отправки, подделки межсайтовых запросов и т. Д. Struts широко использует этот шаблон (пример упоминается в JavaRanch ).


Для тех, кто неНе знаю, как работает Synchronizer Token Pattern, вот что:

  1. Пользователь запрашивает страницу.На сервере контроллер, отвечающий за запрос страницы, получает токен (не JSESSIONID) со страницы.
  2. Если токен, полученный из запроса, совпадает с токеном, найденным в сеансе, это действительный токен, продолжайте.
  3. Сбросьте токен (создайте новый токен) и сохраните его в сеансе.Таким образом, вы можете выполнять проверку и каждый раз возвращаться на одну и ту же страницу с новым токеном.

В вашем предложении вам нужно будет рассчитать время отправки вашего запроса, подсчитать количество полученных токенов сеанса (используя HttpSessionListener) и ограничьте ваш запрос.

Надеюсь, это поможет.

1 голос
/ 04 января 2012

Возможно, это очень плохой взлом, но ...

Реализуйте пользовательский Set<Long>, для которого операция .add() возвращает false, если вы пытаетесь выдвинуть то же самое длинное значение больше порога и использовать его какценности?

Код будет выглядеть следующим образом:

if (!theMap.get(whatever()).add(secondInLong))
    // threshold reached

Одним из преимуществ является то, что он запрещает условия гонки в вашем текущем коде: если синхронизируется только ваша карта, проверьте количествосеансы не защищены.При таком решении это.

Или окружить код какой-либо блокировкой и использовать «нормальную» карту.

Если продолжить эту идею, вы даже можете реализовать пользовательский Map с делегированием.Представление «длинная секунда» будет затем рассчитываться внутри самой карты, и вам не нужно будет об этом заботиться.

1 голос
/ 04 января 2012

5 запросов в секунду эквивалентно 1 запросу каждые 0,2 секунды. Так почему бы просто не иметь Map, в которой хранятся sessionID и последний System.nanoTime () пользователя, а вашему фильтру нужно только сделать быструю оценку, чтобы убедиться, что с момента последнего запроса пользователя прошло не менее 200 мс.

0 голосов
/ 04 января 2012

Звучит разумно и похоже на то, что было предложено в этой статье для интеграции с Spring <-> captcha.

...