Комментарии 94
И ещё один, менее (пока) популярный (и доступный только на устройствах Apple) метод беспарольной аутентификации: использовать Touch ID для аутентификации по отпечаткам пальцев.
Тут надо отметить, что Touch ID обычно только заменят PIN-код при доступе к криптографическим ключам, которые используются для аутентификации.
Кстати есть решения и с новомодным FaceID.
Что касается биометрии, то ее следует рассматривать как локальную аутентификацию на устройстве. Я бы избегал систем, где биометрические данные используются для централизованной аутентификации.
Одним из трендов в аутентификации обещает стать FIDO U2F. Он, к сожалению, не упоминается в этой статье. Про него очень неплохо написано тут.
Если аутентификация stateless, то инвалидировать нельзя никак. Единственное, чем вы можете управлять это время жизни токена. Нужно с умом выбирать тот или иной способ аутентификации в соответсвии с конкретной задачей. И конечно не стоит слепо гнаться за «набирающими популярность» вещами. Надо все самому взвешивать и оценивать.
Если приходит юзер с токеном, то, как правило, там же приходит и user_id, по которому мы будем загружать из БД объект этого юзера. Ничего не мешает хранить в этом объекте и минимальную дату годного токена. Если нужна инвалидация — то просто обновляем эту дату в БД до текущей и все токены с ранними датами протухают.
Для задач, когда хочется и токены использовать и контролировать статус токена, удобнее использовать список отозванных токенов по аналогии CRL для сертификатов.
Пожалуйста, не надо меня убеждать, что это совсем чуть-чуть информации или что это легко и просто сделать. Я не это оспариваю сейчас.
куки, кажется привязывали к ip, но это хранится в бд сервера, а от нее мы хотим отказаться.
ведь должно быть что-то подобное… ну, например, сервер видит запрос, на основании сведений об ip, браузере, на основании каких-то параметров fingerprint компьютера генерирует хэш, и возвращает нам токен с хешем внутри. И далее при каждом предоставлении токена сервером генерируется и проверяется совпадение хешей. Таким образом получится, что токеном нельзя воспользоваться на другом устройстве/из другой программы.
Такое уже есть? Или проще и считается достаточным короткое время жизни?
А вопрос объема дело десятое, т.к. на малом объеме это не существенно, а на большом есть проблемы и посерьезнее.
Когда пользователь выходит из системы, токен на клиентской стороне уничтожается, с сервером взаимодействовать не нужно.
И вот тут есть проблема — приложение должно особым образом обрабатывать выход (закрытие вкладки или окна). Так же стоит обратить внимание что токен не может быть отозван серверном до истечения expire. Ну то есть можно, но вообще нет.
Пожалуй единственный недостаток jwt — отсутствие стандартных механизмов верификации. Но это прямо вытекает из его ориентированности на распределённость.
Это не очень удобно если нужно дать возможность верификации другим сервисам (или даже сторонним). Было бы удобно если бы поддерживался еще и открытый ключ для верификации который можно было бы передавать другим.
Возможно ограничение целей/приложений где и как долго токен действует.
Или приложение может требовать токен не старше N секунд и отправлять принудительно за новым
Возможно ограничение целей/приложений где и как долго токен действует.
Если в самом токене — это не возможность отзыва при бане, например.
Или приложение может требовать токен не старше N секунд и отправлять принудительно за новыммеханизм получения по хорошему должен требовать действий от пользователя (аутентификация), в общем случае. Получается ограничение жизни «сессии».
И еще, не надо сыпать сложной терминологией в простой статье без пояснений, пожалуйста. :( Я ничего не знаю про репликацию. Я даже не знаю что это.
А так вообще очень крутая статья. Хорошо все объяснено.
Если токен хранится только на клиенте и в нем содержится роль юзера, то что ему мешает подделать ее и прописать себя админом?
Этому препятствует тот факт, что токен криптографически подписан.
А вы говорите, «md5»…
А без соли хранить md5 нельзя, так как в наши дни это равнозначно отсутствию хеширования — сейчас существует масса таблиц, в которых можно запросто найти все популярные хеши md5.
Хранить md5 нельзя ни с солью, ни без. Это очень быстрый алгоритм. А массу радужных таблиц можно найти далеко не только для md5.
MD5 и какие-либо другие одиночные хэши не стоит использовать даже с солью — при известном хэше и соли 8-мизначный пароль из букв верхнего и нижнего регистра, цифр и спецсимволов можно перебрать за несколько часов. Вместо этого современные системы используют PBKDF2 с большим количеством итераций для сверки пароля.
Не совсем понимаю, причём тут атака дней рожденияВ том и дело, что ни причём. Но это единственная атака, которую практически можно провести на MD5. Кроме перебора, конечно.
MD5 и какие-либо другие одиночные хэши не стоит использовать даже с солью — при известном хэше и соли 8-мизначный пароль из букв верхнего и нижнего регистра, цифр и спецсимволов можно перебрать за несколько часов.Это другая история. Можно точно также сделать много раундов MD5.
Лет 15-17 назад мало кто заморачивался хешированиями и соленьями.
Открытые пароли в базах лежали в каждой первой базе, которую я видел ^_^
Чудеса в решете.
Хотелось бы еще почитать про аутентификацию на основе утверждений (claims-based).
Аутентификация — это проверка вашей личности. Когда вы входите в приложение с именем и паролем, вы аутентифицируетесь.Пароль в примере — способ разрешить дальнейшее использование аккаунта, идентификатором которого выступает имя. Аутентификация — проверка на подлинность, на соответствие заявленному. Проверку прав на доступ к аккаунту можно считать подвидом авторизации. Аутентификацию можно считать неотъемлемой частью, обязательным шагом процедуры авторизации. То есть «не путайте» не должно превратиться в «основательно разделяйте».
Мне кажется, или идея уже освещалась на хабре уважаемым SuperPaintman не так давно
https://habrahabr.ru/post/341164/
Спасибо, актуально! Как раз ночью сдал контрольную на coursera.org, по аутентификации и авторизации в node.js через токены и пасспорт и думал что-нибудь почитать ещё по теме)
Автор, большое тебе спасибо! Я давно искал что-то вроде JWT, но почему-то Гугл для авторизации без состояния советовал только отдельные сервера для аутентификации, типо SAML и oAuth. Единственное о чем я думаю, секрет должен генерироваться раз в какой-то промежуток времени, иначе если его подобрали, то вся система скомпрометирована.
В статье приравниваются понятия аутентификации на основе кук и на основе сессий. Но ничто не мешает положить тот же токен в куку и не создавать сессии на сервере.
В статье так и написано.
"Токен хранится на клиентской стороне, чаще всего в локальном хранилище, но может лежать и в хранилище сессий или кук."
Или я вас не пойму, или вы запутались.
Сессионный токен это просто идентификатор без полезной нагрузки, просто случайно сгенерированная строка. Такой токен нет особого смысла держать в веб-хранилище. Он передается на сервер через куки, а потом сравнивается с имеющимися токенами в БД.
Токен JWT это зашифрованные данные. Они могут занимать большой размер и поэтому в куки могут не поместится, тут на помощь приходит веб-хранилище. Поскольку доступ к этому хранилищу осуществляется через js, то такой подход актуален, в основном, для SPA.
И правильно ли я понимаю, что если мы используем jwt — мы должны его при каждом запросе передавать на сервер? или есть нюансы?
Токен jwt можно использовать как вам вздумается. Например если у вас токен большой то чтобы его не гонять, можно его хранить в webstorage и токеном получать классическую сессионную куку на сервере и гонять уже ее. В таком случае плюс в экономии траффика и возможности сделать короткую сессию чтобы базу не забивать сессиями годовалой давности.
Недостаток у токена один: если кто то отберет у вас права, то в токене они останутся и сервер будет доверять токену, а не обновленным правам (потому что токен валиден). Чтобы этого избежать придется городить костыль и проверять права при каждом запросе, и jwt перестает отличаться от простых сессионных куки. Можно конечно сделать красивый костыль — например при смене прав куда-то писать что для такого пользователя все токены старше х считать недействительными, и еще хранить дату выдачи в токене, и еще проверять при каждом запросе эту базу, вместо перечитывания всех прав
"Кроме того, раз вы можете хранить внутри JWT дополнительные данные вроде пользовательских разрешений, то можете сэкономить и дополнительные обращения поисковые запросы на получение и обработку данных."
Ага, а если нам нужно изменить пользовательские разрешения?
Ну на сервере мы токен не храним. Когда пользователь к нам прийдёт с токеном, откуда мы будем знать что для него нужно выдать новый токен? Из БД?
Another example you might be familiar with is the 2-step verification of Google, facebook etc.
Перевод
Другой знакомый пример — двухфакторная аутентификация Mail.Ru, Google, Facebook и т. д.
ГОСТ на эту тему сейчас только разрабатывается, но есть же NIST SP 800-63b, где про это очень хорошо написано. И Mail.ru стоило бы более грамотно подходить к этому вопросу, в переводах в том числе.
Для тех, кто не в теме:
Двухшаговая аутентификация отличается от двухфакторной тем, что при двухфакторной вы не знаете результат проверки первого фактора, пока не введете оба фактора. Результат для вас будет либо успех (оба фактора верны) либо неудача (как минимум один из факторов неверный). В двухшаговой вы сначала узнаете, что успешно ввели первый фактор и только после этого вам предлагается ввести второй фактор. То есть тут есть возможность провести атаку сначала на один фактор, а потом проводить атаку на второй. Это зачастую упрощает задачу злоумышленника и по праву считается менее защищенным способом аутентификации.
Авторизация — это проверка наличия у вас доступа к чему-либо. Это может быть набор разрешений на какие-то действия.
Авторизация — это НЕ проверка наличия у вас доступа к чему-либо.
Авторизация — это процедура предоставления субъекту определённых прав.
Так что это вопрос базисной терминологии.
Если процесс, то включает в себя аутентификацию.
Если результат, то отказ или отсутствие отказа, причем отсутствие отказа можно назвать предоставлением права.
В случае с Google этот сервис называется Google Accounts.ЕМНИП сервис называется Google Maia, или что-то вроде того.
Since JWT are signed and encoded only, and since JWT are not encrypted, JWT do not guarantee any security for sensitive data.
Ну, обычно JWT содержит данные о пользователе. Вряд ли они являются секретными для него самого.
Кроме того, ваша цитата противоречит RFC 7519:
JWTs represent a set of claims as a JSON object that is encoded in a JWS and/or JWE structure.
— пункт 3. JSON Web Token (JWT) Overview
То есть JWT может быть как подписанным, так и зашифрованным.
И ещё один, менее (пока) популярный (и доступный только на устройствах Apple) метод беспарольной аутентификации: использовать Touch ID для аутентификации по отпечаткам пальцев.
На адроиде СБОЛ использует биометрию вместо ввода пинкода, так что это не только Эпл.
Как-то странно смешаны методы, для новичка может показаться что для проекта нужно выбрать один из перечисленных. Но как по мне первые два должны идти в отдельной группе.
Ведь тот же беспарольный доступ с помощью одноразового токена или логин через соц. сети передает на сервер некий токен по клику по ссылке в письме или при редиректе с соц сети обратно на сайт проекта.
Далее сервер проверяет этот токен (в базе, oAuth, да это может быть тот же JWT). И в случае успеха для последующих запросов клиент уже будет передавать нечто внутреннее для системы с помощью куки или заголовка.
Так что я бы разбил методы на две группы — что мы используем для логина и что мы используем для подтверждения аутентификации для последующих запросов.
Статья конечно крайне полезная. Добавил в закладки, спасибо автору большое.
Но есть несколько вопросов по JWT токенам.
1) На некоторых конференциях я нашёл, что есть возможность revoke jwt токена (ну например вот с ndc https://www.youtube.com/watch?v=YF8coyfQb0Y). Из комментариев я так понял (прошу поправить, если не так понял), что revoke возможен только через бан лист. Но для проверки, содержится токен или нет в бан листе нужен доступ к базе / редису, то есть проблема скейлинга всё равно присутствует. Нет, данных хранитьменьше, но в статье говорится про фишку в скорости расшифровке vs скорость доступа к базе. А тут получается и расшифровка и доступ к базе. Смысл?
2) Но двигаясь дальше, допустим выбрали мы бан лист. И каждый раз в нём что-то смотрим. Возник следующий вопрос, а как по refresh токену получать данные? В видосике выше с конференции ребята используют одну и ту де функцию - revoke token для запроса нового токена и логаута. Но мы не можем её же использовать, она у нас за бан лист отвечает. Следовательно ребята делают с ошибкой?
Но тут тогда следующий вопрос. А как работает refresh токен в таком случае в логике статьи? Допустим я отправил токен, получил новый, аксес токен, у меня спёрли рефреш, как вылогинить ребят, которые спёрли рефреш? Они же могут новый получать, валидации на сервере нет, в бан лист добавлять?
А как понять, кого в бан лист добавлять? И почему добавлять нужно? Я же не знаю, что его спёрли. Знал бы, не дал бы спереть.
Как это должно работать, объясните пожалуйста?
А тут получается и расшифровка и доступ к базе. Смысл?
Токен не надо расшифровывать. достаточно проверять, например, что подписи нет в БД.
доступ к базе / редису, то есть проблема скейлинга всё равно присутствует
Принудительный отзыв - операция не очень частая, хранить (см. выше) достаточно хвост и дату истечения (в виде даты истечения записи), поэтому база не оч. большая. у токенов есть время жизни, поэтому база не пухнет бесконечно. Поэтому такую базу достаточно легко реплицировать - проблема скейлинга не такая серьезная, чем если надо реплицировать сессионные данные (которые еще и меняются по ходу дела, а подписи токенов статичны - там нет изменяемых данных). Справятся несколько мемкэшей\редисов\etc
revoke token для запроса нового токена и логаута. Но мы не можем её же использовать, она у нас за бан лист отвечает.
Не очень понял проблему. Принудительный логаут - это по сути тот же принудительный бан токена, только с UX нормальным. Если токен при логауте не банить, то им может воспользоваться кто-нибудь, да.
А как понять, кого в бан лист добавлять? И почему добавлять нужно? Я же не знаю, что его спёрли. Знал бы, не дал бы спереть.
Обычно сервисы это реализуют в виде "смотри, чувак, ты зашел с нового устройства, проверь если это был не ты" и списка сессий где-нибудь в UI, где можно убить все остальные сессии принудительно (в т.ч. рефреш). А вообще утекание рефреш токена равносильно утеканию куки с сессией по масштабам бедствия. Защищаться можно, в целом, теми же способами, например зашивать в токен IP получателя (что немного не крутой UX иногда, но зато чуть надежней)
Токен не надо расшифровывать. достаточно проверять, например, что подписи нет в БД.
В статье написано:Главное преимущество: поскольку метод никак не оперирует состояниями, серверу не нужно хранить записи с пользовательскими токенами или сессиями. Каждый токен самодостаточен, содержит все необходимые для проверки данные, а также передаёт затребованную пользовательскую информацию. Поэтому токены не усложняют масштабирование.
Вы говорите, что достаточно проверять, что подписи нет в бд.
Нашёл ещё одно видео (https://www.youtube.com/watch?v=s-4k5TcGKHg), в котором написано, что в бд нужно хранить только рефреш токен, что выглядит очень логично со всем, что я прочитал.
Ху из райт, соответственно. Потому как уже 3 мнения.
И подскажите, как вообще должен отрабатывать рефреш токен и почему. Здесь, я нашёл, что рефреш токен максимум должен жить 15 минут (https://www.youtube.com/watch?v=jzB4TfmOZyw). В другом видео - 1 день норм (https://www.youtube.com/watch?v=s-4k5TcGKHg).
От чего это зависит?
И если у меня истёк токен, всегда ли я должен кидать пользователя на окно авторизации? Если да, то почему я спокойно могу заходить в сервисы гугла без логина. Там на месяц токен? В таком случае, почему кто-то говорит, что он должен быть на минуты?
Ху из райт, соответственно. Потому как уже 3 мнения.
Подпись - это часть токена. Ее не надо расшифровывать. Можно весь токен целиком проверять. Суть та же, только кмк дольше просто. Вероятность совпадения подписей крайне мала. Проверять нужно только в случае если у вас реализован бан-лист. Если бан-листа нет - то можно и не проверять, но в таком случае рекомендовал бы сделать access token максимально коротким (1-2 минуты), чтобы их не надо было бы банить.
От чего это зависит?
От ваших политик безопасности и сценариев поведения. В целом у рефреш токена одна цель - получать новый access token. Сколько он будет жить - зависит от того, как часто идут обращения к защищенному эндпоинту. Очевидно, что если они идут реже, чем время жизни рефреш токена, то вся схема коту под хвост.
Поэтому универсальных цифр никто не даст, выбирайте под свой юзкейс.
Refresh token должен жить столько, сколько времени вы разрешаете пользователю не вводить пароль. 15 минут и 1 день — это очень мало, особенно для мобильных устройств, на которых длинный пароль ещё и фиг введёшь. Если вы не ошиблись и в тех видео действительно рекомендуют ограничивать refresh token — больше не смотрите ничего там.
Сейчас занимаюсь авторизацией в приложении под виндоус (коммерческий проект). Сама регистрация в лк на сервере. Так вот в данном случае например логичнее авторизация по телефону с коротким пин кодом. Смысл в том, что номер телефона почти всегда соответствует только одному человеку. Почта более "расплывчата" - ей могут пользоваться разные люди. Но вот подтвердить код из смс это однозначно может только то самое физ лицо, кому принадлежит телефон. Это то, что ты всегда носишь с собой (паспорт чаще забывают).
Вот в том числе из-за таких товарищей — телефон всяким сервисам я даю от одной службы IP-телефонии (входящие SMS приходит на почту и в телеграм). При этом регистрация в этом сервисе — на меня как физика (для юрлиц РФ у них тоже опция есть). И стоит не очень дорого.
Почему? А раньше был тот телефон который со мной но внезапно оказалось что:
- некоторые из тех, кому даешь номер — любят еще и для спама (c моей точки зрения) использовать (вроде "очень важных" извещений, голосом конечно, иногда ботом иногда человеком).
- совсем не факт что SMS — дойдет (особенно плохо стало примерно последний год, с зарубежными сервисами). А если дойдет — то в срок. Причем когда и сервису и оператор говоришь про проблему — начинается перекладывание сваливание друг на друга. Причем смена номера на номер другого оператора — чаще всего не решает проблему. А вот тот сервис IP-телефонии — просто работает.
- роуминг. Иногда это нужно. И нужно внезапно. В роуминге входящие внезапно платные. А вот слотов под сим-карты — не бесконечное количество, а местная симка — нужна.
Справедливые замечания (про телефон). Поэтому на сайте можно запросить восстановление доступа по данному телефону (приходит на email, дополнительно указывается при регистрации) и далее через ЛК установить заново пин коды телефона(ов).
В описанном мною случае, есть важный нюанс, клиент оплатил лицензию на программу и вспомнить доступ важнее ему, а не нам. Нам важнее, чтобы программу не копировали свободно на разные ПК.
Ну, тут есть один момент. Телефон, мыло, логин-пароль - это все хорошо. но вы же не запрашиваете их на каждый запрос, на каждое открытие странички, скачивание ресурса и тд. Поэтому если ваше приложение реализует постоянные обмены с сервером после авторизации - вы наверняка используете что-то из перечисленного в статье. Это первый момент.
Второй момент - номер телефона (особенно в связке с email) - это ПД. Что несколько усложняет честную реализацию такой аутентификации
Как ты реализуешь аутентификацию, приятель?