Эта статья повествует о наиболее распространенном методе обмена токенами в потоке OpenID Сonnect: грантах [grants]. Обещаем – путешествие будет увлекательным, так что устраивайтесь поудобнее.
Интерлюдия
Периодически все мы сталкиваемся с ситуациями, когда приходится удостоверять свою личность, например, оплачивая счета, покупая билеты на самолет или даже посещая ночные клубы. Обычно это не проблема – паспорт есть у каждого. Получается, что власти страны, выдавшей паспорт, подтверждают личность получившего его гражданина.
Токен – это аналог паспорта в Интернете. Он содержит:
сведения о пользователе;
подпись эмитента;
срок действия.
Именно здесь в игру вступает OpenID Connect (OIDC). Этот протокол основан на спецификации OAuth2 и выступает сетевым аналогом паспорта со всеми необходимыми подписями, которые запрашиваются соответствующими проверяющими сервисами (также известными как relying parties, RPs). Токены выпускаются и подписываются поставщиками удостоверений (identity providers, IdPs) – этаким цифровым аналогом паспортного стола.
В итоге у нас есть проверяющая сторона, которая запрашивает токен, и поставщик идентификационных данных, который эти токены выпускает. Так что же дальше? Как получить токен и куда обращаться за ним?
Гранты
Существует множество грантов, т.е. способов взаимодействия с IdP с целью получения токена. Большинство из них типичны и широко распространены. Некоторые выделяются особенностями, связанными с IdP.
Информация о поддерживаемых грантах публична; получить ее можно, направив запрос на endpoint IdP:
curl 'https://your-idp.com/.well-known/openid-configuration' \
| jq .grant_types_supported
["authorization_code","refresh_token","urn:ietf:params:oauth:grant-type:device_code"]
А теперь давайте рассмотрим особенности, плюсы и минусы самых популярных грантов OIDC.
1. Грант Authorization Code
Грант по коду авторизации (Authorization Code) – это главная ценность протокола OIDC и основная причина, по которой он был вообще изобретен. В гранте участвуют все три стороны: пользователь, IdP и RP.
Пользователь инициирует процесс, обратившись к endpoint'у авторизации IdP и обменивает учетные данные на... образ токена (или, как мы его называем, код) вместо самого токена. Вооружившись кодом, пользователь идет к проверяющей стороне. Получив код, последняя запрашивает токен у IdP через соответствующий endpoint.
Плюсы:
Кроме IdP, никто не видит учетные данные пользователя;
RP получает токен непосредственно от доверенного IdP.
Минусы:
Процесс завязан на браузер пользователя, что невозможно при межмашинном взаимодействии;
Злоумышленники могут перехватить код;
Требуется трехсторонняя связь между всеми участниками процесса: пользователем, RP и IdP.
2. Proof Key for Code Exchange (PKCE)
PKCE – это дальнейшее развитие концепции предыдущего гранта, предотвращающее возможность кражи кода. В Authorization Code уязвимым звеном является пересылка кода пользователем проверяющей стороне. Откуда мы знаем, что это та самая RP? Злоумышленник может занять ее место, как это сделал волк, прикинувшись бабушкой в Красной шапочке. То есть принцип «Никому не верь» актуален всегда.
Впрочем, идея proof key не особенно сложна. Пользователь всего лишь должен сообщить RP, как расшифровать код, а IdP – как его зашифровать. И все!
Получить поддерживаемые методы проверки кода можно, запросив endpoint IdP:
curl 'https://your-idp.com/.well-known/openid-configuration' \
| jq .code_challenge_methods_supported
["S256","plain"]
3. Грант Implicit
Этот грант был разработан для аутентификации в одностраничных приложениях (SPA). Он похож на грант Authorization Code. Разница лишь в том, что при перенаправлении пользователь получает реальный токен в качестве GET-параметра, а не код (который образ токена, помните?).
Плюсы:
SPA не нужно делать POST-запрос к IdP (что может быть запрещено механизмом CORS).
Минусы:
Злоумышленники могут получить доступ к токенам в истории браузера;
Невозможно выпустить токен обновления (refresh token).
Удобство этого потока не столь существенно, поскольку он приводит к созданию огромной дыры в безопасности. Рекомендуем отказаться от неявного гранта в пользу гранта по коду авторизации.
4. Грант Password Credentials
Также пользователь может предоставить свои учетные данные проверяющей стороне, чтобы та получила токен от его имени. Однако раскрывать свои пароли кому бы то ни было – не самая лучшая идея. Этот грант можно использовать только в случаях, когда вы абсолютно уверены в RP. Однако, как упоминалось ранее, верить нельзя никому.
Этот грант существует только потому, что иногда можно поступиться безопасностью ради удобства, но все же использовать его не рекомендуется. Подумайте дважды, прежде чем им воспользоваться.
Плюсы:
Можно использовать для аутентификации CLI-приложений;
Можно использовать для межмашинной связи;
Хорошо подходит для автоматизации, так как со стороны пользователя требуется лишь один запрос.
Минусы:
Может произойти утечка данных;
Данный подход заставляет пользователей делиться своими учетными данными с кем-то кроме IdP.
5. Грант Client Credentials
Этот грант позволяет получить токен проверяющей стороне. Нечто вроде паспорта для паспортного стола.
Пользователь в процессе не участвует. Такой токен наделяет полномочиями саму RP – например, на осуществление дополнительных обращений на API IdP.
Плюсы:
Интересная возможность.
Минусы:
Этот грант не касается пользователей, так что нам он не особо интересен.
6. Грант Refresh Token
Наши паспорта действительны на протяжении многих лет, но представьте себе паспорт, срок действия которого истекает через 5 или 10 минут. В реальной жизни это было бы похоже на ад и нам приходилось бы получать новый паспорт всякий раз, когда возникает необходимость удостоверить личность (например, при покупке авиабилетов).
Авиакомпании всегда хотят самые свежие фотографии и данные. Именно поэтому срок действия столь короткий. По той же причине процедура обновления должна быть максимально простой, чтобы пользователи не потеряли рассудок от бюрократии и проволочек. То есть она должна выглядеть примерно так: «Привет! Это снова я. Пришли мне, пожалуйста, новый паспорт».
К счастью, такая процедура существует и называется Refresh Token. Этот специальный токен можно поменять на новый идентификационный токен без участия пользователя.
Плюсы:
Удобство;
Refresh Token – это токен длительного действия, который отправляется исключительно в IdP, а это самый безопасный способ получения токена.
Минусы:
Его можно использовать только для продления срока действия токена;
Требуется доступ к IdP.
7. Грант Device Authorization
«Хорошо, – скажете вы, – но что, если мне нужен паспорт для холодильника, микроволновки или пылесоса?» Ура! Протокол OIDC широко применяется и в Интернете вещей. Единственная сложность – как получить токен, если у холодильника нет браузера или терминала?
Прежде всего устройство должно знать URL-адрес, чтобы инициировать аутентификацию. Для этого следует послать запрос на discovery endpoint поставщика удостоверений (IdP):
curl 'https://your-idp.com/.well-known/openid-configuration' \
| jq .device_authorization_endpoint
https://your-idp.com/oauth2/v1/device/authorize
После запроса на device authorization endpoint IdP сгенерирует код устройства вместе с проверочной ссылкой для подтверждения его аутентификации. Эта ссылка будет передана на устройство.
С этого момента устройство начинает одновременно:
Посылать запросы с кодом устройства на соответствующий endpoint с целью обменять его на токен;
Выводить на экран проверочную ссылку.
После того как пользователь нажмет на проверочную ссылку, устройство получит токен.
Плюсы:
Класс! Можно аутентифицировать устройства!
Минусы:
Отныне вам придется покупать исключительно дорогую «умную» бытовую технику.
Заключение
В этой статье кратко рассмотрены наиболее распространенные гранты OIDC и типичные сценарии их применения.
TLDR: в 99% случаев достаточно гранта Authorization Code, дополненного PKCE и refresh-токенами.
Расширяемость протокола OIDC позволяет изобретать кастомные гранты и декларировать их поддержку при обращении на discovery endpoint. Я умышленно обошел вниманием CIBA – это интересный, многообещающий, но довольно «сырой» грант, который пока не поддерживается популярными провайдерами OIDC, такими как Okta или Auth0.
Надеюсь, эта статья помогла вам лучше понять процесс аутентификации в целом и процедуру получения токена в частности. Оставайтесь на связи!
P.S.
Эта же статья доступна и на английском языке в блоге Flant. Там же можно подписаться на технические материалы от наших инженеров, которыми легко делиться с ИТ-коллегами со всего мира.
Читайте также в нашем блоге:
Комментарии (3)
JenoOvchi
17.06.2022 13:15+2Честно говоря не самая удачная статья - многие важные моменты упущены, а схемы не точны. Вот в этой статье принцип получения токена и его обновления описаны гораздо подробнее и понятнее: https://habr.com/ru/company/flant/blog/475942
nabokihms Автор
18.06.2022 11:38+3Добрый день! Мне тоже нравится статья, которую вы привели в пример. Она более всеобъемлющая, да и картинки там очень хорошие.
Статья, которая я написал, более узконаправленная, сфокусированная лишь на небольшом кусочке OIDC. Она должна отвечать на вопросы по типу: "А как мне получить токен, если у меня два сервера, на которых нет браузера?" Изначально она была страницей документации для dexidp.io, в разработке которого мы принимаем участие, но получилась более художественной, чем нужно.
В любом случае, спасибо большое за обратную связь!
VitalySh
Статья хорошая, спасибо!
В свое время потратил много времени, чтобы разобраться со всеми тонкостями OAuth 2.0 и OIDC, но некоторые вещи всё ещё кажутся избыточными и не очень понятными.
Моя проблема в том, что мне важно понимать смысл этих всех ухищрений. То как они работают с функциональной точки зрения - понятно. Но они создавались с какой-то целью, чтобы противостоять каким-то уязвимостям. Очень мало в подобных статьях пишут именно о векторах атаки, как и каким образом данные могут быть скомпрометированы и применены в реальной жизни.
Если бы это раскрывалось в стиле - вот этот сервис не использует PKCE, а значит его можно атаковать вот таким-то способом (и подробное описание эксплуатации уязвимости) - было бы очень круто и полезно почитать.