markdown Протокены,JSON Web Tokens(JWT),аутентификациюиавторизацию
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了markdown Протокены,JSON Web Tokens(JWT),аутентификациюиавторизацию相关的知识,希望对你有一定的参考价值。
# Token-Based Authentication(JWT)
## Preconditions:
В данной заметке рассматривается работа JWT с __симметичным__ алгоритмом шифрования (HS256/HS384/HS512)
## Основы:
__Аутентификация(authentication, от греч. αὐθεντικός [authentikos] – реальный, подлинный; от αὐθέντης [authentes] – автор)__ - это процесс проверки учётных данных пользователя (логин/пароль). Проверка подлинности пользователя путём сравнения введённого им пароля с паролем, сохранённым в базе данных пользователей;
__Авторизация(authorization — разрешение, уполномочивание)__ - это проверка прав пользователя на доступ к определенным ресурсам.
Например после аутентификации юзер _**sasha**_ получает право обращатся и получать от ресурса __"super.com/vip"__ некие данные. Во время обращения юзера _**sasha**_ к ресурсу __vip__ система авторизации проверит имеет ли право юзер обращатся к этому ресурсу (проще говоря переходить по неким разрешенным ссылкам)
1. Юзер c емайлом _**sasha_gmail.com**_ успешно прошел аутентификацию
2. Сервер посмотрел в БД какая роль у юзера
3. Сервер сгенерил юзеру токен с указанной ролью
4. Юзер заходит на некий ресурс
5. Сервер смотрит на права(роль) юзера в токене и соотвественно пропускает или отсекает запрос
Собственно п.5 и есть процесс __авторизации__.
*Дабы не путатся с понятиями __Authentication/Authorization__ можно использовать псевдонимы __checkPassword/checkAccess__(я так сделал в своей API)*
__JSON Web Token (JWT)__ — содержит три блока, разделенных точками: заголовок(__header__), набор полей (__payload__) и __сигнатуру__. Первые два блока представлены в JSON-формате и дополнительно закодированы в формат base64. Набор полей содержит произвольные пары имя/значения, притом стандарт JWT определяет несколько зарезервированных имен (iss, aud, exp и другие). Сигнатура может генерироваться при помощи и симметричных алгоритмов шифрования, и асимметричных. Кроме того, существует отдельный стандарт, отписывающий формат зашифрованного JWT-токена.
Пример подписанного JWT токена (после декодирования 1 и 2 блоков):
```
{ «alg»: «HS256», «typ»: «JWT» }.{ «iss»: «auth.myservice.com», «aud»: «myservice.com», «exp»: «1435937883», «userName»: «John Smith», «userRole»: «Admin» }.S9Zs/8/uEGGTVVtLggFTizCsMtwOJnRhjaQ2BMUQhcY
```
__Токены__ предоставляют собой средство __авторизации__ для каждого запроса от клиента к серверу. Токены(и соотвественно сигнатура токена) генерируются на сервере основываясь на секретном ключе(который хранится на сервере) и __payload'e__. Токен в итоге хранится на клиенте и используется при необходимости __авторизации__ како-го либо запроса. Такое решение отлично подходит при разаработке SPA.
При попытке хакером подменить данные в __header'ре__ или __payload'е__, токен cтанет не валидным, поскольку сигнатура не будет соответствовать изначальным значениям. А возможность сгенерировать новую сигнатуру у хакера отсутствует, поскольку секретный ключ для зашифровки лежит на сервере.
__access token__ - используется для __авторизации запросов__ и хранения дополнительной информации о пользователе (аля __user_id__, __user_role__ или еще что либо, эту информацию также называет __payload__)
__refresh token__ - выдается сервером по результам успешной аутентификации и используется для получения нового __access token'a__ и обновления __refresh token'a__
Каждый токен имеет свой срок жизни, например __access__: 30мин, __refresh__: 60дней
__Поскольку токены это не зашифрованная информация крайне не рекомендуется хранить в них такую информацию как пароли__
## Схема создания/использования токенов:
1. Пользователь логинится в приложении, передавая логин/пароль на сервер
2. Сервер проверят подлинность логина/пароля, в случае удачи генерирует и отправляет клиенту два токена(__access, refresh__) и время смерти __access token'а__ (`expires_in` поле, в __unix timestamp__). Также в __payload__ __refresh token'a__ добавляется __user_id__
```
"accessToken": "...",
"refreshToken": "...",
"expires_in": 1502305985425
```
3. Клиент сохраняет токены и время смерти __access token'а__, используя __access token__ для последующей авторизации запросов
4. Перед каждым запросом клиент предварительно проверяет время жизни __access token'а__ (из `expires_in`)и если оно истекло использует __refresh token__ чтобы обновить __ОБА__ токена и продолжает использовать новый __access token__
__Ключевой момент__ что в момент рефреша то есть обновления __access token'a__ обновляются __ОБА__ токена. Но как же __refresh token__ может сам себя обновить, он ведь создается только после успешной аунтефикации ? __refresh token__ в момент рефреша сравнивает себя с тем __refresh token'ом__ который лежит в БД и вслучае успеха, а также если у него не истек срок, система рефрешит токены. __Внимание__ при обновлении __refresh token__ продливается также и его срок жизни.
Возникает вопрос зачем __refresh token'y__ срок жизни, если он обновляется каждый раз при обновлении __access token'a__ ? Это сделано на случай если юзер будет в офлайне более 60 дней, тогда прийдется заново вбить логин/пароль.
С такой схемой юзер сможет быть залогинен только на одном устройстве. Тоесть в любом случае при смене устройства ему придется логинится заново.
## Схема рефреша токенов:
1. Клиент проверяет перед запросом не истекло ли время жизни __access token'на__
2. И если истекло клиент отправляет на `auth/refresh-token` URL __refresh token__
3. Сервер берет __user_id__ из __payload'a__ __refresh token'a__ по нему ищет в БД запись данного юзера и достает из него __refresh token__
4. Сравнивает __refresh token__ клиента с __refresh token'ом__ найденным в БД
5. Проверяет валидность и срок действия __refresh token'а__
6. В случае успеха сервер:
1. Пересоздает и записывает __refresh token__ в БД
2. Создает новый __access token__
3. Отправляет оба токена и новый `expires_in` __access token'а__ клиенту
7. Клиент повторяет запрос к API c новым __access token'ом__
## В случае кражи(обоих токенов):
1. Хакер воспользовался __access token'ом__
2. Закончилось время жизни __access token'на__
3. __Клиент хакера__ отправляет __refresh token__
4. Хакер получает новую пару токенов
5. На сервере создается новая пара токенов(__"от хакера"__)
5. Юзер пробует зайти на сервер >> обнаруживается что токены невалидны
6. Сервер перенаправляет юзера на форму аутентификации
7. Юзер вводит логин/пароль
8. Создается новая пара токенов >> пара токенов __"от хакера"__ становится не валидна
__Проблема:__ Поскольку __refresh token__ продлевает срок своей жизни каждый раз при рефреше токенов >> хакер пользуется токенами до тех пор пока юзер не залогинится.
### В случае паранои:
- хранить список валидных IP, deviceID, fingerprint браузера, генерить рандомный randomUserID
- дополнительно шифровать токены (в nodejs например crypt >> aes-256)
### Чтиво:
- https://tools.ietf.org/html/rfc6749
- https://jwt.io/introduction/
- https://auth0.com/blog/using-json-web-tokens-as-api-keys/
- https://auth0.com/blog/cookies-vs-tokens-definitive-guide/
- https://auth0.com/blog/ten-things-you-should-know-about-tokens-and-cookies/
- https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/
- https://habrahabr.ru/company/dataart/blog/262817/
- https://scotch.io/tutorials/authenticate-a-node-js-api-with-json-web-tokens
- Заметка базируется на: https://habrahabr.ru/company/Voximplant/blog/323160/
- https://www.youtube.com/watch?v=Ngh3KZcGNaU
- https://www.youtube.com/playlist?list=PLvTBThJr861y60LQrUGpJNPu3Nt2EeQsP
以上是关于markdown Протокены,JSON Web Tokens(JWT),аутентификациюиавторизацию的主要内容,如果未能解决你的问题,请参考以下文章
markdown Протокены,JSON Web Tokens(JWT),аутентификациюиавторизацию
markdown Приемыпроектированияjavascript
markdown Протокены,JSON Web Tokens(JWT),аутентификациюиавторизацию。基于令牌的身份验证
markdown Определитькакиеещеможноустановитьпакетыphp