jwt-documentation

Полная документация по JSON Web Token (JWT)

Содержание

  1. Введение
  2. Что такое JWT?
  3. Структура JWT
  4. Стандарты и спецификации
  5. Принцип работы JWT
  6. Использование JWT
  7. Преимущества JWT
  8. Недостатки и ограничения
  9. Безопасность JWT
  10. Примеры использования JWT
  11. Хранение JWT
  12. Обновление и отзыв JWT
  13. Лучшие практики при использовании JWT
  14. Заключение

Введение

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

Что такое JWT?

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

Структура JWT

JWT состоит из трех частей, разделенных точками (.):

  1. Header (Заголовок): Содержит информацию о типе токена и алгоритме подписи.
  2. Payload (Полезная нагрузка): Содержит утверждения (claims) — данные, которые необходимо передать.
  3. Signature (Подпись): Обеспечивает целостность токена, позволяя проверять, что он не был изменен.

Пример структуры JWT:

xxxxx.yyyyy.zzzzz

Детальный пример:

1. Header

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

2. Payload

{
  "sub": "1234567890",
  "name": "Иван Иванов",
  "admin": true,
  "iat": 1516239022
}

3. Signature

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

Полный JWT:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6
IkpvaG4gSmltYW5vdiIsImFkbWluIjp0cnVl
LCJpYXQiOjE1MTYyMzkwMjJ9.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Стандарты и спецификации

Принцип работы JWT

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

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

Аутентификация

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

Авторизация

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

Передача информации

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

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

Недостатки и ограничения

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

Рекомендации по безопасности:

  1. Используйте HTTPS: Всегда передавайте JWT по защищенному каналу, чтобы предотвратить перехват токена.
  2. Секретный ключ: Храните секретный ключ в безопасности и регулярно его обновляйте.
  3. Алгоритмы: Используйте надежные алгоритмы подписи, такие как HS256 или RS256. Избегайте использования none в качестве алгоритма.
  4. Срок действия: Устанавливайте короткий срок действия (exp) для токенов, чтобы минимизировать риск их использования после компрометации.
  5. Валидация: Всегда проверяйте подпись и срок действия токена на сервере.
  6. Отзыв токенов: Реализуйте механизмы отзыва токенов, если это необходимо (например, при выходе пользователя из системы).

Уязвимости и как их избежать:

Примеры использования JWT

Python с библиотекой PyJWT

Установка библиотеки

pip install PyJWT

Пример создания и проверки JWT

import jwt
import datetime

# Секретный ключ для подписания токена
SECRET_KEY = 'your-secret-key'

# Создание токена
def create_token(user_id, username):
    payload = {
        'user_id': user_id,
        'username': username,
        'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=1),  # Токен действителен 1 час
        'iat': datetime.datetime.utcnow(),
        'nbf': datetime.datetime.utcnow()
    }
    token = jwt.encode(payload, SECRET_KEY, algorithm='HS256')
    return token

# Проверка токена
def verify_token(token):
    try:
        decoded = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
        return decoded
    except jwt.ExpiredSignatureError:
        print("Токен истек")
    except jwt.InvalidTokenError:
        print("Неверный токен")

# Пример использования
if __name__ == "__main__":
    token = create_token(123, 'akrom')
    print(f"JWT токен: {token}")

    decoded_payload = verify_token(token)
    if decoded_payload:
        print(f"Декодированные данные: {decoded_payload}")

JavaScript с библиотекой jsonwebtoken

Установка библиотеки

npm install jsonwebtoken

Пример создания и проверки JWT

const jwt = require('jsonwebtoken');

// Секретный ключ для подписания токена
const SECRET_KEY = 'your-secret-key';

// Создание токена
function createToken(userId, username) {
    const payload = {
        user_id: userId,
        username: username
    };
    const options = {
        expiresIn: '1h'
    };
    const token = jwt.sign(payload, SECRET_KEY, options);
    return token;
}

// Проверка токена
function verifyToken(token) {
    try {
        const decoded = jwt.verify(token, SECRET_KEY);
        return decoded;
    } catch (err) {
        if (err.name === 'TokenExpiredError') {
            console.log('Токен истек');
        } else {
            console.log('Неверный токен');
        }
    }
}

// Пример использования
const token = createToken(123, 'akrom');
console.log(`JWT токен: ${token}`);

const decoded = verifyToken(token);
if (decoded) {
    console.log('Декодированные данные:', decoded);
}

Java с библиотекой jjwt

Установка библиотеки

Добавьте зависимость в ваш pom.xml для Maven:

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.11.5</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.11.5</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId> <!-- или jjwt-gson, если вы предпочитаете Gson -->
    <version>0.11.5</version>
    <scope>runtime</scope>
</dependency>

Пример создания и проверки JWT

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.SignatureException;
import java.util.Date;

public class JwtExample {
    // Секретный ключ для подписания токена
    private static final String SECRET_KEY = "your-secret-key";

