jwt malformed что значит

Jwt malformed что значит

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

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

Формат JWT: описание

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

Структура JWT

Согласно RFC-7519, JSON Web Tokens — один из способов представления данных для передачи между двумя или более сторонами в виде JSON-объекта.

Как правило, структурно JWT состоит из трех частей:

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

Заголовок и полезная нагрузка — обычные JSON-объекты, которые необходимо дополнительно закодировать при помощи алгоритма base64url. Закодированные части соединяются друг с другом, и на их основе вычисляется подпись, которая также становится частью токена.

В общем случае токен выглядит следующим образом:

На рис. 1 можно увидеть, что токен состоит из трех частей, разделенных точками.

jwt malformed что значит. Смотреть фото jwt malformed что значит. Смотреть картинку jwt malformed что значит. Картинка про jwt malformed что значит. Фото jwt malformed что значитРис. 1. JSON Web Token (пример с сайта jwt.io)

Красная часть — заголовок:

Фиолетовая часть — полезная нагрузка:

Голубая часть — подпись:

Рассмотрим структуру полей более подробно.

Заголовок

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

Эта часть, как было ранее упомянуто, является JSON-объектом и имеет следующий формат:

Здесь присутствуют следующие поля:

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

Поле alg обязательно для заполнения. В приведенном случае был применен алгоритм HS256 (HMAC-SHA256), в котором для генерации и проверки подписи используется единый секретный ключ.

Для подписи JWT могут применяться и алгоритмы асимметричного шифрования, например RS256 (RSA-SHA256). Стандарт допускает использование и других алгоритмов, включая HS512, RS512, ES256, ES512, none и др.

Использование алгоритма none указывает на то, что токен не был подписан. В подобном токене отсутствует часть с подписью, и установить его подлинность невозможно.

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

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

В нашем случае полезная нагрузка содержит следующий JSON-объект:

Здесь присутствуют следующие поля:

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

Подпись

Подпись генерируется следующим образом.

Заголовок и полезная нагрузка кодируются при помощи алгоритма base64url, после чего объединяются в единую строку с использованием точки ( «.» ) в качестве разделителя.

Генерируется подпись (в нашем примере — с применением алгоритма HMAC-SHA256), которая добавляется к исходной строке так же через точку.

На псевдокоде алгоритм выглядит примерно так:

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

Подпись приведенного в пример токена можно проверить с использованием секретного ключа test (например, на сайте jwt.io).

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

Схема аутентификации с использованием JWT предельно проста.

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

При последующих обращениях токен передается приложению в запросах от пользователя (в cookie, заголовках запроса, POST- или GET-параметрах и т. д.).

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

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

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

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

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

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

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

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

Формат JWT: атаки

В этом разделе будут рассмотрены основные атаки на JWT и даны рекомендации по их предотвращению.

Перехват токена

Перехват пользовательского токена может привести к ряду неприятных последствий.

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

В соответствии с лучшими практиками для предотвращения подобной угрозы рекомендуется:

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

Здесь рекомендации будут следующие:

Refresh tokens

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

Access token при таком подходе имеет сильно ограниченное время жизни (например, одну минуту). Refresh token же имеет длительное время жизни (день, неделя, месяц), но он одноразовый и служит исключительно для обновления access token пользователя.

Схема аутентификации в таком случае выглядит следующим образом:

Подбор ключа симметричного алгоритма подписи

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

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

Рекомендации для защиты от атаки в этом случае такие:

Использование алгоритма none

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

Рассмотрим подобную атаку на нашем примере. Наш токен в незакодированном виде выглядит следующим образом:

Предположим, мы хотим, чтобы приложение считало нас администратором. Для этого необходимо установить значение admin в поле role полезной нагрузки. Но при внесении в токен этого изменения подпись токена станет невалидной, и приложение не примет такой JWT.

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

Поскольку мы используем алгоритм none, подпись отсутствует. В закодированном виде наш JWT будет выглядеть так:

Этот токен мы и передадим на сервер. Уязвимое приложение, проверив заголовок JWT и обнаружив в нем alg: none, примет этот токен без всяких проверок, как если бы он был легитимным, в результате чего мы получим привилегии администратора.

