JWT, where to store JWT, HMAC, RSA - Max-Starling/Notes GitHub Wiki

JSON Web Token

JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with HMAC algorithm) or a public/private key pair using RSA.

JWT это открытый стандарт, который представляет собой компактный и автономный способ безопасной передачи информации между сторонами как JSON-объект. Эта информация может быть подтверждена и нажёжна, потому что есть цифровая подпись. JWT можно подписывать используя секрет (HMAC алгоритм) или используя public/private пару ключей RSA.

HMAC – Hash-based Message Authentication Code

HMAC - это особый формат MAC, содержащий криптографическую хэш-фукнцию и секретный криптографический ключ. Он может использоваться для одновременной проверки целостности данных и аутентификации сообщения (как при любом MAC). Любая криптографическая функция, например SHA256 или SHA3, может быть использована для вычислений. Криптографическая сила HMAC зависиот от криптографической силы базовой хэш-функции, размера её хэш-вывода и размера, качества ключа. HMAC использует два прохода хэш-вычисления. Секретный ключ сначала используется для получения двух ключей - внутреннего и внешнего. Первый проход алгоритма создаёт внутренний хэш, полученный из сообщения и внутреннего ключа. Второй проход даёт окончательный код HMAC, полученный из внутреннего хэш-результата и внешнего ключа, что обеспечивает лучшую устойчивость к атакам расширения длины. HMAC не шифрует сообщение. Вместо этого сообщение (зашифрованное или нет) должно быть отправлено вместе с хэшем HMAC. Стороны с секретным ключом снова выдадут сообщение, и если оно будет таким же, то полученные и вычисленные хэши будут совпадать.

RSA – Rivest-Shamir-Adleman (фамилии создателей)

Пользователь RSA создаёт и затем публикует public ключ основанный на двух больших простых числах вместе с вспомогательными значениями. Простые числа должны содержать секрет. Они перемножаются между собой, таким обазом создавая public ключ. Кто угодно может использовать публичный ключ, чтобы зашифровать сообщение. Если public ключ достаточно большой, то только кто-то знающий заданные простые числа имеет возможность расшифровать сообщение. Взлом RSA-шифрования известен как PSA problem. Для RSA ключей больших размеров (более 1024 бит) не было найдено эффективного метода разрешения проблемы.

Свойства JWT

  • Компатность (compact). Объясняется размером. Токен может быть выслан в query (запрос get), в body (запрос post) или же внутри headers.
  • Автономность (self-contained). Payload содержит всю необходимую информацию о пользователе, чтобы избежать дополнительных запросов к БД.

Когда нужен JWT

  • Аутентификация (authentication). Самый распространённый сценарий использования. Когда пользователь авторизировался, каждый последующий запрос содержит JWT, позволяющий пользователю пользователю получать доступ к роутам, сервисам и русурсам, который разрешены токеном.
  • Обмен информацией (information exchange). JWT – хороший способ безопастной передачи информации между сторонами, потому что токены могут быть подписаны.

Структура JWT

JWT имеет три части, разделённые точками (xxx.yyy.zzz):

  • Header
  • Payload
  • Signature

Header обычно состоит из двух частей:

  • typ - тип токена
  • alg - хэширующий алгоритм

Payload содержит требования (claims). Claims - это утверждения о сущности (обычно о пользователе) и дополнительные мета-данные. Есть три типа требований:

  • Reserved claims. Это множество предопределённых требований, которые не являются обязательными, но рекомендованы. Их цель: обеспечить набор полезных, повместимых требований. Одни из них: iss - issuer, exp - expiration time, sub - subject, aud - audience.
  • Public claims. Могут быть определены по желанию теми, кто использует JWT. Но во избежание коллизий они должны быть определены в реестре веб-токенов IANA JSON или быть определены как URI, который содержит пространство с устройчивостью к конфликтам.
  • Private claims. Это пользовательские требования, созданные для обмена информацией между сторонами, которые согласны их использовать.

Чтобы создать Signature (подпись), нужно совместить: зашифрованный header + зашифрованный payload + secret + хэширующий алгоритм из header + sign.
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret);
Signature используется, чтобы подтвердить, что отправитель JWT является тем, кто он говорит, и чтобы сообщение не было изменено.

В итоге имеем три Base64 строки, разделённые точками. Эти строки можно легко передать в HTML и HTTP среды благодаря компактности.

Как работает JWT

В случае аутентификации, когда пользователь успешно авторизировался используя его полномочия (credentials), JWT возвращается и сохраняется локально (обычно в localStorage, но иногда и в cookies). Это используется вместо традиционного подхода создания сессий на сервере и возвращения cookie.

Когда пользователь хочет получить доступ к защищённому маршруту (protected route), высылается JWT (обычно в Autrhorization header используя Bearer схему):
Authorization: Bearer <token>

Это механизм аутентификации без состояния (stateless), так как состояние пользователя никогда не сохраняется в память сервера. Защищённые роуты сервера будут проверять валидность JWT из Authorization header. Если всё хорошо, то у пользователя будет доступ к ресурсам. Так как JWT автономны, вся необходимая информация уже содержится в них, что позволяет не обращаться лишний раз к базе данных.

Таким образом неважно, какие домены обслуживаются API, поскольку Cross-Origin Resource Sharing (CORS) не будет проблемой, так как не используются файлы cookie.

Сравнение с SWT, SAML

Так как JSON менее подробный по сравнению с XML, то когда он закодирован его размер так же мельше, что делает JWT компактнее, чем Security Assertion Markup Language Tokens (SAML).

По сравнению c Simple Web Token (SWT) JWT является более безопастным, так как SWT может быть только симметрично подписан общим секретом используя HMAC алгоритм. В то время как JWT и SAML могут также использовать public/private ключи. Однако и тут JSON проще подписать, чем XML.

Парсеры JSON широко распространены во многих языках программирования, потому что их можно просто перевести (map) в обычные объекты в то время, как XML не имеет natural document-to-object mapping.

JWT в Auth0

В Auth0 выдаётся JWT в результате процесса аутентификации. Когда пользователь входит в систему с использованием Auth0, создаётся JWT, подписывается (с помощью HMAC/RSA) и отправляется пользователю. Затем этот токен будет использоваться для аутентификации и авторизации с помощью API-интерфейсов, которые предоставят доступ к их защищённым маршрутам и ресурам.

https://jwt.io/
https://blog.usejournal.com/sessionless-authentication-withe-jwts-with-node-express-passport-js-69b059e4b22c
https://logrocket.com/blog/jwt-authentication-best-practices/
https://auth0.com/docs/security/store-tokens
https://www.rdegges.com/2018/please-stop-using-local-storage/
https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-html5-web-storage
https://stormpath.com/blog/jwt-the-right-way
https://developer.okta.com/blog/2017/08/17/why-jwts-suck-as-session-tokens
https://stackoverflow.com/questions/34817617/should-jwt-be-stored-in-localstorage-or-cookie
https://stackoverflow.com/questions/27067251/where-to-store-jwt-in-browser-how-to-protect-against-csrf?noredirect=1&lq=1

⚠️ **GitHub.com Fallback** ⚠️