    // Создание токена
    public static String createToken(long userId, String username) {
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        Date exp = new Date(nowMillis + 3600000); // 1 час

        return Jwts.builder()
                .setSubject(Long.toString(userId))
                .claim("username", username)
                .setIssuedAt(now)
                .setExpiration(exp)
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();
    }

    // Проверка токена
    public static Claims verifyToken(String token) {
        try {
            Claims claims = Jwts.parser()
                                .setSigningKey(SECRET_KEY)
                                .parseClaimsJws(token)
                                .getBody();
            return claims;
        } catch (ExpiredJwtException e) {
            System.out.println("Токен истек");
        } catch (SignatureException e) {
            System.out.println("Неверная подпись токена");
        } catch (Exception e) {
            System.out.println("Неверный токен");
        }
        return null;
    }

    // Пример использования
    public static void main(String[] args) {
        String token = createToken(123, "akrom");
        System.out.println("JWT токен: " + token);

        Claims claims = verifyToken(token);
        if (claims != null) {
            System.out.println("Декодированные данные:");
            System.out.println("user_id: " + claims.getSubject());
            System.out.println("username: " + claims.get("username"));
            System.out.println("exp: " + claims.getExpiration());
        }
    }
}

Хранение JWT

JWT можно хранить на клиентской стороне различными способами. Выбор метода хранения влияет на безопасность приложения.

Варианты хранения:

  1. Local Storage:
    • Преимущества: Простота использования, доступен через JavaScript.
    • Недостатки: Уязвим к XSS-атакам, так как JavaScript может получить доступ к токену.
  2. Session Storage:
    • Преимущества: Данные удаляются при закрытии вкладки браузера.
    • Недостатки: Тоже уязвим к XSS-атакам.
  3. HttpOnly Cookies:
    • Преимущества: Недоступны через JavaScript, что защищает от XSS-атак.
    • Недостатки: Уязвимы к CSRF-атакам, если не применять дополнительные меры.

Рекомендации:

Обновление и отзыв JWT

Обновление токенов (Refresh Tokens)

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

  1. Access Token: Короткоживущий токен для доступа к ресурсам.
  2. Refresh Token: Долгоживущий токен для получения новых Access Token.

Пример потока обновления токенов:

  1. Пользователь аутентифицируется и получает Access Token и Refresh Token.
  2. Когда Access Token истекает, клиент использует Refresh Token для запроса нового Access Token.
  3. Сервер проверяет Refresh Token и, если он валиден, выдает новый Access Token.

Отзыв токенов

JWT, будучи самодостаточными, сложно отзывать без дополнительной инфраструктуры. Возможные подходы:

  1. Черный список (Blacklist): Хранение списка отозванных токенов на сервере и проверка каждого токена против этого списка.
  2. Использование коротких сроков действия: Уменьшение времени, в течение которого украденный токен может быть использован.
  3. Хранение состояния (Stateful JWT): Сохранение состояния токенов на сервере, что противоречит основному преимуществу JWT, но позволяет контролировать их отзыв.

Лучшие практики при использовании JWT

  1. Минимизируйте информацию в Payload: Включайте только необходимую информацию, чтобы уменьшить размер токена и снизить риски утечки данных.
  2. Используйте надежные алгоритмы подписи: Предпочитайте HS256, RS256 и другие проверенные алгоритмы.
  3. Устанавливайте срок действия токена: Определите разумный срок действия (exp) для ограничения времени использования токена.
  4. Обновляйте секретные ключи: Регулярно меняйте секретные ключи и обеспечивайте их безопасное хранение.
  5. Внедрите контроль доступа на основе ролей (RBAC): Управляйте доступом пользователей к ресурсам на основе их ролей, включенных в JWT.
  6. Защитите от CSRF-атак: Если используете куки для хранения токенов, внедрите защиту от CSRF, например, с помощью CSRF-токенов.
  7. Проверяйте все утверждения: Убедитесь, что все важные утверждения (например, exp, iss, aud) проверяются на сервере.
  8. Используйте HTTPS: Всегда передавайте токены по защищенному каналу.
  9. Логируйте подозрительные действия: Отслеживайте попытки несанкционированного доступа и другие подозрительные действия.

Заключение

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

Дополнительные ресурсы

Часто задаваемые вопросы (FAQ)

1. Чем отличается JWT от сессий?

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

2. Можно ли шифровать JWT?

Да, JWT можно не только подписывать, но и шифровать, используя спецификацию JWE (JSON Web Encryption). Это позволяет скрыть содержимое токена от посторонних глаз. Однако в большинстве случаев достаточно подписанного JWT (JWS).

3. Как защититься от атак CSRF при использовании JWT в куки?

Используйте двойную отправку куки (Double Submit Cookie) или включите CSRF-токены, которые проверяются на сервере при каждом запросе. Также рассмотрите использование SameSite атрибута для куки.

4. Можно ли использовать JWT для аутентификации в мобильных приложениях?

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

5. Что делать, если секретный ключ был скомпрометирован?

Немедленно обновите секретный ключ и отзовите все текущие токены. Это может потребовать реализации механизма отзыва токенов или использования коротких сроков действия токенов.