JWT (произносится как «джот») означает JSON Web Token. Он определен в стандарте RFC7519, опубликованном в мае 2015 года. Он используется для безопасной передачи объектов JSON. Давайте углубимся в то, из чего состоит JWT и почему это важно!

Вот из чего состоит JWT:

Header.Payload.Signature

Вау! Так просто, правда?

Заголовок обычно состоит из двух элементов: типа токена и алгоритма хеширования:

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

JWT здесь означает веб-токен JSON, как вы можете себе представить. HS256 означает алгоритм HMAC-SHA256, симметричный алгоритм, который использует один секретный ключ для Подписи. Есть много других алгоритмов, которые можно использовать, но другие распространенные включают RSASSA-PKCS1-v1_5 + SHA256 (RS256) и ECDSA + P-256 + SHA256 (ES256), оба являются асимметричными, что означает, что они используют пару открытый/закрытый ключ. Также доступно значение none для alg, которое, как было обнаружено, выявляет уязвимости в некоторых библиотеках JWT.

Полезная нагрузка содержит фактические данные и также называется заявками. Пример показан ниже с различными битами информации в объекте:

Payload = { "user_id": "0916", "admin": true, "iss": "robert.com" } 

Существует три типа утверждений: зарезервированные, общедоступные и частные. По большей части общедоступные утверждения используются в том виде, в каком они определены теми, кто использует JWT. Зарезервированные утверждения включают iss для эмитента токена, aud для аудитории, для которой предназначен JWT, sub. для темы и exp для срока действия. Они используют три буквы, чтобы сделать JWT компактным. Частные претензии — это индивидуальные претензии, согласованные между сторонами. Однако вас предупреждают, что они могут конфликтовать (при совпадении имен утверждений) и должны использоваться с осторожностью.

Подпись принимает закодированный Заголовок и закодированную Полезную нагрузку, секретный ключ, известный только производителю JWT (нашего сервера), алгоритму хэширования. (например, HMAC-SHA256) и подписывает его.

signature = HMACSHA256(
    base64UrlEncode(Header) + "." + 
    base64UrlEncode(Payload), 
    "some_secret_key"
);

Происходит следующее: Заголовок и Полезная нагрузка кодируются и соединяются с помощью .. Затем оба закодированных бита информации затем хешируются с помощью нашего алгоритма HS256 и нашего секретного ключа, поэтому мы называем его some_secret_key для создания подписи. Все они объединяются, чтобы сформировать наш веб-токен JSON (фактически закодированный с помощью https://jwt.io/#debugger)! Теперь этот JWT можно легко передать через среды HTML и HTTP.

base64UrlEncode(Header) => eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
base64UrlEncode(Payload) => eyJ1c2VyX2lkIjoiMDkxNiIsImFkbWluIjp0cnVlLCJpc3MiOiJyb2JlcnQuY29tIn0
signature => HWmfTFIMIgCym7sVsH7O4SvCpqS5hvBi50Z_tNV9F7Q
JWT = eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiMDkxNiIsImFkbWluIjp0cnVlLCJpc3MiOiJyb2JlcnQuY29tIn0.HWmfTFIMIgCym7sVsH7O4SvCpqS5hvBi50Z_tNV9F7Q

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

Вот простая аналогия того, что такое JWT и как работает этот процесс проверки. Ты VIP-персона, собирающаяся на концерт любимой группы. Ваши учетные данные — это вы сами и ваш идентификатор (так же, как имя пользователя и пароль). Место проведения и персонал (сервер) имеют список гостей, который содержит ваше имя (база данных). После предоставления своих учетных данных вам выдается этот волшебный браслет, который доказывает, что ваша личность была проверена по списку и подтверждена (JWT). Вам больше не нужно проходить повторную проверку, так как нет другого способа получить эти волшебные браслеты, и вы можете свободно входить и выходить из зала до окончания концерта (срок действия JWT — «exp»).

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

Вам когда-нибудь приходилось менять секретный ключ? Это вопрос, над которым я действительно размышлял. В идеале вам не нужно менять секретный ключ, потому что он секретный и должен быть защищен, как и большинство секретных вещей. Изменение ключа потребует, чтобы все пользователи вышли из системы (что для меня звучит как своего рода перезагрузка сервера), поскольку старые выпущенные JWT пользователей будут недействительны с новым секретным ключом.

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

Вот некоторые случайные вещи, которые я заметил, изучая JWT. Во-первых, их довольно часто называют токенами JWT. Эта практика страдает от синдрома RAS или «синдрома избыточного синдрома Акройнима» (HA!), Поскольку буква «T» в JWT означает токен. Называть его токеном JWT — это то же самое, что называть банкомат или PIN-код. Во-вторых, JWT — это аббревиатура внутри аббревиатуры (OMG Acronym-ception)! JWT означает JSON, Web Token, а сам JSON означает JavaSscript Object N. К сожалению, веб-токен JavaScript Object Notation довольно громоздкий, поэтому давайте просто остановимся на «jot» 😀.