Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
В этой статье мы максимально глубоко изучим технологию JSON Web Tokens (JWT): где она используется, в чем ее плюсы и минусы и какие опасности она может таить для всего веб‑приложения, если программист видит ее впервые. Мы также рассмотрим типичные уязвимости JWT, научимся их эксплуатировать и исправлять.
Прежде чем мы перейдем непосредственно к JWT, давай повторим основы и вспомним главные термины, которые неразрывно связаны с современным вебом и информационной безопасностью, а именно — аутентификация и авторизация. Эти знания нам необходимы, чтобы понимать весь дальнейший материал.
Представим, что мы хотим войти в свой аккаунт Facebook. Веб‑приложению нужно понять, что мы владеем этим аккаунтом. Для этого оно просит нас предоставить корректные учетные данные. Обычно это логин и пароль, которые мы вводим на странице входа.
Приложение проверяет предоставленные данные, и, если они верны, мы входим в собственный аккаунт. Этот процесс называется аутентификацией.
info
Аутентификация — проверка подлинности предъявленного пользователем идентификатора, в процессе которой пользователь доказывает, что он действительно тот, за кого себя выдает. Сравнение пароля, введенного пользователем, с паролем, который сохранен в базе данных сервера, — один из примеров аутентификации.
Высокоуровневая схема аутентификации
После успешной аутентификации мы заходим на страницу со своим профилем. Веб‑приложение понимает, что пользователь — тот, за кого себя выдает, то есть мы успешно аутентифицированы.
Теперь мы можем отредактировать собственный профиль, изменить имя и фамилию или поменять возраст. Мы не можем редактировать чужой профиль, поэтому прежде, чем разрешить редактирование, приложению нужно убедиться, что запрос пришел от владельца профиля. Процесс проверки прав на осуществление действий называется авторизацией.
info
Авторизация — это процесс проверки, подтверждения или предоставления разрешений, прав доступа и привилегий на выполнение определенных действий. Пример авторизации: пользователь хочет прочитать документ на сайте, приложение проверяет, имеет ли он право читать его.
Высокоуровневая схема авторизации
Аутентификация проходит один раз, когда ты вводишь логин и пароль. Авторизация происходит при каждом запросе после аутентификации, поэтому если допустить ошибку в этой системе, то злоумышленники смогут выполнять действия от имени других пользователей. Например, сделать покупку от их имени или узнать конфиденциальную информацию. Важно знать безопасные и проверенные способы как аутентификации, так и авторизации.
Сессионные cookie и токены — два важных и взаимозаменяемых механизма безопасности в современном вебе, которые используются в процессах аутентификации и авторизации.
После того как пользователь аутентифицировался, они служат фактором, на основе которого сервер понимает, что запрос отправил определенный пользователь. Без необходимости повторно вводить логин и пароль.
Взаимодействие браузера и сервера с куками
HTTP Cookie — это небольшие записи, которыми обмениваются клиент (твой браузер) и сервер. Всякий раз при обращении к соответствующему сайту эти данные пересылаются серверу в составе HTTP-запроса.
Куки придуманы давно, в начале девяностых годов. В июне 1994 года Лу Монтулли, сотруднику Netscape Communications, пришла идея использовать их при веб‑соединении.
Куки используются в веб‑приложениях:
Процесс использования кук выглядит следующим образом:
В итоге нам не нужно вводить пароль каждый раз. Благодаря кукам сервер понимает, что мы уже прошли этот процесс.
info
Сервер не должен хранить куки пользователей ни в базе данных, ни в файловой системе. Они должны использоваться только в рантайме, чтобы ими не могли воспользоваться злоумышленники, которые получат доступ к серверу.
Для присвоения куки пользователю сервер отправляет такой заголовок:
Set-Cookie: <имя cookie>=<значение cookie>
Браузер, в свою очередь, — такой:
Cookie: <имя cookie>=<значение cookie>
Каждый из этих заголовков поддерживает множество атрибутов, которые позволяют снизить риски при возникновении уязвимостей на стороне приложения.
В современном вебе используются не только куки, но и токены. Это альтернативный и более современный механизм, который имеет свои плюсы и минусы по сравнению с привычными «печеньками».
Например, когда ты хочешь аутентифицироваться на сайте через другой сайт, на котором ты уже аутентифицирован (например, войти в Facebook через Gmail), используются OAuth-токены для межсерверной аутентификации между приложением и провайдером данных.
OAuth — не единственные токены, существует много других форматов:
Issuer
, Audience
, ExpiresOn
и HMACSHA256
;
Три основополагающие части JWT
Аббревиатура JWT расшифровывается как JSON Web Token. Стандарт RFC 7519 описывает отправку криптографически подписанных JSON данных (значений key-value) между системами. Теоретически стандарт RFC 7519 допускает отправку любых данных, но в современном вебе чаще используется, чтобы передавать информацию о пользователях для аутентификации, обработки сеансов и контроля доступа.
info
JWT (JSON Web Token) — это специальный формат токена, который позволяет безопасно передавать данные между клиентом и сервером. В качестве клиента может выступать браузер пользователя или мобильное приложение, сервера — виртуальная машина или выделенный компьютер с запущенным веб‑приложением.
JWT-токены были придуманы гораздо позже, чем куки. В 2011 году была сформирована группа JOSE (JSON Object Signing and Encryption group), призванная стандартизировать механизм защиты целостности, шифрования, а также формат ключей и алгоритмов идентификации для обеспечения совместимости служб безопасности, использующих формат JSON. К 2013 году в открытом доступе появились неофициальные наброски и примеры использования идей этой группы. Официально был стандартизован группой IETF в мае 2015 года.
Токены, как и сессионные куки, создаются сервером либо в начале взаимодействия пользователя с сайтом или приложением, либо после аутентификации пользователя в приложении. Затем они отправляются пользователю как часть ответа сервера — либо в HTTP-заголовке Set-Cookie
, либо в заголовке Bearer
. От того, где будет записан токен, зависит, как строится дальнейшая модель безопасности.
Взаимодействие браузера и сервера с JWT
Аутентификация и авторизация с использованием JWT-токена устроена следующим образом:
Все данные, которые нужны серверу, хранятся на стороне клиента в самом JWT. Это делает JWT популярным выбором для высокораспределенных веб‑сайтов, где пользователям необходимо беспрепятственно взаимодействовать с несколькими внутренними серверами.
Безопасность коммуникации между веб‑браузером и веб‑приложением строится на том, что токены генерируются и подписываются только со стороны веб‑приложения. Злоумышленник в теории не сможет подделать токен, так как не знает секретный ключ, который используется для подписи токена.
При подписи токена используется шифрование. С помощью подписи веб‑приложение проверяет, что токен действительно был сгенерирован им. Алгоритмы шифрования могут быть разными, например HS256 — HMAC с SHA-256.
JWT-токен состоит из трех частей, которые разделены точкой:
Формат токена:
header.payload.signature
Каждая из этих частей обычно кодируется в Base64 для передачи без повреждений по сети. Помимо этого, используется облегченный вариант URL-кодирования. Свойственный Base64 знак равенства усекается. Плюс заменяется минусом, а слеш (/
) — подчеркиванием, чтобы не возникло коллизий.
Пример токена:
eyJraWQiOiI5MTM2ZGRiMy1jYjBhLTRhMTktYTA3ZS1lYWRmNWE0NGM4YjUiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsImV4cCI6MTY0ODAzNzE2NCwibmFtZSI6IkNhcmxvcyBNb250b3lhIiwic3ViIjoiY2FybG9zIiwicm9sZSI6ImJsb2dfYXV0aG9yIiwiZW1haWwiOiJjYXJsb3NAY2FybG9zLW1vbnRveWEubmV0IiwiaWF0IjoxNTE2MjM5MDIyfQ.SYZBPIBg2CRjXAJ8vCER0LA_ENjII1JakvNQoP-Hw6GG1zfl4JyngsZReIfqRvIAEi5L4HV0q7_9qGhQZvy9ZdxEJbwTxRs_6Lb-fZTDpW6lKYNdMyjw45_alSCZ1fypsMWz_2mTpQzil0lOtps5Ei_z7mM7M8gCwe_AGpI53JxduQOaB5HkT5gVrv9cKu9CsW5MS6ZbqYXpGyOG5ehoxqm8DL5tFYaW3lB50ELxi0KsuTKEbD0t5BCl0aCR2MBJWAbN-xeLwEenaqBiwPVvKixYleeDQiBEIylFdNNIMviKRgXiYuAvMziVPbwSgkZVHeEdF5MQP1Oe2Spac-6IfA
Заголовок обычно состоит из JSON-объекта с двумя свойствами:
Далее этот JSON-объект хешируется с помощью Base64URL-кодирования, чтобы представить его в виде компактной строки.
Таким образом, в нашем примере заголовок JWT-токена имеет следующее значение:
{ "kid": "9136ddb3-cb0a-4a19-a07e-eadf5a44c8b5", "alg": "RS256"}
Также напомню, что это не шифрование, поэтому его можно раскодировать из консоли Linux:
$ echo eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9 | base64 -d {"typ":"JWT","alg":"HS256"}
Или из консоли JavaScript в браузере:
>> atob("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9") "{"typ":"JWT","alg":"HS256"}"
Вариант расшифровки через PowerShell:
PS C:> [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9")) {"typ":"JWT","alg":"HS256"}
Можно даже из CMD, но чуть сложнее:
C:>echo eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9 > file.txt && certutil -decode -f file.txt outfile.txt && type outfile.txt Input Length = 40 Output Length = 27 CertUtil: -decode command completed successfully. {"typ":"JWT","alg":"HS256"}
Вторая часть токена — это полезная нагрузка в виде JSON-объекта. Она содержит данные об авторизованном пользователе. Значение этой части JWT-токена разное в разных веб‑приложениях. Мы можем записать здесь любые публичные данные, которые могут быть полезны при авторизации.
Как и заголовок JWT-токена, полезная нагрузка хешируется с помощью Base64URL-кодирования для представления в виде компактной строки.
В нашем примере полезная нагрузка JWT-токена имеет следующее значение:
{ "iss": "portswigger", "exp": 1648037164, "name": "Carlos Montoya", "sub": "carlos", "role": "blog_author", "email": "[email protected]", "iat": 1516239022}
Названия некоторых полей могут показаться непонятными с первого взгляда. Здесь говорится о том, кто выписал токен (iss
), на кого он выписан (sub
и name
) и каков его срок жизни (exp
), по прошествии которого сервер должен считать его невалидным. Эти данные может изменить любой человек, затем закодировать в Base64 и вставить на место изначальных. Поэтому вся безопасность зависит напрямую от криптографической подписи.
www
При составлении полей полезной нагрузки разработчики стараются учитывать имена из документации IANA (Internet Assigned Numbers Authority), чтобы избежать конфликтов имен с общепринятыми нормами.
Основная причина, почему названия полей в полезной нагрузке JWT-токена пишутся сокращенно, — это уменьшение размера токена после шифрования.
Чтобы создать подпись, мы должны взять закодированный в Base64 заголовок, закодированную в Base64 полезную нагрузку, секретную строку и зашифровать эти данные. При этом нужно использовать тот же алгоритм шифрования, который указан в заголовке JWT-токена.
Вот пример для HS256:
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), your-256-bit-secret )
Процесс создания Signature предполагает наличие секретного ключа подписи. Подпись позволяет серверам убедиться в том, что данные, содержащиеся в токене, не были подделаны кем‑то другим с момента его выпуска.
www
jwt.io — онлайн‑дебаггер, который автоматизирует декодирование, проверку и генерацию JWT-токенов. Его можно использовать для собственных экспериментов.
Поскольку подпись напрямую зависит от остальной части токена, изменение одного байта заголовка или полезной нагрузки приводит к тому, что она перестает быть валидной. Не зная секретного ключа, невозможно сгенерировать правильную подпись для токена.
Исходная спецификация JWT очень ограниченна. Она определяет только формат представления информации в виде объекта JSON, который может быть передан между двумя сторонами. На практике JWT практически не используется как отдельная сущность.
Спецификация JWT была расширена спецификациями JSON Web Signature (JWS) — RFC 7515 и JSON Web Encryption (JWE) — RFC 7516, которые определяют конкретные способы реализации JWT.
Другими словами, когда мы говорим про JWT-токены в контексте веба, мы на самом деле имеем в виду либо JWS-токены, либо токены JWE. Токены JWE и JWS очень похожи, первые зашифрованы, а вторые закодированы.
Атаки на JWT-токены подразумевают отправку злоумышленником измененных токенов на сервер для достижения своей цели. Как правило, эта цель заключается в том, чтобы обойти аутентификацию и контроль доступа, выдавая себя за другого пользователя, который уже прошел аутентификацию.
Последствия JWT-атак обычно серьезны. Если злоумышленнику удается создать собственные действительные токены с произвольными значениями, он может повысить свои привилегии или выдать себя за другого пользователя, получив полный контроль над его учетной записью.
Уязвимости, позволяющие подделывать JWT-токены, обычно возникают из‑за несовершенной обработки этих самых токенов в самом приложении. Разные спецификации, связанные с JWT-токенами, относительно гибки по своей конструкции и позволяют разработчикам сайтов самостоятельно определять многие детали реализации. В результате разработчики могут допустить уязвимость даже при использовании библиотек с усиленной защитой.
Недостатки реализации, как правило, подразумевают, что подпись у токенов не проверяется должным образом. Это позволяет злоумышленникам подделывать подписанные данные.
Даже если подпись проверена надежно, можно ли ей доверять, в значительной степени зависит от того, действительно ли никому не известен секретный ключ сервера. Если этот ключ каким‑то образом утекает либо его можно угадать или перебрать, злоумышленник может сгенерировать действительную подпись для любого произвольного токена, что поставит под угрозу все приложение.
Сейчас мы перейдем к рассмотрению большинства уязвимостей, которые могут возникнуть при работе с JWT-токенами. Мы будем проверять их на практике, поэтому советую зарегистрироваться на сайте PortSwigger и решать лаборатории вместе со мной.
info
PortSwigger WebSecurity Academy — бесплатная академия разработчиков Burp Suite (популярного инструмента, используемого пентестерами) для обучения безопасности.
Кроме того, качай Burp Suite и ставь плагин JWT Editor, который поможет нам подписывать JWT-токены и реализовать некоторые атаки при прохождении.
Вместо одной функции вызвать другую — вот первая ошибка, которую можно допустить при проверке подписи. Звучит нелепо, но ее действительно легко совершить — особенно если ты только что познакомился с токенами и работаешь с ними впервые.
Источник: xakep.ru