Чтобы защититься от такой атаки:

Изменение алгоритма подписи

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

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

Для рассмотрения примера этого варианта атаки нам понадобится новый JWT:

В кодированном виде он будет выглядеть следующим образом:

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

Для тестов мы будем использовать сайт jwt.io (рис. 2).

jwt malformed что значит. Смотреть фото jwt malformed что значит. Смотреть картинку jwt malformed что значит. Картинка про jwt malformed что значит. Фото jwt malformed что значитРис. 2. Исходный JWT

Как и в предыдущем примере, модифицируем токен:

В кодированном виде заголовок и полезная нагрузка будут выглядеть следующим образом:

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

Для начала переводим ключ в hex-представление (рис. 3).

jwt malformed что значит. Смотреть фото jwt malformed что значит. Смотреть картинку jwt malformed что значит. Картинка про jwt malformed что значит. Фото jwt malformed что значитРис. 3. Hex-представление ключа

Затем генерируем подпись с использованием openSSL (рис. 4).

jwt malformed что значит. Смотреть фото jwt malformed что значит. Смотреть картинку jwt malformed что значит. Картинка про jwt malformed что значит. Фото jwt malformed что значитРис. 4. Генерация подписи для JWT

Полученное значение E1R1nWNsO-H7h5WoYCBnm6c1zZy-0hu2VwpWGMVPK2g добавляем к уже имеющейся строке, и наш токен принимает следующий вид:

Подставляем в поле secret на jwt.io наш публичный ключ, и JWT успешно проходит проверку (не забудьте поставить галочку secret base64 encoded!) (рис. 5).

jwt malformed что значит. Смотреть фото jwt malformed что значит. Смотреть картинку jwt malformed что значит. Картинка про jwt malformed что значит. Фото jwt malformed что значитРис. 5. Успешная проверка подписи JWT

Для предотвращения такой атаки рекомендуется:

Манипуляция ключевыми идентификаторами

Стандарт RFC-7515 описывает параметр заголовка kid (Key ID, идентификатор ключа). Вместе с тем стандарт говорит о том, что формат этого поля строго не определен. Поэтому разработчики вольны интерпретировать его так, как удобно им, что зачастую приводит к различным ошибкам.

Для примера возьмем следующий заголовок JWT:

Предполагается, что для проверки токена будет использован хранящийся в БД ключ с идентификатором 1337. В случае ошибок кодирования это поле может быть уязвимо к SQL-инъекции:

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

В следующем примере предположим, что для проверки токена будет использован ключ из файла keys/service3.key.

Если параметр не валидируется, злоумышленник сможет провести атаку Path Traversal (Directory Traversal) и вместо предполагаемого пути до файла с ключом передаст в поле kid путь до какого-либо публичного файла:

Злоумышленник может получить доступ к файлу cat.png и подписать JWT с использованием содержимого этого файла, поскольку этот файл общедоступный (например, он опубликован на одной из страниц сервиса). Сервис же, получив в поле kid путь до файла cat.png, использует его содержимое в качестве ключевого файла для проверки подписи токена (которая окажется успешной, ведь злоумышленник заранее об этом позаботился).

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

Заключение

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

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

Итак, для безопасного использования JWT следует:

Источник

jwt malformed #756

Comments

grenadecx commented Jun 13, 2016 •

Okay so I’m running laravel 5.2 and trying to generate a token that is valid on a socket.io server. However I seem to fail horrible at this, (not sure if this is a problem with me or this library) so some help would be much appreciated!

On my laravel I have some simple lines:

And then I use this token when making the socket io connection from the client:

Simple socketio server:

However this gives me:

So I instead of using socketio-jwt library, I also tried interfacing it directly against jsonwebsocket which gives me invalid signature as well.

I use the same key on both places and my jwt.php config file looks like this:

So what am I missing? I also tried to decode the jwt on the https://jwt.io/ website, but that doesn’t work either. Help is very much appreciated!

The text was updated successfully, but these errors were encountered:

tymondesigns commented Jun 13, 2016

grenadecx commented Jun 13, 2016

Sorry, I accidentally opened it without context, it’s added.

grenadecx commented Jun 13, 2016

And at some point I also got jwt malformed, just trying to replicate that. But any help would be appreciated.

grenadecx commented Jun 13, 2016

I just tried another library, https://github.com/lcobucci/jwt and I have no problems generating a token that will get validated from the socketio server.

Could this be an issue with the underlying namshi/jose library?

tymondesigns commented Jun 13, 2016

No problem.. reopened.. I’ll take a look when I can

tdhsmith commented Jun 15, 2016

Could you post an example of a failing JWT with its key?

grenadecx commented Jun 15, 2016 •

Edit:
Validating this key as from my understanding should work great over at jwt.io since it uses HS256 encryption. But it fails with invalid signature over there.

Here’s a simple validation directly against jsonwebtoken for nodejs that fails:

mcblum commented Jun 17, 2016

Does this sound like it could be the same as the issue I just submitted, #765?

tdhsmith commented Jun 17, 2016 •

@grenadecx Ok well I can confirm that jwt.io and jsonwebtoken don’t accept it for some reason, but I’m not sure why yet.

I manually verified that the signature looks valid based on the given payload and header, though:

I did find one big discrepancy: your payload has escaping backslashes before the forward slashes:

The extra slashes then disappear to javascript because / isn’t a metacharacter, which is an important point, but I don’t know why this would be relevant during the signature validation. (it should verify the signature of the base64-ed payload directly, not decode it to a string, then reencode it)

grenadecx commented Jun 17, 2016

Thanks for taking a look.

I’ve no idea why I have baskslashes in the url. I mean, I don’t do anything funky with it, I’m running the basic configuration file and all I do is the JWTAuth::fromUser function with a user and then insert the token with <<$token>> in the javascript.

How imporant is the iss? Seems like it can basically be anything and still give a valid signature?

tdhsmith commented Jun 17, 2016

Actually I’m thinking the backslash thing was a red herring. The way I calculated the signature was wrong, so it’s not a good sign that namshi/jose agreed with me.

iss isn’t actually checked by this library’s validators, but some services use it to identify where requests are coming from for example. If you’re building both ends of the communication, it isn’t required by any means. You’d have to take it out of your jwt.required_claims as well as call JWTAuth::factory()->setDefaultClaims to exclude it. But don’t do that yet because I don’t think that’s the problem anymore.

tdhsmith commented Jun 17, 2016

Do you know what version of namshi/jose you have installed? (run composer show namshi/jose )

It’s possible you’re hitting namshi/jose#36. It’s been fixed in this library since #126 (i.e. jwt-auth v0.5.4), but it’s possible you haven’t updated or are running a really old version. (What jwt-auth version are you running by the way?)

tdhsmith commented Jun 17, 2016

The odd thing—and the reason I think that’s the issue—is that your signature is the base64url encoded version of the HMAC hex string. But you should be taking the base64url of the HMAC’s actual binary value.

Otherwise it’s doing a weird conversion that’s basically useless (base64 is mostly about making binary data consumable as text, but hex is already text). It also explains why your signature was weirdly long (base64 is 4x denser than hex, and base64-ing hex makes it another 3/4ths as dense).

grenadecx commented Jun 18, 2016

Yeah I also found it weird that the token as so long compared to other libraries when generating the same amount of data.

I was using the documentation when installing just a few days ago, but I can try updating to 0.5.4 or whatever the latest is and see if that solves it.

I’ll report back in a bit 🙂

grenadecx commented Jun 18, 2016

Okay so I updated to tymon/jwt-auth 0.5.9 which updated the namshi/jose to 5.0.2 and it solved my problem.

Not sure why I was using an older version since the documentation says to install 0.5.*. I really appreciate the help and wish ya the best!

Источник

Пять простых шагов для понимания JSON Web Tokens (JWT)

jwt malformed что значит. Смотреть фото jwt malformed что значит. Смотреть картинку jwt malformed что значит. Картинка про jwt malformed что значит. Фото jwt malformed что значит

Представляю вам мой довольно вольный перевод статьи 5 Easy Steps to Understanding JSON Web Tokens (JWT). В этой статье будет рассказано о том, что из себя представляют JSON Web Tokens (JWT) и с чем их едят. То есть какую роль они играют в проверке подлинности пользователя и обеспечении безопасности данных приложения.

Для начала рассмотрим формальное определение.

JSON Web Token (JWT) — это JSON объект, который определен в открытом стандарте RFC 7519. Он считается одним из безопасных способов передачи информации между двумя участниками. Для его создания необходимо определить заголовок (header) с общей информацией по токену, полезные данные (payload), такие как id пользователя, его роль и т.д. и подписи (signature).
Кстати, правильно JWT произносится как /dʒɒt/

jwt malformed что значит. Смотреть фото jwt malformed что значит. Смотреть картинку jwt malformed что значит. Картинка про jwt malformed что значит. Фото jwt malformed что значит

Приложение использует JWT для проверки аутентификации пользователя следующим образом:

Структура JWT

Шаг 1. Создаем HEADER

Хедер JWT содержит информацию о том, как должна вычисляться JWT подпись. Хедер — это тоже JSON объект, который выглядит следующим образом:

Шаг 2. Создаем PAYLOAD

Payload — это полезные данные, которые хранятся внутри JWT. Эти данные также называют JWT-claims (заявки). В примере, который рассматриваем мы, сервер аутентификации создает JWT с информацией об id пользователя — userId.

Мы положили только одну заявку (claim) в payload. Вы можете положить столько заявок, сколько захотите. Существует список стандартных заявок для JWT payload — вот некоторые из них:

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

Шаг 3. Создаем SIGNATURE

Подпись вычисляется с использование следующего псевдо-кода:

Алгоритм base64url кодирует хедер и payload, созданные на 1 и 2 шаге. Алгоритм соединяет закодированные строки через точку. Затем полученная строка хешируется алгоритмом, заданным в хедере на основе нашего секретного ключа.

Шаг 4. Теперь объединим все три JWT компонента вместе

Теперь, когда у нас есть все три составляющих, мы можем создать наш JWT. Это довольно просто, мы соединяем все полученные элементы в строку через точку.

Вы можете попробовать создать свой собственный JWT на сайте jwt.io.
Вернемся к нашему примеру. Теперь сервер аутентификации может слать пользователю JWT.

Как JWT защищает наши данные?

Очень важно понимать, что использование JWT НЕ скрывает и не маскирует данные автоматически. Причина, почему JWT используются — это проверка, что отправленные данные были действительно отправлены авторизованным источником. Как было продемонстрировано выше, данные внутри JWT закодированы и подписаны, обратите внимание, это не одно и тоже, что зашифрованы. Цель кодирования данных — преобразование структуры. Подписанные данные позволяют получателю данных проверить аутентификацию источника данных. Таким образом закодирование и подпись данных не защищает их. С другой стороны, главная цель шифрования — это защита данных от неавторизованного доступа. Для более детального объяснения различия между кодированием и шифрованием, а также о том, как работает хеширование, смотрите эту статью. Поскольку JWT только лишь закодирована и подписана, и поскольку JWT не зашифрована, JWT не гарантирует никакой безопасности для чувствительных (sensitive) данных.

Шаг 5. Проверка JWT

В нашем простом примере из 3 участников мы используем JWT, который подписан с помощью HS256 алгоритма и только сервер аутентификации и сервер приложения знают секретный ключ. Сервер приложения получает секретный ключ от сервера аутентификации во время установки аутентификационных процессов. Поскольку приложение знает секретный ключ, когда пользователь делает API-запрос с приложенным к нему токеном, приложение может выполнить тот же алгоритм подписывания к JWT, что в шаге 3. Приложение может потом проверить эту подпись, сравнивая ее со своей собственной, вычисленной хешированием. Если подписи совпадают, значит JWT валидный, т.е. пришел от проверенного источника. Если подписи не совпадают, значит что-то пошло не так — возможно, это является признаком потенциальной атаки. Таким образом, проверяя JWT, приложение добавляет доверительный слой (a layer of trust) между собой и пользователем.

В заключение

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

Что дальше?

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *