Pull to refresh

Как усилить защиту паролей «12345» от brute-force атаки

Algorithms *
Sandbox
Объект: веб-форма входа в систему.
Дана задача: усилить защиту аккаунта пользователя от подбора простого пароля к его аккаунту, используя минимум средств.

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

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

Можно ли так сделать? В теории, конечно, нет. Но в практике, в частном порядке и при определенных условиях, как оказалось, весьма возможно.
Приглашаю под кат за подробностями.

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

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

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

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

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» для пользователя «test» обновляется на текущую: '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. Очень хочется услышать критику, потому что система уже внедрена в один проект, и пока не создала ни одного тикета с проблемой доступа к системе.

Заранее спасибо.
Tags:
Hubs:
Total votes 44: ↑25 and ↓19 +6
Views 30K
Comments Comments 52