К вопросу о безопасности, или зачем вообще хранить пароли

в 9:17, , рубрики: авторизация, Алгоритмы, безопасность, Веб-разработка, криптография, пароли, хеширование, метки: , , ,

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

Общие рассуждения

Когда передо мной встала задача авторизации пользователей, я пришел к выводу что хранение паролей, в любом виде, недопустимо. Ни в открытом виде, ни в виде хеша, кроме того недопустима передача пароля в открытом или хешированном виде по сети, при авторизации пользователя на сайте. Причины просты:

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

Решение

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

key = MD5(login + MD5(password))

Рассмотрим шаги

Регистрация

На стороне клиента производится вычисление ключа, по приведенной выше формуле, по сети передается логин и полученный ключ, они же хранятся в базе на сервере. Т.е. при краже базы, получить путем расшифровки и логиг и пароль вряд ли будет возможным. Хотя, конечно, можно попробовать придумать алгоритм дешифровки, зная логин и формулу генерации ключа, здесь нужно оценить трудозатратность и возможность.
Как вариант можно не хранить логин, а если мы хотим прописывать на странице сайта что-то вроде
Добро пожаловать, юзернейм, прописывать при входе на клиенте логин в куки и брать оттуда, тем самым мы избавимся от необходимости хранить логин в базе и повысим надежность.

Вход

Аналогично вычисляется ключ и передается на сервер, на сервере генерируется второй ключ на период сессии, например так:

session_key = MD5(key + date_now)

который пишется в базу, передается в куки клиенту, и будет использоваться для проверки авторизованности пользователя.

Мания преследования

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

В данном случае мое решение заключается в следующем:

  1. В начале сессии заводим на клиенте и в базе поле Counter привязанное к ключу сессии, устанавливаем в 0
  2. На клиенте работает таймер, период срабатывания которого задается случайным образом на каждую следующую итерацию, например:
    period = 10000 + rnd(5000, 50000) // от 15 секунд до минуты
    
  3. При срабатывании таймера
    • клиент просит у сервера сгенерировать новый ключ сессии
    • сервер проверяет текущий ключ сессии, если ключ не подошел, предупреждаем пользователя о возможном перехвате трафика(на почту), и советуем сменить пароль, на клиенте советуем проверить почту и говорим что сессия была завершена
    • если проверка текущего ключа прошла успешно, сервер увеличивает значение счетчика на 1, генерирует новый ключ сессии и отсылает клиенту значение счетчика и ключ
    • клиент принимает новый ключ и значение счетчика, сравнивает собственный счетчик с присланным, и если разница не равна единице, значит есть вероятность перехвата трафика (т.е. человек использовавший наш ключ, зашел на сайт, и таймер на его странице запросил новый ключ раньше нас), в этом случае оповещаем сервер о взломе, сервер прерывает сессию, и высылает письмо с предложением сменить пароль.
    • если разница счетчиков оказалась равна единице, записываем в счетчик новое значение, и обновляем ключ сессии

Данный способ я использую в Node.JS, который позволяет контроллировать все запросы к серверу, и соответсвенно позволяет крайне просто встроить такое решение.

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

Автор: Ogoun

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js