JWT токены

JWT (JSON Web Token) — это открытый стандарт (RFC 7519), который определяет компактный и самодостаточный способ безопасной передачи информации между сторонами как объект JSON. Эта информация может быть проверена и доверена, поскольку она обычно подписана с использованием секретного ключа или публичного/приватного ключа.

JWT состоит из трех частей: заголовка (header), полезной нагрузки (payload) и подписи (signature). Эти части разделены точками (.) и представляют собой строку. Пример JWT:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Заголовок (Header)

Заголовок JWT обычно состоит из двух частей: типа токена, который всегда равен “JWT”, и алгоритма подписи, который используется, например, HMAC SHA256 или RSA.

Пример заголовка в JSON-формате:

{
  "alg": "HS256",
  "typ": "JWT"
}

Заголовок затем кодируется в Base64Url.

Полезная нагрузка (Payload)

Полезная нагрузка — это основная информация, которую передает токен. Она может содержать как публичные, так и приватные данные, но важно помнить, что полезная нагрузка не зашифрована, а только кодируется, что делает ее уязвимой для несанкционированного доступа.

Основные компоненты полезной нагрузки:

  • Claims (утверждения): данные, которые передаются в JWT. Они бывают трех типов:

    • Registered claims: стандартные утверждения, такие как iss (issuer), exp (expiration time), sub (subject), aud (audience) и другие.
    • Public claims: могут быть определены любым пользователем и не конфликтовать с зарезервированными утверждениями.
    • Private claims: определяются и используются между сторонними участниками, и не стандартизированы.

Пример полезной нагрузки в JSON-формате:

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

Полезная нагрузка также кодируется в Base64Url.

Подпись (Signature)

Чтобы создать подпись, необходимо взять закодированный заголовок и полезную нагрузку, объединить их с помощью точки и затем подписать с использованием указанного в заголовке алгоритма и секретного ключа (или приватного ключа для алгоритмов RSA или ECDSA). Подпись гарантирует, что токен не был изменен после его подписания.

Пример алгоритма создания подписи:

HMACSHA256(
  base64UrlEncode(header) + "." + base64UrlEncode(payload),
  secret)

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

Преимущества JWT

  1. Самодостаточность: JWT несет в себе всю информацию, необходимую для аутентификации или авторизации. Это делает его удобным для использования в распределенных системах и микросервисах.
  2. Компактность: Токен JWT занимает малый объем и может быть передан через URL, параметры запроса, заголовки HTTP и даже через cookies.
  3. Удобство работы с RESTful API: JWT часто используется для аутентификации в REST API, так как токен передается в HTTP-заголовках в каждом запросе.
  4. Поддержка разных алгоритмов подписи: Возможность выбора между симметричными (HMAC) и асимметричными (RSA, ECDSA) алгоритмами делает JWT гибким и безопасным.

Применение JWT

JWT применяется в системах аутентификации и авторизации для безопасной передачи пользовательской информации. Пример использования — это создание токенов доступа и обновления для пользователей, которые могут быть переданы в заголовке HTTP-запроса.

Аутентификация с использованием JWT

  1. Пользователь отправляет запрос с данными для входа (например, логин и пароль).
  2. Сервер проверяет данные и генерирует JWT — если аутентификация успешна, сервер создает JWT с необходимыми данными и подписывает его с использованием секретного ключа.
  3. JWT передается клиенту (обычно в ответе на запрос).
  4. Клиент хранит JWT в памяти или в cookie.
  5. Клиент отправляет JWT серверу в заголовке Authorization в последующих запросах, чтобы получить доступ к защищенным ресурсам.

Пример заголовка с JWT в запросе:

Authorization: Bearer <jwt-token>
  1. Сервер проверяет подпись токена и извлекает данные для аутентификации/авторизации.

Авторизация с использованием JWT

JWT может содержать информацию о правах пользователя, например, роль или права доступа. После аутентификации пользователь получает токен, который может быть использован для проверки доступа к защищенным ресурсам. В этом случае сервер проверяет не только подпись, но и содержимое токена (например, роль пользователя).

Безопасность JWT

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

  1. Хранение токена. Важно безопасно хранить JWT. Не рекомендуется хранить токен в локальном хранилище, так как это может подвергнуть его риску кражи через XSS-уязвимости. Вместо этого предпочтительнее использовать cookies с флагом HttpOnly и Secure.
  2. Срок действия токена. Токены могут быть с истекающим сроком действия. Чтобы минимизировать риски, следует использовать короткие сроки действия и внедрить механизм обновления токенов (refresh tokens).
  3. Ротация ключей. Если секретный ключ или приватный ключ скомпрометирован, следует немедленно сменить ключи и аннулировать старые токены.

Пример работы с JWT в JavaScript

Пример использования JWT в Node.js с библиотекой jsonwebtoken:

const jwt = require('jsonwebtoken');
const secretKey = 'your-secret-key';

// Создание токена
const payload = { userId: 123, role: 'admin' };
const token = jwt.sign(payload, secretKey, { expiresIn: '1h' });
console.log(token);

// Верификация токена
jwt.verify(token, secretKey, (err, decoded) => {
  if (err) {
    console.error('Invalid token');
  } else {
    console.log('Decoded payload:', decoded);
  }
});

Использование Refresh Tokens

JWT имеет ограниченный срок действия, что важно для безопасности. Однако это также создает проблему с удобством использования. Один из способов решения этой проблемы — использовать систему токенов обновления (refresh tokens).

Алгоритм работы с refresh токенами:

  1. Пользователь аутентифицируется с использованием логина и пароля.

  2. Сервер генерирует два токена:

    • JWT (access token) с коротким сроком действия.
    • Refresh token с более длительным сроком действия.
  3. JWT передается клиенту, а refresh token сохраняется на сервере.

  4. Когда срок действия JWT истекает, клиент отправляет refresh token на сервер для получения нового access token.

  5. Сервер генерирует новый access token и отправляет его клиенту.

Этот механизм помогает поддерживать безопасность и удобство работы с долгосрочными сессиями.

Вывод

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