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

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

Хотя JWT обычно используется для управления авторизацией, идея JWT на самом деле совсем другая - для обмена информацией! Существует открытая спецификация отраслевого стандарта под названием RFC 7519, в которой описывается, как должна быть структурирована JWT и как ее использовать для обмена информацией или претензиями, как это обычно называется. Но поскольку JWT так широко используется для авторизации, давайте сосредоточим наше внимание в этой статье именно на этом.

Необходимость авторизации

Итак, вы хотите авторизовать свое веб-приложение? Какие у вас есть варианты? Помимо JWT, есть еще множество опций, включая идентификаторы сеансов. Во всех этих механизмах авторизации виновато одно - HTTP. HTTP - это протокол без сохранения состояния. Это означает, что каждое взаимодействие в HTTP должно содержать всю информацию, необходимую для этого взаимодействия. Ничего не помнят раньше. Состояние не поддерживается по нескольким запросам.

Во всех этих механизмах авторизации виновато одно - HTTP.

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

Итак, если у вас есть серверное приложение со страницами P1 и P2, доступными только определенным пользователям. Вы сообщаете серверу через HTTP, кто вы и какая страница вам нужна. Сервер авторизует вас и, возможно, предоставит вам нужную страницу. Но если бы вы ответили другим запросом, сервер не знал бы, кто вы на этот раз, потому что он не «помнит» ваш предыдущий запрос. При каждом взаимодействии вы должны предоставлять все детали и информацию, необходимые для этого взаимодействия. Нет зависимости от предыдущей информации.

Теперь вы можете сказать: «Подожди. У меня не было такого опыта работы с веб-приложениями ». Например, вы можете войти на банковский веб-сайт со своим идентификатором пользователя и паролем, а затем, когда вы перейдете на страницу своих учетных записей, на веб-сайте не появится сообщение« Подожди, кто ты? » Веб-сайт знает, кто вы! Как оно это делает?

Есть несколько способов, которыми веб-приложения управляют и запоминают сеансы, и два популярных способа, которыми это делается, используют так называемые токены. Два популярных варианта:

  1. Использование токенов сеанса
  2. Использование веб-токенов JSON или JWT.

Давайте разберемся с ними обоими, чтобы вы действительно поняли, как работает JWT.

Понимание авторизации на основе сеанса

Приведу аналогию. Допустим, у клиента есть запрос в службу поддержки. Он звонит им и рассказывает, в чем его проблемы, скажем, с продуктом. Представитель пытается выполнить некоторые действия по устранению неполадок, и когда ничего не помогает, он говорит: «Хорошо, позвольте мне передать это в какой-нибудь другой отдел, и они могут помочь. Пожалуйста, перезвони завтра ».

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

Это своего рода то, что происходит с аутентификацией с использованием токенов сеанса. При аутентификации сервер создает сеанс и сам отслеживает его. Он создает идентификатор сеанса для связи с этим сеансом и передает его вам. Это похоже на заявку в службу поддержки в только что рассмотренном примере. Впоследствии клиент передает этот токен серверу как часть * каждого * запроса, и сервер просматривает его и определяет, кто является клиентом. (Общий подход - сохранить идентификатор сеанса в файле cookie, чтобы он автоматически добавлялся в заголовок файла cookie при каждом последующем запросе). Поскольку серверу обычно приходится обслуживать несколько клиентов одновременно, передача каждому клиенту своего идентификатора сеанса делает это удобным. Сервер всегда знает, кто является клиентом, и может искать информацию на основе этого единственного токена.

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

Проблема с идентификаторами сеанса

Самая большая проблема в том, что этот подход предполагает что-то - что всегда существует только один монолитный сервер веб-приложение. Раньше так было, как правило, в прошлом. Но в наши дни это уже не так.

Подход с использованием идентификатора сеанса предполагает что-то - что всегда есть только один монолитный сервер веб-приложение.

У вас есть несколько серверов, которые разделяют нагрузку, которые находятся за балансировщиком нагрузки. Когда поступает запрос, балансировщик нагрузки решает, на какой сервер направить запрос. Итак, вот в чем проблема. Пользователь мог бы направить свой запрос на вход на один сервер, но следующий запрос проходит через балансировщик нагрузки на совершенно другой сервер. Теперь этот новый сервер не знает об этом предыдущем обмене.

Хорошо, решение очевидно. Вы вводите общий кеш сеанса, в котором все эти серверы сохраняют сеансы и ищут токены сеансов. Это типичный вариант использования кеша Redis именно по этой причине. Но это сложно!

«Переключаемая» модель

Хорошо, а теперь предложим альтернативную модель. Вспомните аналогию со службой поддержки, которую я вам говорил. Допустим, сотрудники службы не поддерживают состояние. Клиент подходит к отделу обслуживания, и агент спрашивает его, что не так, и он говорит им. Сервисный парень говорит: «Хорошо, мы поработаем над этим. Приходи завтра снова ».

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

Вот идея. Вместо того, чтобы регистрировать обращение в своей системе и сообщать клиенту номер обращения, вы записываете все детали взаимодействия на листе бумаги и передаете его клиенту и говорите: «Верните его с собой в следующий раз. и передайте его представителю клиента, с которым вы разговариваете. Они могут прочитать это, понять и получить все подробности ».

Это отличие от предыдущей модели. Представитель клиента не сообщает клиенту идентификатор токена, который относится к деталям. Представитель клиента сам сообщает заказчику подробности. Должен ли представитель службы поддержки что-нибудь помнить, если это произойдет? Ну нет. Ответственность за получение этого листка бумаги для последующего взаимодействия со службой поддержки лежит на заказчике. Сервисной службе ничего запоминать не нужно!

Это хорошо, но у этого подхода есть недостаток. Допустим, клиент приносит лист бумаги с историей проблем. Насколько ему доверяет торговый представитель? Это может быть злоумышленник, который берет лист бумаги и записывает полную историю плохого обслуживания клиентов и обращается за халявой из-за плохого обращения. Вы должны сделать запись истории достоверной!

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

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

Маркер не является идентификатором, который ссылается на состояние сервера. Токен - это сама ценность! Это объект JSON, содержащий всю информацию. Это веб-токены JSON!

Веб-токен JSON не является идентификатором, который ссылается на состояние на сервере. Токен - это сама ценность!

Проблема безопасности решается путем подписания токенов, которые обрабатываются каждый раз. Когда пользователь аутентифицируется, сервер просто не отправляет никаких объектов JSON. Он отправляет что-то в специальном подписанном формате. Там есть подпись. Итак, когда клиент отправляет следующий запрос, подписанный JWT отправляется обратно на сервер. Сервер проверяет подпись и доверяет ей, только если она действительна.

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

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