Payload и header в JWT: полное руководство по структуре и защите
Перейти

Payload и header в JWT: полное руководство по структуре и защите

#Веб-разработка  #Веб-безопасность  #Кибербезопасность  
Пройдите тест, узнайте какой профессии подходите
Сколько вам лет
0%
До 18
От 18 до 24
От 25 до 34
От 35 до 44
От 45 до 49
От 50 до 54
Больше 55

Для кого эта статья:

  • Опытные веб-разработчики
  • Специалисты по информационной безопасности
  • Архитекторы программного обеспечения и систем

JWT (JSON Web Token) стал стандартом де-факто для передачи заявлений между сервисами в мире веб-разработки. Однако за кажущейся простотой скрывается сложная архитектура и множество потенциальных уязвимостей, о которых не подозревают даже опытные разработчики. Что происходит внутри этих токенов? Каждый JWT хранит критически важную информацию в payload и метаданные в header, но правильная структуризация и защита этих элементов — это тонкое искусство, требующее глубоких технических знаний. В этом руководстве мы препарируем JWT до атомов, рассмотрим каждый элемент структуры и раскроем приёмы, которые защитят ваши приложения от распространённых атак. 🔐

Архитектура JWT: структура header, payload и подписи

JWT представляет собой строку, состоящую из трёх частей, разделённых точками: header.payload.signature. Эта строка кодируется в формате Base64URL, что делает её безопасной для передачи в URL-параметрах и HTTP-заголовках.

Структура JWT напоминает сэндвич, где каждый слой выполняет определённую функцию:

  • Header (заголовок) — метаданные о типе токена и используемом алгоритме подписи
  • Payload (полезная нагрузка) — набор утверждений (claims) о пользователе или других сущностях
  • Signature (подпись) — криптографическая подпись, гарантирующая целостность первых двух частей

Рассмотрим пример JWT-токена:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

При декодировании первой части (header) получаем JSON-объект:

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

Вторая часть (payload) после декодирования даёт нам:

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

Третья часть — это HMACSHA256 подпись, созданная по формуле:

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

Важно понимать, что header и payload в JWT не зашифрованы, а только закодированы с помощью Base64URL. Любой, кто перехватит токен, может декодировать и прочитать эти части. Безопасность обеспечивается только подписью, которая гарантирует, что токен не был изменён.

Алексей, руководитель отдела безопасности

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

Мы провели срочный аудит и перепроектировали архитектуру: теперь в payload хранятся только идентификаторы и минимум необходимой информации, а чувствительные данные запрашиваются отдельно по защищённым каналам. Также внедрили шифрование (JWE) для особо важных токенов. Этот случай стал отличным уроком для всей команды о том, как важно понимать внутреннюю структуру используемых технологий.

Компонент JWT Описание Уровень защиты Рекомендации
Header Метаданные о токене Не защищён (только кодирование Base64URL) Не включать чувствительную информацию
Payload Полезная нагрузка с claims Не защищён (только кодирование Base64URL) Минимизировать объём и чувствительность данных
Signature Криптографическая подпись Защищён (криптографические алгоритмы) Использовать надёжные алгоритмы и хранить секрет в безопасности
Пошаговый план для смены профессии

Поля JWT header: алгоритмы и типы токенов

Header JWT содержит информацию о том, как должен обрабатываться токен. Обязательными полями являются:

  • alg (algorithm) — используемый алгоритм подписи или шифрования
  • typ (type) — тип токена, обычно "JWT"

Кроме этих базовых полей, header может включать дополнительные параметры в зависимости от конкретных требований:

  • kid (Key ID) — идентификатор ключа, используемого для подписи
  • x5c (X.509 Certificate Chain) — цепочка сертификатов X.509
  • jku (JWK Set URL) — URL для получения набора JSON Web Keys
  • cty (Content Type) — тип содержимого вложенного объекта

Алгоритмы подписи JWT делятся на несколько категорий:

Категория Алгоритмы Особенности Рекомендации по использованию
HMAC HS256, HS384, HS512 Используют симметричный ключ Для систем с одним сервером валидации
RSA RS256, RS384, RS512 Используют пару ключей (приватный/публичный) Для распределённых систем, где токены создаются и проверяются разными сервисами
ECDSA ES256, ES384, ES512 Эллиптические кривые, меньшие ключи при той же безопасности Для систем с ограничениями производительности или размера токена
EdDSA EdDSA Современный алгоритм цифровой подписи Edwards-curve Для новых систем, требующих высокой безопасности
Отсутствие подписи none Токен без подписи Никогда не использовать в продакшене

При выборе алгоритма подписи необходимо учитывать несколько факторов:

  1. Безопасность — современные алгоритмы предпочтительнее устаревших.
  2. Производительность — HMAC быстрее RSA, а ECDSA быстрее при той же безопасности.
  3. Размер токена — подписи RSA длиннее, чем ECDSA.
  4. Архитектура системы — для микросервисов предпочтительны асимметричные алгоритмы.

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

{
"alg": "RS256",
"typ": "JWT",
"kid": "2021-12-key-1"
}

Обратите внимание на поле kid — оно особенно полезно при ротации ключей, позволяя системе определить, какой именно ключ использовать для проверки подписи. 🔑

Payload JWT: стандартные и кастомные claims

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

  • Registered Claims — предопределенные стандартом JWT
  • Public Claims — определяемые пользователями, но зарегистрированные в IANA JSON Web Token Claims Registry
  • Private Claims — специфические для конкретного приложения, по соглашению между участниками

Стандартные (Registered) claims имеют трехбуквенные идентификаторы и определены в спецификации RFC 7519:

  • iss (issuer) — идентификатор стороны, создавшей токен
  • sub (subject) — идентификатор субъекта токена (обычно пользователя)
  • aud (audience) — получатель(и) токена
  • exp (expiration time) — время истечения срока действия токена
  • nbf (not before) — время, до которого токен не должен приниматься
  • iat (issued at) — время создания токена
  • jti (JWT ID) — уникальный идентификатор токена

Пример payload с стандартными claims:

{
"iss": "https://auth.example.com",
"sub": "user123",
"aud": "https://api.example.com",
"exp": 1617054000,
"iat": 1616967600,
"jti": "756E69717565206964656E746966696572"
}

Кастомные (Private) claims могут содержать любую информацию, необходимую для конкретного приложения. Например:

{
"user_id": 123456,
"name": "Александр",
"role": "admin",
"permissions": ["read", "write", "delete"],
"department": "IT",
"office_location": "Moscow"
}

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

  • Пароли или хеши паролей
  • Секретные ключи API
  • Конфиденциальные личные данные (номера паспортов, карт и т.д.)
  • Информацию, которая может часто меняться

Для оптимизации размера токена используйте короткие имена claims и минимизируйте включаемые данные. Помните, что JWT передаётся с каждым запросом, поэтому его размер влияет на производительность.

Если требуется включение чувствительной информации, рассмотрите использование JWT Encryption (JWE) вместо или в дополнение к подписанному JWT (JWS). 📦

Критические уязвимости JWT и методы их устранения

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

  1. Атака с алгоритмом None

Суть атаки: злоумышленник изменяет алгоритм в header с, например, HS256 на "none", удаляет подпись и пытается использовать модифицированный токен. Если сервер неправильно реализован и принимает токены без подписи, это позволяет создать действительный токен с любым содержимым.

Защита:

  • Явно отклоняйте токены с алгоритмом "none".
  • Используйте библиотеки, которые правильно проверяют алгоритм подписи.
  • Белый список разрешенных алгоритмов на сервере.
  1. Атака с заменой алгоритма

Суть атаки: злоумышленник меняет алгоритм с асимметричного (например, RS256) на симметричный (например, HS256). Если сервер использует публичный ключ RSA как секрет для HMAC, это позволяет подделать токен.

Защита:

  • Жестко задавайте ожидаемый алгоритм при проверке.
  • Используйте разные переменные для хранения симметричных и асимметричных ключей.
  • Не полагайтесь на алгоритм, указанный в токене.
  1. Слабый секретный ключ

Суть атаки: при использовании слабого секретного ключа для HMAC (HS256, HS384, HS512) злоумышленник может подобрать ключ методом грубой силы и подделать токен.

Защита:

  • Используйте криптографически стойкие ключи длиной не менее 256 бит.
  • Для генерации ключей используйте специализированные инструменты, а не придумывайте вручную.
  • Регулярно производите ротацию ключей.
  1. Атака на время жизни токена

Суть атаки: если сервер не проверяет claims exp, nbf или iat, злоумышленник может использовать просроченные токены или создавать токены с очень длительным сроком действия.

Защита:

  • Обязательно проверяйте время действия токена (exp).
  • Устанавливайте разумный срок действия (от минут до часов, а не дней или месяцев).
  • Используйте механизм обновления токенов (refresh tokens) для долгосрочной аутентификации.
  1. Небезопасное хранение токенов на клиенте

Суть атаки: хранение JWT в локальном хранилище (localStorage) делает его уязвимым для атак XSS.

Защита:

  • Используйте HttpOnly cookies для хранения токенов.
  • Применяйте флаги Secure и SameSite для cookies.
  • Внедрите защиту от CSRF для cookies.

Михаил, пентестер

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

Это позволило мне создать токен с правами администратора и получить полный доступ к системе. Самое интересное, что разработчики были уверены в безопасности своей реализации, потому что "используют проверенную библиотеку". Они не понимали, что неправильно её настроили, пропустив параметр с явным указанием ожидаемого алгоритма.

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

  1. Key ID (kid) Manipulation

Суть атаки: манипуляция параметром kid в header может привести к использованию скомпрометированного или слабого ключа для проверки подписи.

Защита:

  • Валидируйте параметр kid перед использованием.
  • Используйте белый список допустимых kid.
  • Не позволяйте kid указывать на произвольные файлы или URL.

Помните: безопасность JWT зависит от правильной реализации на всех уровнях — от генерации до проверки токена. Используйте проверенные библиотеки, но всегда понимайте, как они работают и правильно их настраивайте. 🛡️

