Ответ
JWT — это открытый стандарт (RFC 7519) для создания токенов доступа, которые позволяют безопасно передавать информацию между сторонами в виде компактного JSON-объекта. Токен подписан цифровой подписью, что позволяет проверять его целостность и подлинность.
Структура JWT: Токен состоит из трех частей, разделенных точками:
header.payload.signature
- Header (Заголовок): Содержит тип токена (
JWT) и алгоритм подписи (например,HS256илиRS256).{ "alg": "HS256", "typ": "JWT" } - Payload (Полезная нагрузка): Содержит утверждения (claims) — утверждения о пользователе и дополнительных данных. Стандартные claims:
sub(subject — идентификатор пользователя),exp(expiration time — срок действия),iat(issued at — время выдачи).{ "sub": "1234567890", "name": "John Doe", "role": "admin", "exp": 1516239022 } - Signature (Подпись): Создается путем кодирования header и payload в Base64Url, их объединения с точкой и последующей подписи с использованием секретного ключа (для HMAC) или приватного ключа (для RSA) по алгоритму, указанному в header.
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
Типичный поток аутентификации с JWT:
- Логин: Пользователь отправляет учетные данные (логин/пароль) на сервер аутентификации.
- Верификация и генерация токена: Сервер проверяет учетные данные и, если они верны, генерирует JWT, подписывает его секретным ключом и отправляет клиенту (обычно в теле ответа или в cookie).
- Хранение и отправка токена: Клиент (браузер, мобильное приложение) сохраняет токен (часто в
localStorageилиHttpOnlycookie) и включает его в заголовокAuthorizationпоследующих запросов к защищенным API.Authorization: Bearer <your-jwt-token> - Верификация токена на защищенных ресурсах: Сервер (или API-шлюз) получает токен, проверяет его подпись на валидность с помощью секретного/публичного ключа, убеждается, что срок действия (
exp) не истек, и извлекает claims (например,role) для авторизации доступа к ресурсу.
Ключевые преимущества:
- Бессостояние (Stateless): Серверу не нужно хранить сессию пользователя. Вся необходимая информация содержится в самом токене.
- Масштабируемость: Легко масштабировать, так как любой сервер с секретным/публичным ключом может проверить токен.
- Гибкость: В payload можно включать любые пользовательские данные (claims).
Критические моменты безопасности:
- Секретный ключ: Должен храниться в безопасности на сервере. Компрометация ключа позволяет злоумышленнику генерировать любые токены.
- Небезопасное хранение на клиенте: Хранение в
localStorageуязвимо к XSS-атакам. Более безопасный вариант —HttpOnly,Secure,SameSitecookies. - Невозможность отзыва: JWT действует до истечения срока (
exp). Для реализации мгновенного выхода (logout) требуется дополнительная архитектура (черные списки токенов, короткий срок жизни + refresh tokens).
Пример генерации и проверки токена на C# (библиотека System.IdentityModel.Tokens.Jwt):
// Генерация токена
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("your_super_secret_key"));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, "user123"),
new Claim("role", "admin")
};
var token = new JwtSecurityToken(
issuer: "your_issuer",
audience: "your_audience",
claims: claims,
expires: DateTime.Now.AddMinutes(30),
signingCredentials: credentials
);
var tokenString = new JwtSecurityTokenHandler().WriteToken(token);
// Проверка токена
var tokenHandler = new JwtSecurityTokenHandler();
tokenHandler.ValidateToken(tokenString, new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = securityKey,
ValidateIssuer = true,
ValidIssuer = "your_issuer",
ValidateAudience = true,
ValidAudience = "your_audience",
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero // Точная проверка времени
}, out SecurityToken validatedToken); Ответ 18+ 🔞
А, JWT, ёпта! Ну это ж классика, как бутерброд с колбасой в мире авторизации. Смотри, сейчас разжую, как для дебила, но ты не обижайся — просто чтоб на пальцах.
Представь, что ты приходишь в клуб, а тебе на руку штамп ставят. Ты потом с этим штампом ходишь, тебе и в бар наливают, и в туалет пускают. JWT — это и есть такой цифровой штамп, только вместо чернил — криптография, блядь.
Из чего эта хрень состоит?
Токен — это три куска, склеенные точками: голова.тело.подпись. Всё в кодировке Base64Url, но это так, техническая хуйня.
- Голова (Header) — там написано, что это за тип и чем подписано. Типа инструкция для проверяющего.
{ "alg": "HS256", // Алгоритм подписи, например, HMAC-SHA256 "typ": "JWT" // Тип — JWT, чё уж там } - Тело (Payload) — а вот тут самое интересное лежит. Всякие утверждения (claims) про пользователя: кто он, какие права имеет, когда токен сдохнет. Можно свои поля пихать.
{ "sub": "1234567890", // Кто (subject) "name": "Вася Пупкин", "role": "admin", // Роль — админ, значит, можно всё "exp": 1516239022 // Время смерти токена (timestamp) } - Подпись (Signature) — вот тут магия. Берут закодированные голову и тело, склеивают точкой и ебут алгоритмом с секретным ключом. Получается этакая печать, которую не подделать, если ключ не утек.
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
Как этим пользуются? Очень просто:
- Логин. Ты шлёшь логин-пароль на сервер. Сервер проверяет — не мудак ли ты. Если не мудак, он генерит этот JWT, подписывает своим секретным ключом и шлёт тебе обратно.
- Хранение. Ты этот токен куда-то суёшь. В браузере — либо в
localStorage(но это рискованно, могут через XSS украсть), либо вHttpOnlyкуки (безопаснее). В мобилке — в защищённое хранилище. - Использование. Когда тебе нужно что-то от защищённого API, ты просто прикрепляешь этот токен в заголовок запроса:
Authorization: Bearer <твой_длинный_токен_тут> - Проверка. Сервер или API-шлюз видят этот заголовок, вытаскивают токен, проверяют подпись своим секретным (или публичным) ключом. Если подпись сошлась — значит, токен настоящий, не поддельный. Потом смотрят на срок (
exp) — не просрочен ли. Если всё ок, вытаскивают из тела (payload) данные, например, роль"admin", и решают — пускать тебя дальше или послать на хуй.
Чем хорош?
- Stateless (без состояния). Серверу не нужно помнить сессии в памяти или базе. Всё нужное прямо в токене. Масштабируется легко — поставил десять серверов, и все могут проверять токен, зная один секретный ключ.
- Универсальный. В payload можно запихнуть что угодно — имя, почту, права, цвет любимых трусов.
Где подвох? Безопасность, сука!
- Ключ. Секретный ключ на сервере — это святое. Утечёт ключ — злоумышленник сможет лепить любые токены, будто он Бог. Хранить надо как зеницу ока.
- Хранение на клиенте.
localStorage— лакомый кусок для XSS. Куки с флагамиHttpOnly,Secure,SameSite— надёжнее. - Не отозвать. Пока токен не просрочился (поле
exp), он жив. Нельзя просто так взять и "разлогинить" пользователя. Для этого нужны дополнительные костыли: либо чёрные списки токенов (что убивает stateless), либо короткая жизнь access-токена + refresh-токены.
Пример на C# (чтоб было понятно, как код выглядит):
// Создание токена
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("твой_супер_секретный_ключ_сюда"));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, "user123"),
new Claim("role", "admin")
};
var token = new JwtSecurityToken(
issuer: "твой_сервис",
audience: "твоё_приложение",
claims: claims,
expires: DateTime.Now.AddMinutes(30), // Живёт 30 минут
signingCredentials: credentials
);
var tokenString = new JwtSecurityTokenHandler().WriteToken(token); // Вот он, строка токена
// Проверка токена
var tokenHandler = new JwtSecurityTokenHandler();
tokenHandler.ValidateToken(tokenString, new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = securityKey, // Проверяем подпись тем же ключом
ValidateIssuer = true,
ValidIssuer = "твой_сервис", // Должен совпасть issuer
ValidateAudience = true,
ValidAudience = "твоё_приложение", // Должен совпасть audience
ValidateLifetime = true, // Проверяем, не протух ли
ClockSkew = TimeSpan.Zero // Без допуска по времени, строго
}, out SecurityToken validatedToken); // Если всё ок — validatedToken будет не null
Короче, JWT — инструмент мощный, но как топор: если в руках идиота, можно себе же ноги отрубить. Главное — ключи хранить в секрете, сроки жизни делать адекватные и не пихать в payload чувствительные данные (тип паролей), потому что payload легко раскодировать и прочитать, блядь. Подпись защищает от подделки, но не от чтения.