Как стать автором
Обновить

Комментарии 2

Сколько я уже разрабатываю веб-сервисы, еще не разу не видел адектавно реализованого механизма аутентификации и авторизации. Возникает ощущение, что никто в компании не понимает, как использовать стандартные протоколы, включая кастомных Identity Provider-ов, например на базе того же IdentityServer4.

Я выделил следующие типы странностей при использовании OAuth2 и OIDC:

  • Отправкаid_token в API; Вроде как этот токен часть флоу аутентификации, форма токена вполне стандартная и не подразумевает разнообразие claims достаточных, для авторизации в API;

  • Отсутсвие верификации audience и scope при передаче access_token. Т.е. фактически токен может быть получен для другого API, но при этом нормально восприниматься любым API в системе. Это как будто бы нарушает принцип наименьших привелегий и оставляет кучу дыр в безопасности;

  • Пинг-понг токенами ( access_token и id_token ) между сервисами. Это развивает идеи предыдущего пункта. Т.е. в любой API можно идти с любым токеном, который выдан корректным identity provider. Данный подход начинает играть еще более интересными красками, когда где-то в середине "партии" токен истекает.

У меня накопились следующие вопросы по использованию OAuth2 и OIDC:

  1. Правильно ли я понимаю, что OAuth2 был придуман для реализации интеграций с другими сервисами? Т.е. реализуется сценарий делегирования, когда пользователь передает Сервису Б права доступа работы с данными в Сервисе А. Примеры пользовательских сценариев: пользователь логинится в почтовом аггрегаторе. Далее пользователь передает почтовому аггрегатору права доступа к почте пользователя используя OAuth2 + offline_access.

  2. Правильно ли я понимаю, что OIDC был придуман как замена SAML, и был реализован в качестве расширения к OAuth2?

    1. Корректен ли следующий пользовательский сценарий: пользователь нажимает на кнопку "Войти через Google" в моем веб-сервисе. Далее пользователь проходит аутентификацию в Google и идет обратный редирект в мое приложение.

      1. Далее если это классическое веб-приложение (ASP.NET Core, Ruby on Rails & etc), приложение опционально делает ассоциацию пользователя в БД с subject из id_token полученного от Google и например далее записывает состояние аутентификации в куки?

      2. Далее если это SPA (React, Angular), id_token остается в приложении и... тут мое понимание зачем это надо теряется. Возвращаемся к кейсу отправки id_token к API, что противоречит рекоммендациям OAuth2.

  3. Поясните, пожалуйста, как OAuth2 должен работать в экосистеме веб-сервиса? Предположим, если веб-сервис, в котором есть несколько приложений. Например, Client Portal (панель управления клиента) - Next.JS; Developer Portal (где клиенты могут регистрировать свои клиенты в Identity Provider и покупать лицензии на интеграции) - ASP.NET Core; и Partner Portal (где партнеры могут выставлять свои API в маркетплейс Developer Portal) - ReactJS SPA. Предположим что в системе есть свой Identity Provider, который реализует OAuth2 и OIDC.

    1. Как должны работать внутренние приложения? Каждое приложение должно иметь статический клиент в identity Provider?

    2. Нужно ли Next.JS и ASP.NET Core использовать OAuth2 и писать access_token и refresh_token в куки? Или достаточно использовать OIDC? Или комбинация?

    3. Как поступить с ReactJS SPA? Куда девать id_token после логина? Он вообще нужен в этом случае?

    4. Что насчет API? Каждое API должно иметь свой resource_id и scope-ы? Так же каждый API должен иметь список требуемых ему claims для работы (например, user.role или org.id).

    5. Значит ли это, что для каждого статического клиента нужно задать список API к которым он обращается? Этот список заранее известен, поэтому, кажется, это не должно стать проблемой?

    6. Необходимо ли проверять audience claim на стороне API? Какие последствия, если проигнорировать эту проверку?

    7. Как реализовать коммуникацию между микросервисами за пределами API Gateway? Гонять токены пользователя? Использовать client_credentials флоу? Если client_credentials флоу, то нужно ли ограничивать пермишены клиентов? Типа Profile Microservice может ходить в Subscriptions Microservice на чтение, и не может ходить в остальные сервисы? Или OAuth2 здесь вообще не нужен?

