Pull to refresh

Comments 20

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

Ну и при наличии минимальных знаний криптографии от таблички можно отказаться (см. Flask-Login): делать подписанную куку на основе секретного ключа, хеша от «соленого хешированного пароля», который уже есть в базе, IP и даты протухания. Грубо говоря:

hash(salted_password_hash) + date + ip, hmac(secret_key, hash(salted_password_hash) + date + ip)

При получении такой куки проверять все поля. Если не подходит hmac, неправильный IP, протухшая дата или несоответствующий хеш от «соленого хешированного пароля» — кука невалидна, пользователя по ней не пускаем, стираем. Если валидна — переставляем с новой датой протухания. Для каждого пользователя существует множество кук, по которым его пустило бы. Это не проблема, так как для выставления фальшивой, но валидной куки необходимо взломать hmac или украсть с сайта секретный ключ.

Очевидно, элемент случайности уже есть в salted_password_hash в виде соли. Зачищать на стороне сервера ничего не надо, так как ничего не хранится, кроме того, что и так должно храниться вечно.

Также очевидно, что смена пароля (в том числе на тот же самый) сделает куки на других устройствах недействительными.
Я навел пример имплементации лишь для контраста. Описания подходов достойно отдельной статьи. Я учел ваш коммент и добавил в посте ссылку на подробное описание различных схем авторизации пользователя в целом. Честно говоря, я думал не писать пример имплементации вообще, так как пост больше о доверии к фреймворкам чем об автентификации.
Отказ от хранения токена в базе — не очень хороший вариант. Вы лишаетесь возможности сделать функцию «логаут на всех устройствах». А она полезна, например, при подозрении на угон пароля (ну или просто при смене пароля).

Вообще, подробная статья о способах реализации функции “remember me” очень бы не помешала.
Функция «логаут на всех устройствах» в моем варианте как раз есть. Для этого достаточно поменять пароль (в том числе на тот же самый) — при этом изменится его соленый хеш.

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

ps: а, понял, вы предлагаете совсем отказаться от хранилища на сервере.
смена пароля (в том числе на тот же самый)

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

Для использования функциональности «логаут на всех устройствах» пользователь в моей схеме действительно должен ввести пароль. Впрочем, я эту функциональность в явном виде могу и не предоставлять. Достаточно фразы «Если вы подозреваете, что злоумышленники получили доступ к вашей учетной записи, смените пароль».
Использовать в качестве токена шифрованный id пользователя в недрах фреймворка — это прямо-таки epic fail :/
Привязка к ip опять же не самый лучший вариант. У многих ip меняются раз в сутки, а например с GPRS так вообще ip может меняться по несколько раз в пределах одного сеанса. Спустился в метро, потерял связь. Вышел из метро, предположим сессия истекла, идёт попытка авторизации по токену, а ip уже другой.
Ну как я писал, это всего-лишь пример. Конечно есть плюсы и минусы
Ваш способ не работает в тех случаях, когда нужно авторизовываться на разных устройствах, например на работе и дома, а такая вещь нужна практически всегда. Аннулировать просто так предыдущий токен нельзя, иначе в другом месте разлогинит. Фейсбук например предлагает выйти «из всех устройств», по сути обнулить все токены.
Анулируеться только токен по которому пользователь зашел на сайт, другие остаються. Тоесть спокойно можно сидеть нараз с двух девайсов
Если вы говорите про токен в сессии или куках, то он может быть утерян по разными причинам и узнать — по какому токену заходил пользователь будет невозможно.
Постараюсь описать пример:
1) Вы логинитесь с компа, создается токен т1
2) Вы логинитесь с телефона, создается токен т2
3) Через некоторое время вы зпходите с компа опять, системе передается куки т1. Система вас логинит, стирает т1 с базы, создает и отсылает вам токен т3
4) Вы заходите с телефона, ваш токен т2 аналогически заменяется на т4.

Итого в системе теперь 2 токена (т3 и т4) и телефон и компьютер залогинены
Если я на компе переустанавливаю браузер или куки были утеряны, стерты, кончилось их время, то токен т1 останется в системе и никак его уже клиент (браузер) передать не сможет. Если этот токен вечный или дан на большой период?
у токенов есть срок годности (колонка expires_on). Перед каждым селектом с нее запускаем: DELETE FROM tokens where expires_on < now()
«Фикс» на самом деле приводит к тому что теперь только один девайс может иметь «remember_me» токен. Поскольку он хранится в табличке с пользователями то очевидно что каждый пользователь может иметь только один токен. Я не понимаю почему им так трудно сделать правильно?
Только начал изучать Laravel как кандидата на реализацию веб-сервиса — передумал =-/
Sign up to leave a comment.

Articles