Брут-форс / DoS-профилактика в PHP - PullRequest
18 голосов
/ 13 ноября 2009

Я пытаюсь написать сценарий для предотвращения попыток входа в систему методом грубой силы на веб-сайте, который я создаю. Логика выглядит примерно так:

  1. Пользователь отправляет информацию для входа.
  2. Проверьте правильность имени пользователя и пароля
    • Если да, впустите их.
    • Если нет, записать неудачную попытку в базу данных. Проверьте, не слишком ли много ошибок в течение определенного периода времени (например, 5 за 5 минут):
      • Если Да, то приостановить выполнение на 10 секунд: sleep(10), затем сообщить пользователю об ошибке входа в систему.
      • Сообщить пользователю об ошибке входа в систему немедленно

Объясняя это коллеге, меня спросили, как это поможет, если хакер отправит, скажем, 1000 запросов в секунду. Вернутся ли первые 5 сразу, а остальные 995 займут всего 10 секунд?

У меня есть подозрение, что я не до конца понимаю, как работает HTTP - эта ситуация даже выше возможной, или есть ли ограничение на число одновременных запросов, которые сервер будет обрабатывать от одного клиента?

Лучшим решением было бы увеличить время сна?

sleep($numRequestsInLast5Minutes - 5)

Итак, первые 5 будут быстрыми, а затем каждый последующий увеличит сон.

Ответы [ 5 ]

15 голосов
/ 04 апреля 2013

Проблема заключается в балансе между доступностью пользователя и моделью атакующего.

Первое решение

If not password correct for a certain number of time:
    block the user
    send a reset link to the user

Пользователь : может быть заблокирован, и им не нравится сброс
Атакующий : заблокировал всех пользователей, пытаясь пройти аутентификацию для всех пользователей (особенно если все логины доступны публично)

Второй раствор

If not password correct:
    sleep(amount_of_time)

Вопрос в том, каково значение 'amount_of_time'?

Пользователь : может раздражать ожидание 'amount_of_time' для каждой ошибки
Атакующий : продолжайте попытки, с более низким тестом / сек

Третье решение

If not password correct:
    sleep(amount_of_time)
    amount_of_time = amount_of_time * 2

Пользователь : меньше раздражает за несколько ошибок пароля
Attacker : заблокировать подключение пользователя, отправив партию неверного пароля

Четвертое решение

If not password correct for a certain number of time:
    submit a catchpa

Пользователь : необходимо разрешить CAPTCHA (не слишком сложно)
Атакующий : необходимо разрешить CAPTCHA (должен быть сложным)

Хорошее решение (и используется многими сайтами), но будьте осторожны с нашей CAPTCHA. осуществление . В любом случае есть хитрость (см. Следующее решение).

Пятое решение

If not password correct for a certain number of time:
    block the ip
    (eventually) send a reset link

Пользователь : Пользователь может быть заблокирован, потому что он не может правильно запомнить свой пароль.
Атакующий : пробует один и тот же пароль с другим пользователем, потому что блокировка зависит от количества логинов пользователя.

Окончательное решение?

If several login attempts failed whatever is the user by an IP :
    print a CAPTCHA for this IP

Пользователь : Пользователю не может быть заблокирован IP-адрес, но он должен запомнить свой пароль.
Атакующий : сложно провести эффективную атаку грубой силой.

Важные заметки

Форма входа или ссылка для входа заблокирована? Блокировка формы входа бесполезна.

Сопротивление грубой силе - это ПЕРВАЯ проблема сложности пароля, поэтому вам нужна строгая политика паролей (особенно в случае распределенной грубой силы).

Я не упоминаю тот факт, что вы хэшировали свои пароли солью, вы уже делаете это правильно? Поскольку, если доступ к базе паролей проще, чем перебор, злоумышленник выберет это решение ( «Цепь настолько же сильна, как и ее самое слабое звено» ).

13 голосов
/ 13 ноября 2009

Я хотел бы предложить, если пользователь попытался безуспешно, скажем, более пяти раз и пять минут, вы сразу же начнете возвращать 503 Service Unavailable для этого IP-адреса. В случае сбоя входа в систему вы можете использовать memcache для получения текущих неудачных попыток для IP, а затем увеличить сумму и сохранить ее обратно в memcache с истечением 5 минут.

Вы не хотите вставлять sleep в свой PHP-код, поскольку это позволит одному пользователю создавать множество соединений с вашим веб-сервером и потенциально приводить к сбоям других пользователей.

Поскольку пользователь не вошел в систему, у вас нет cookie-файла сеанса, и если пользователь пытается грубо взломать свой аккаунт, он может вообще не представить cookie-файл.

4 голосов
/ 17 ноября 2009

Я использовал что-то вроде этого ...

  1. Проверка имени пользователя и пароля

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

    1.2 Каждый сбой делает ожидание между возможностью входа в систему что-то вроде failsCount * 30 секунд, максимум (например, 10 минут).

  • Это означает, что атака грубой силой будет экспоненциально длиться дольше и дольше.
  • Он может заблокировать пользователя - но он не будет считать неудачный вход в систему при попытке входа в течение периода блокировки. Это должно минимизировать это.

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

2 голосов
/ 15 июня 2014

Я создал класс, который заботится о защите от перебора в PHP.

https://github.com/ejfrancis/BruteForceBlocker

он регистрирует все неудачные входы по всему сайту в таблице базы данных, и, если количество неудачных входов в систему за последние 10 минут (или любой другой период времени, который вы выберете) превышает установленный лимит, он вызывает задержку и / или Требуется капча перед повторным входом.

пример:

// построить массив настроек газа. (# недавние неудачные входы в систему => ответ).

$ throttle_settings = [

    50 => 2,            //delay in seconds
    150 => 4,           //delay in seconds
    300 => 'captcha'    //captcha 

];

$ BFBresponse = BruteForceBlocker :: getLoginStatus ($ throttle_settings);

// $ throttle_settings - необязательный параметр. если он не включен, будет использован массив настроек по умолчанию в BruteForceBlocker.php

switch ($ BFBresponse ['status']) {

case 'safe':
    //safe to login
    break;
case 'error':
    //error occured. get message
    $error_message = $BFBresponse['message'];
    break;
case 'delay':
    //time delay required before next login
    $remaining_delay_in_seconds = $BFBresponse['message'];
    break;
case 'captcha':
    //captcha required
    break;

}

1 голос
/ 13 ноября 2009

Я не уверен, что лучший метод, но при работе с DoS-атаками, лучшая стратегия состоит в том, чтобы на самом деле перенаправить трафик * с вашего сервера. Установка таймаутов на самом деле не поможет, потому что вы все еще обрабатываете запрос и запускаете PHP.

Рассматривали ли вы создание другого веб-сервера, на котором установлена ​​более простая урезанная версия страницы входа? Когда пользователь пытается слишком много раз (например, тысячи раз), отправьте сообщение, чтобы настроить маршрутизатор и перенаправить этого пользователя на второй веб-сервер.

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

...