В общем такие вот вопросы. В целом на всех проектах, на которых я работал, это сделано "как-то" и работает соответствующе. Т.е. используются OAuth2 и OIDC для приложений, которые являются часть экосистемы, но одна команда везде использует id_token , другая access_token . В целом получается кое-как используется одно ключевое свойтво этого механизма - оба токена содержат subject для идентификации пользователия и механизм валидации издателя токена для аутентификации. Поэтому выглядит так, что все работает, включая SSO. А чтобы понять,какая комбинация параметров правильная и действительно безопасная для каждого конкретного пользовательского сценария - компетенций и знаний уже не хватает. А потом в вся система пропитывается таким миксом подходов, один костыль начинает подпирать другой и вот уже переделать это кажется невыполнимой задачей. Тем боеле, когда все еще не знаешь, а как правильно-то делать :) Это надо какую-то песочницу заводить и в ней ковыряться, воспроизводить ключевые системы, ключевые флоу, желательно в паре с экспертом в безопасности, в частности в OAuth2 и OIDC. Иначе получатся те же яйца, только в профиль.

Немного расширю своим виденьем, как это возможно надо делать, поправьте меня, если неправ.

  • OAuth2 только для внешних интеграций с нашим сервисом.

    • Пользователь делегирует доступ какому-то third-party сервису;

    • Пользователь делегирует доступ своему собственному сервису для партнерской интеграции; тут было бы неплохо как-то через клиент работать - т.е. создавать специальный партнерский API, регистрировать клиент в системе и присваивать напрмямую клиенту нужные для авторизации клеймы. И то скорее все не получится поместить в клеймы, скорее всего будет какая-то рантайм проверка.

  • Как альтернативу OAuth2 для обоих типов интеграций можно использовать API Keys (там свои нюансы с ротацией, но как вариант).

  • OIDC как Identity Provider для логина в другой сервис / приложение через наш сервис.

  • OIDC для предоставления SSO в нашей платформе.

    • Наши веб-приложения на ASP.NET Core / NextJS получают id_token, и сами идут в нужные микросервисы, чтобы собрать объект session и либо положить его в куки, либо положить session_id в куки, а сам session в хранилище сессий, чтобы поддерживать выход из определенных сессий. Далее все взаимодействия с внутренними микросервисами идут через это веб-приложение. Или другие варианты реализации, но суть в том, что будут использоваться secure cookie.

    • Наши SPA на ReactJS / Angular работают c BFF. BFF реализует такой же механизм, как и в предыдущем сервисе через куки и служит единой точкой запросов SPA.

    • Мобильные приложения работают так же работают с BFF. Пользователь логинится в webview, далее одно двух - session_id отправляется в мобильное приложение и хранится в зашифрованном виде; либо реализуется механизм jwt + refresh_token, с хранилищем активных refresh_tokens. Все необходимые запросы к нашему сервису приложение делает через BFF.

    • Сервисы между собой аутентифицируются по комбинации следующих параметров:

      • Изоляция сети

      • iAM: что-то типа Open Policy Agent (OPA) + Gatekeeper

    • Сервисы интегрируются с внешними сервисами по OAuth2.

    • Т.е. OAuth2 вообще никак не фигурирует во внутренних сервисах, кроме интеграций с внешним миром.

  • Альетернативно OIDC, можно реализовать механизм "попроще", когда сервер возвращает подписанный jwt на заранее сконфигугированные разрешенные callback_url, а дальше то же самое - session , session_id , secure cookie. По сути тот же OIDC (только замени id_token из флоу выше на jwt), клиенты точно так же заранее сконфигурированы и имеют callback_url. Но решение с jwt не тянет за собой ритуалов навязанных базисом OAuth2. Но тут надо подумать.

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

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации