49.1. Безопасное проектирование модуля валидатора#

49.1. Безопасное проектирование модуля валидатора

49.1. Безопасное проектирование модуля валидатора #

Предупреждение

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

49.1.1. Обязанности Валидатора #

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

Validate the Token

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

Онлайн-валидация, обычно реализуемая через OAuth Token Introspection, требует меньше шагов от модуля валидации и позволяет централизованно отзывать токен в случае его кражи или неправильной выдачи. Однако, это требует от модуля выполнения как минимум одного сетевого запроса на каждую попытку аутентификации (все из которых должны быть завершены в течение настроенного authentication_timeout). Кроме того, ваш провайдер может не предоставлять конечные точки интроспекции для использования внешними серверами ресурсов.

Офлайн-валидация гораздо более сложна, обычно требуя от валидатора поддерживать список доверенных ключей подписи для провайдера, а затем проверять криптографическую подпись токена вместе с его содержимым. Реализации должны строго следовать инструкциям провайдера, включая любую проверку эмитента ("откуда этот токен?"), аудитории ("для кого этот токен?") и периода действия ("когда этот токен может быть использован?"). Поскольку нет связи между модулем и провайдером, токены не могут быть централизованно отозваны с использованием этого метода; реализации офлайн-валидатора могут пожелать установить ограничения на максимальную длину периода действия токена.

Если токен не может быть проверен, модуль должен немедленно завершить работу. Дальнейшая аутентификация/авторизация бессмысленна, если токен не был выдан доверенной стороной.

Authorize the Client

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

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

Хотя возможно установить авторизацию клиента без явных областей, используя внеполосные знания развернутой архитектуры, это исключает пользователя из процесса, что мешает ему обнаруживать ошибки развертывания и позволяет использовать такие ошибки незаметно. Доступ к базе данных должен быть строго ограничен только доверенными клиентами [17] если пользователям не предлагается запросить дополнительные области.

Даже если авторизация не удалась, модуль может выбрать продолжение извлечения информации аутентификации из токена для использования в аудите и отладке.

Authenticate the End User

Наконец, валидатор должен определить идентификатор пользователя для токена, либо запросив эту информацию у провайдера, либо извлекая её непосредственно из токена, и вернуть этот идентификатор серверу (который затем примет окончательное решение об авторизации, используя конфигурацию HBA). Этот идентификатор будет доступен в рамках сессии через system_user и будет записан в журналы сервера, если log_connections включен.

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

Обратите внимание, что анонимный/псевдонимный вход также возможен, если включено делегирование usermap; см. Раздел 49.1.3.

49.1.2. Общие рекомендации по кодированию #

Разработчики должны учитывать следующее при реализации проверки токенов:

Token Confidentiality

Модули не должны записывать токены или части токенов в журнал сервера. Это верно, даже если модуль считает токен недействительным; злоумышленник, который вводит клиента в заблуждение, заставляя его взаимодействовать с неправильным провайдером, не должен иметь возможность извлечь этот (в противном случае действительный) токен с диска.

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

Logging

Модули могут использовать те же средства ведения журнала, что и стандартные расширения; однако правила для вывода записей журнала клиенту несколько отличаются во время фазы аутентификации соединения. В общем, модули должны регистрировать проблемы проверки на уровне COMMERROR и возвращаться в нормальный режим, вместо использования ERROR/FATAL для разворачивания стека, чтобы избежать утечки информации неаутентифицированным клиентам.

Interruptibility

Модули должны оставаться прерываемыми сигналами, чтобы сервер мог корректно обрабатывать тайм-ауты аутентификации и сигналы завершения работы от pg_ctl. Например, блокирующие вызовы на сокетах обычно следует заменять кодом, который обрабатывает как события сокетов, так и прерывания без гонок (см. WaitLatchOrSocket(), WaitEventSetWait() и др.), а длительные циклы должны периодически вызывать CHECK_FOR_INTERRUPTS(). Несоблюдение этих рекомендаций может привести к неотзывчивым сеансам бэкенда.

Testing

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

Documentation

Реализации валидаторов должны документировать содержимое и формат аутентифицированного ID, который сообщается серверу для каждого конечного пользователя, так как администраторам баз данных может потребоваться использовать эту информацию для создания pg_ident карт. (Например, является ли это адресом электронной почты? организационным идентификационным номером? UUID?) Они также должны документировать, безопасно ли использовать модуль в delegate_ident_mapping=1 режиме, и какая дополнительная конфигурация требуется для этого.

49.1.3. Авторизация пользователей (Делегирование Usermap) #

Стандартным результатом модуля валидации является идентификатор пользователя, который сервер затем сравнит с любой настроенной pg_ident.conf сопоставлением и определит, имеет ли конечный пользователь право на подключение. Однако, OAuth сам по себе является фреймворком авторизации, и токены могут содержать информацию о привилегиях пользователя. Например, токен может быть связан с организационными группами, к которым принадлежит пользователь, или перечислять роли, которые пользователь может принимать, и дублирование этих данных в локальные карты пользователей для каждого сервера может быть нежелательным.

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

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

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



[17] То есть, "доверенный" в том смысле, что клиент OAuth и сервер Tantor SE контролируются одной и той же организацией. Примечательно, что поток авторизации устройства, поддерживаемый libpq, обычно не соответствует этому критерию, так как он предназначен для использования публичными/недоверенными клиентами.