[Из песочницы] Как усилить защиту паролей «12345» от brute-force атаки

Объект: веб-форма входа в систему.Дана задача: усилить защиту аккаунта пользователя от подбора простого пароля к его аккаунту, используя минимум средств.Что такое минимум средств? Это не использовать таблицы-справочники для блокировки по IP-адресу и User-Agent. Не использовать лишние запросы к системе, не захламлять систему авторизации лишними циклами.

И, выполнить совершенно волшебное требование — даже если бот введет нужные логин и пароль… не дать ему войти, а вот реального пользователя впустить.

Можно ли так сделать? В теории, конечно, нет. Но в практике, в частном порядке и при определенных условиях, как оказалось, весьма возможно.Приглашаю под кат за подробностями.Итак, предположим, что, логин у нашего пользователя «test», а пароль »12345». Мерзкий бот подключил свой словарь сгенерированных паролей, и готов работать с нашим API со скоростью 700 паролей в секунду. Он знает, что логин пользователя — «test». Ситуация аховая: пароль »12345» будет вычислен за очень малое время. Пользователь, тем временем, открыл сайт и начал вводить логин и пароль в веб-форму логина.

Давайте внесем изменения в систему авторизации, пока ни один из них не начал свою работу, и не случилась беда.

Магия будет заключаться в третьей переменной, которую следует «приклеить» к паре логин-пароль. Я назвал ее touch.

Каждый раз, когда кто-то получает (внимание: получает, а не запрашивает!) логин-пароль в БД, дата touch обновляется на текущую дату-время:

login/password/touch: 'test', '12345', '2014–12–13 14:00:00'. Предположим, что бот начал первую итерацию и спросил пароль »1» для логина «test» в '2014–12–13 15:00:00'. Cрабатывает контроллер login_check, который читает из базы данных пару логин-пароль, которую никто не «трогал» целых 2 секунды! Откуда вообще эти 2 секунды?! Об этом будет дальше.Такая пара логин-пароль находится. Разница между последним touch и текущим временем — 1 час. Поэтому запись успешно возвращается на наш запрос.

Сначала пара логин-пароль сличается и login_check приходит к выводу, что test/12345 не равно test/1. Контроллер возвращает «auth error». При этом обновляется дата touch для этой пары логин-пароль на '2014–12–13 15:00:00'.

Бот приступает к следующей итерации: спрашивает пароль »2».

Скорость работы бота измеряется микросекундами. Он спрашивает запись сразу же: '2014–12–13 15:00:00'.И тут вступает в действие наш алгоритм — условие по третьему параметр touch уже не выполняется. 2 секунды еще не прошли. Fail.

Модифицированный нашей логикой контроллер login_check не может получить пару логин-пароль из БД.Запись существует, но ее дата touch еще слишком «свежая».

И она она уже не попадает в выборку. А раз такой пары логин-пароль нет, то контроллер ответит боту «auth error».

Бот не сдается, продолжает подбор и, наконец, приходит к правильному паролю »12345».Вероятность, что именно текущая попытка вернет успех — крайне и крайне мала. 1/700 на каждую попытку входа! То есть, если раньше было 1:1, то теперь 1:700. И чем быстрее бот, тем больше вероятность, что его ждет fail.

В итоге только очень малая часть паролей будет действительно проверена. Остальные получат ложные срабатывания, даже если они будут верны.

А что пользователь? Начнем с пользователя. Пользователь, в отличие от бота, вводит данные в веб-форму руками через клавиатуру и смотрит зрительными органами на монитор. А гибкость его алгоритмических способностей куда лучше, чем бота. По сути, пользователь в некотором роде искусственный интеллект. А значит, часть логики уже лежит в нем. И мы ею воспользуемся!

Когда пользователь видит ошибку авторизации, он часто переписывает пароль заново. Даже если пароль он только что вбил сам. Даже если пароль подставлен автоматом из password-manager. Я делал это еще до того, как применил свою систему защиты простых паролей.

Да, я обещал рассказать про две секунды. Рассказываю: Две секунды это оптимальное время, за которое пользователь проводит операции по корректировке данных и совершает следующую попытку входа. В эти две секунды пользователь укладывается полностью. Если пользователь не уложился — он всегда может повторить попытку и за это время действие touch уже наверняка аннулируется.

В заключение.Что будет если бот знает о 2-секундной задержке? Если применить наши тестовые данные, это значит, что эффективность бота снизится: всего 1 попытка подбора пароля вместо 1400.

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

Заранее спасибо.

© Habrahabr.ru