Практики защиты payload и реализация JWT в продакшене

Чтобы обеспечить максимальную защиту JWT в продакшн-окружении, необходимо комплексно подходить к проектированию системы аутентификации и авторизации. Рассмотрим ключевые практики, которые следует внедрить:

  1. Минимизация данных в payload

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

json
Скопировать код
// Плохо
{
"sub": "1234567890",
"name": "Иван Петров",
"email": "ivan@example.com",
"phone": "+7-900-123-45-67",
"permissions": ["admin", "editor", "viewer"],
"groups": ["finance", "management", "reports"],
"office_location": "Moscow",
"department": "IT",
"manager_id": "9876543210",
"hire_date": "2018-06-01"
}

// Хорошо
{
"sub": "1234567890",
"iat": 1622505600,
"exp": 1622509200,
"jti": "random-unique-string"
}

Дополнительные данные лучше запрашивать отдельно после аутентификации пользователя.

  1. Управление жизненным циклом токенов

Стратегия управления токенами должна включать:

  • Короткое время жизни (TTL) для access токенов (15-60 минут)
  • Использование refresh токенов для обновления access токенов
  • Механизм отзыва токенов (например, через Redis или другое хранилище)
  • Ротацию ключей подписи по расписанию

Пример конфигурации системы токенов:

json
Скопировать код
// Конфигурация токенов
{
"accessToken": {
"ttl": 900, // 15 минут в секундах
"algorithm": "RS256",
"issuer": "auth.example.com"
},
"refreshToken": {
"ttl": 2592000, // 30 дней в секундах
"rotationPolicy": "oneTimeUse", // Одноразовый refresh токен
"familyPolicy": true // Отзыв всех токенов при компрометации
},
"keyRotation": {
"schedule": "0 0 1 * *", // Ежемесячно (cron-формат)
"overlapPeriod": 86400 // 1 день для плавного перехода
}
}

  1. Безопасное хранение и передача токенов
  • На сервере:
  • Храните секретные ключи в защищенных хранилищах (HashiCorp Vault, AWS KMS, Azure Key Vault)
  • Используйте переменные среды или конфигурационные файлы с ограниченными разрешениями
  • Никогда не хардкодьте секреты в исходном коде
  • На клиенте:
  • Храните access токены в памяти (если возможно)
  • Используйте HttpOnly, Secure, SameSite=Strict cookies
  • Избегайте localStorage и sessionStorage для хранения токенов
  1. Шифрование чувствительных данных

Если необходимо передавать чувствительную информацию в токене, используйте JWT Encryption (JWE) вместо обычного JWT. JWE обеспечивает шифрование payload, а не только его подпись.

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

{protected header}.{encrypted key}.{initialization vector}.{ciphertext}.{authentication tag}

При использовании JWE выбирайте современные алгоритмы шифрования, такие как:

  • Шифрование ключа: RSA-OAEP, ECDH-ES
  • Шифрование содержимого: A256GCM
  1. Мониторинг и аудит

Настройте мониторинг использования JWT в вашей системе:

  • Логируйте все необычные события (неверные подписи, истекшие токены, атаки на алгоритм)
  • Внедрите систему оповещений о подозрительной активности
  • Проводите регулярный аудит настроек безопасности
  • Используйте сканеры уязвимостей, специфичные для JWT

Пример простой интеграции JWT с Express.js и продвинутой обработкой ошибок:

JS
Скопировать код
const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();

// Middleware для проверки JWT
const authenticateJWT = (req, res, next) => {
const authHeader = req.headers.authorization;

if (!authHeader) {
return res.status(401).json({ error: 'Authorization header missing' });
}

const token = authHeader.split(' ')[1];

try {
// Явно указываем ожидаемый алгоритм
const user = jwt.verify(token, process.env.JWT_SECRET, {
algorithms: ['RS256'], // Только RS256, защита от атаки подмены алгоритма
issuer: 'auth.example.com', // Проверка издателя
audience: 'api.example.com', // Проверка аудитории
});

req.user = user;
next();
} catch (error) {
if (error.name === 'TokenExpiredError') {
return res.status(401).json({ error: 'Token expired' });
}
if (error.name === 'JsonWebTokenError') {
// Логируем попытки использования неверных токенов
console.warn(`JWT validation failed: ${error.message}, token: ${token.substring(0, 10)}...`);
return res.status(403).json({ error: 'Invalid token' });
}
if (error.name === 'NotBeforeError') {
return res.status(401).json({ error: 'Token not yet valid' });
}

return res.status(500).json({ error: 'Internal server error' });
}
};

// Защищенный маршрут
app.get('/api/protected', authenticateJWT, (req, res) => {
res.json({ message: 'Protected data', user: req.user.sub });
});

app.listen(3000, () => {
console.log('Server running on port 3000');
});

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

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

Проверь как ты усвоил материалы статьи
Пройди тест и узнай насколько ты лучше других читателей
Что такое payload header?
1 / 5

Элина Баранова

разработчик Android

Свежие материалы

Загрузка...