OpenID Connect

Что такое OpenID Connect?

OpenID Connect расширяет протокол OAuth, добавляя специальный слой идентификации и аутентификации, который накладывается поверх базовой реализации OAuth. Он добавляет некоторую простую функциональность для лучшей поддержки сценариев аутентификации с использованием OAuth.

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

Эти примитивные механизмы аутентификации OAuth были далеки от идеала. Клиентское приложение никак не могло узнать, когда, где и как пользователь проходил аутентификацию. Каждая реализация была по сути «самодельным костылём», и не существовало стандартизированного способа запроса данных пользователя для этих целей. Чтобы корректно поддерживать OAuth, клиентские приложения должны были настраивать отдельные механизмы OAuth для каждого провайдера, с разными конечными точками, уникальными наборами scope и т.д.

OpenID Connect решает множество этих проблем, добавляя стандартизованные функции, связанные с идентификацией, чтобы аутентификация через OAuth работала более надёжно и единообразно.

Как работает OpenID Connect?

OpenID Connect органично встраивается в обычные процессы OAuth. С точки зрения клиентского приложения ключевое отличие в том, что появляется дополнительный, стандартизованный набор scope, одинаковый для всех провайдеров, а также новый тип ответа: id_token.

Роли

Роли при OpenID Connect практически такие же, как у стандартного OAuth, но спецификация использует немного другую терминологию:

  • Relying party — приложение, запрашивающее аутентификацию пользователя. Аналог клиентского приложения OAuth.

  • End user — пользователь, который проходит аутентификацию. Аналог владельца ресурса в OAuth.

  • OpenID provider — сервис OAuth, настроенный для поддержки OpenID Connect.

claims и scopes

Термин «claims» обозначает пары ключ:значение, описывающие информацию о пользователе на сервере ресурсов. Например: "family_name":"Montoya".

В отличие от базового OAuth, где набор scopes уникален для каждого провайдера, все сервисы OpenID Connect используют единый набор scopes. Чтобы воспользоваться OpenID Connect, клиентское приложение должно указать область openid в запросе авторизации. Затем можно добавить одну или несколько стандартных областей:

  • profile

  • email

  • address

  • phone

Каждая из этих областей соответствует доступу на чтение к подмножеству claims о пользователе, определённых в спецификации OpenID. Например, указание openid profile даст клиентскому приложению доступ к набору данных о личности пользователя: family_name, given_name, birth_date и т. д.

ID token

Другое ключевое дополнение OpenID Connect — это тип ответа id_token. Этот токен возвращается в формате JWT, подписанного с применением JWS. Полезная нагрузка токена JWT содержит список claims на основе изначально запрошенных областей, а также сведения о том, когда и как пользователь был аутентифицирован сервисом OAuth в последний раз. Клиентское приложение использует эту информацию для решения, считать ли пользователя аутентифицированным. Основное преимущество использования id_token — сокращение количества запросов между клиентским приложением и сервисом OAuth, что повышает общую производительность. Вместо того чтобы сначала получать access token, а затем отдельно запрашивать пользовательские данные, ID‑токен с этой информацией передаётся клиентскому приложению сразу после аутентификации пользователя.

В отличие от базового OAuth, который просто полагается на доверенный канал, целостность данных в ID‑токене обеспечивается криптографической подписью JWT. Поэтому использование ID‑токенов может помочь защититься от некоторых MITM атак. Однако, поскольку криптографические ключи для проверки подписи передаются по тому же сетевому каналу (чаще всего доступны по адресу /.well-known/jwks.json), некоторые атаки остаются возможными.

Помимо этого, OAuth поддерживает множественные типы ответов, поэтому вполне допустимо, если клиентское приложение отправляет запрос авторизации одновременно и с типом OAuth, и с типом OpenID Connect:

В этом случае клиентское приложение получит одновременно ID‑токен и либо код, либо токен.

Идентификация использования OpenID Connect

Если клиентское приложение активно использует OpenID Connect, это можно заметить в запросе авторизации. Самый надёжный признак — наличие области openid.

Даже если процесс входа сначала не кажется связанным с OpenID Connect, стоит проверить, поддерживает ли сервис OAuth эту функциональность. Для этого можно попробовать добавить область openid или изменить тип ответа на id_token и наблюдать, приведёт ли это к ошибке.

Как и в случае базового OAuth, также полезно изучить документацию провайдера OAuth на наличие сведений о поддержке OpenID Connect. Кроме того, вы можете получить доступ к конфигурационному файлу по стандартной конечной точке /.well-known/openid-configuration.

Уязвимости OpenID Connect

Спецификация OpenID Connect гораздо строже, чем у базового OAuth, поэтому вероятность уязвимых кастомных реализаций ниже. Однако, поскольку OpenID Connect — это лишь надстройка поверх OAuth, клиентское приложение или сервис OAuth могут по‑прежнему быть уязвимыми ко многим атакам на основе OAuth. Фактически вы могли заметить, что все лабораторные работы по аутентификации OAuth также используют OpenID Connect. В этом разделе мы рассмотрим некоторые дополнительные уязвимости, которые могут появляться из‑за дополнительных функций OpenID Connect.

Незащищённая динамическая регистрация клиента

Спецификация OpenID описывает стандартизованный способ, позволяющий клиентскому приложению регистрироваться у провайдера OpenID. Если поддерживается динамическая регистрация клиента, клиентское приложение может зарегистрироваться, отправив POST‑запрос на специальную конечную точку /registration. Обычно название этой конечной точки приводится в конфигурации и документации.

В теле запроса клиентское приложение передаёт ключевую информацию о себе в формате JSON. Например:

  • массив разрешённых redirect URI,

  • имя приложения,

  • конечные точки, которые приложение хочет использовать,

  • публичные ключи и т. п.

Пример запроса на регистрацию:

Провайдер OpenID обязан требовать аутентификацию клиентского приложения. В примере выше используется HTTP Bearer‑токен. Однако некоторые провайдеры позволяют динамическую регистрацию клиента без какой-либо аутентификации, что даёт злоумышленнику возможность зарегистрировать собственное вредоносное приложение. Последствия зависят от того, каким образом будут использоваться значения контролируемых атрибутов.

Например, если какое‑то из таких значений является URI, и провайдер OpenID его запрашивает, это может приводить к SSRF атакам второго порядка без дополнительных мер защиты.

Разрешение ссылочных запросов авторизации

До этого момента мы рассматривали стандартную схему подачи параметров авторизационного запроса через строку запроса. Некоторые провайдеры OpenID позволяют передавать параметры в виде JWT. Если эта возможность поддерживается, вы можете отправить один параметр request_uri, указывающий на JWT, содержащий остальные параметры OAuth и их значения. В зависимости от конфигурации сервиса OAuth параметр request_uri может стать вектором для SSRF.

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

Last updated