IdentityServer4. Основные понятия. OpenID Connect, OAuth 2.0 и JWT

  • Tutorial

Этим постом я хочу открыть ветку статей посвященную IdentityServer4. Начнем мы с основных понятий.


Самым перспективным на текущий момент протоколом аутентификации является OpenID Connect, а протоколом авторизации (предоставления доступа) является OAuth 2.0. IdentityServer4 реализует эти два протокола. Он оптимизирован для решения типичных проблем безопасности.


OpenID Connect — это протокол и стандарт аутентификации, он не дает доступ к ресурсам (Web API), но т.к. он разработан поверх протокола авторизации OAuth 2.0, он позволяет получить параметры профиля пользователя как будто вы получили доступ к ресурсу UserInfo.

JWT (JSON Web Token) представляет собой веб-стандарт, который определяет способ передачи данных о пользователе в формате JSON в зашифрованном виде.

OAuth 2.0 (RFC 6749) — это протокол и стандарт авторизации. Он позволяет приложениям получить доступ к защищенным ресурсам, например к Web API.

Взглянем на диаграмму обращения к защищенному ресурсу и разберемся с основными шагами и принятой терминологией:


is4


  1. Клиент запрашивает у пользователя разрешение пройти авторизацию от его имени. Клиент — это клиентское приложение обращающиеся к защищённым ресурсам от имени владельца ресурсов. Ресурс — это все наши защищенные сервисы Web API.


  2. User разрешает клиентскому приложению пройти авторизацию от его имени, например, вводит логин и пароль. Логин и пароль будут являться грантом авторизации для клиентского приложения. User (владелец ресурса) — программа или человек, который может выдать доступ к защищённым ресурсам, например, путем ввода логина (username) и пароля (password);


  3. Клиентское приложение запрашивает токен доступа у IdentityServer4 путём предоставления информации о самом себе (client_id, client_secret), предоставления разрешения на авторизацию от пользователя (username, password) и предоставления grant_type и scope. Затем сервер авторизации проверяет подлинность клиента и реквизиты владельца ресурса (логин и пароль).


    Протокол OAuth 2.0 проводит аутентификации не только пользователя, но и клиентского приложения, осуществляющего доступ к ресурсам. Для этого протокол предусматривает такие параметры как client_id и client_secret.
    сlient_id — это идентификатор клиентского приложения, используемый IdentityServer4 для поиска информации о клиенте.
    client_secret является аналогом пароля для клиентского приложения и используется для аутентификации клиентского приложения на IdentityServer4. Секрет клиента должен быть известен только приложению и API. Исходя из вышесказанного делаем вывод что IdentityServer4 должен знать о своих клиентах.

  4. Если подлинность приложения подтверждена и разрешение на авторизацию действительно, IdentiryServer4 создаёт access-токен (токен доступа) для приложения и необязательный ключ обновления (refresh-токен). Процесс авторизации завершён. Если запрос недопустимый или несанкционированный, то сервер авторизации возвращает код с соответствующим сообщением об ошибке.


  5. Клентское приложение обращается за данными к защищенному Web API, предоставляя при этом токен доступа для авторизации. Если код ответа сервера ресурсов 401, 403 или 498, то токен доступа, используемый для аутентификации, недействителен или просрочен.


  6. Если токен действителен, Web API предоставляет данные приложению.



Типы токенов


Зарегистрированным в IdentityServer4 клиентам позволено запрашивать у IdentityServer4 identity-токен, access-токен и refresh-токен.


  • identity-токен (токен идентификации) — результат процесса аутентификации. Содержит идентификатор пользователя и информации о том, как и когда пользователь проходит аутентификацию. Можно расширить своими данными.
  • access-токен (токен доступа) — передается защищенному API и используется им для авторизации (разрешения доступа) к своим данным.
  • refresh-токен (токен обновления) — необязательный параметр, который сервер авторизации может возвратить в ответ на запрос токена доступа.

Введем еще два понятия:


Authenticatation Server Url — конечная точка для получения ключа доступа. Все запросы на предоставление и возобновление ключей доступа будем направлять на этот URL-адрес.


Resource Url — URL-адрес защищенного ресурса, по которому нужно обращаться, чтобы получить доступ к нему, передавая ему ключ доступа в заголовке авторизации.


Запрос ключа доступа


Для запроса ключа доступа клиент делает POST запрос к конечной точке IdentityServer4 со следующим заголовком


'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json',
'Expect': '100-continue'

и передавая следующие параметры:


'grant_type' : 'password',
'username' : login,
'password' : password,
'scope' : 'scope',
'client_id' : 'client_id',
'client_secret' : '{client_secret}'

username, password, client_id и client_secret были разобраны выше. Разберём остальные параметры:


grant_type — тип гранта или тип разрешения на авторизацию. Тип разрешения на авторизацию зависит от используемого приложением метода запроса авторизации, а также от того, какие типы разрешения поддерживаются со стороны API. В нашем случае он будет иметь значение password, что согласно спецификации OAuth 2.0 соответствует гранту реквизитов доступа владельца ресурса (авторизация по логину и паролю).


Протокол OAuth 2.0 определяет следующие типы грантов требующие обязательного взаимодействие с пользователям:


  • код авторизации (authorization code). Является одним из наиболее распространённых типов разрешения на авторизацию, т.к. хорошо подходит для серверных приложений (server-side applications), где исходный код приложения и секрет клиента не доступны посторонним;
  • неявный (implicit). Неявный тип разрешения на авторизацию используется мобильными и веб-приложениями, где конфиденциальность секрета клиента не может быть гарантирована;

И типы грантов, которые могут выполняться без интерактивного взаимодействия с пользователям:


  • реквизиты владельца ресурса (resource owner). Этот тип разрешения стоит использовать только в том случае, когда клиентское приложение пользуется доверием пользователя и пользователь спокойно относится к вводу своего логина и пароля. Этот тип разрешения должен использоваться только в том случае, когда другие варианты не доступны. Данный тип разрешения удобен для корпоративных клиентов, которые в рамках своей системы уже использовали учетные данные пользователя и хотят перейти на OAuth 2.0.
  • учетные данные клиента. Используются при доступе приложения к API. Это может быть полезно, например, когда приложение хочет обновить собственную регистрационную информацию на сервисе или URI перенаправления, или же осуществлять доступ к другой информации, хранимой в аккаунте приложения на сервисе, через API сервиса.

scope — это необязательный параметр. Он определяет область видимости. Токен доступа, возвращенный сервером, будет обеспечивать доступ только к тем службам, которые входят в эту область. Т.е. мы можем несколько служб объединить под одним scope и если клиент получает ключ доступа к этому scope он получает доступ ко всем этим службам. Также scope может использоваться для ограничения прав авторизации (например, доступ на чтение или запись)

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

    –3

    Статья хорошая, я бы даже сказал отличная. Важное дело делаете — продолжайте освещать эту тему, а то в Интернете каша полная по ней, полнейшая путаница на stack overflow и 90% людей не понимают как это работает и как должно работать. Страшно подумать сколько уязвимостей сейчас существует из-за неправильно настроенной авторизации на сайтах.


    И самое печальное, что в 2020 году до сих пор нет готовых решений plug and play, которые не требуют глубоких технических навыков и программирования для внедрения OAuth2 и Open ID Connect. Но есть перспективная тенденция: SECaaS, и например наша некоммерческая организация готовит SECaaS платформу которая в этом году произведёт революцию в этой сфере. И она независима (хоть и поддерживает/совместима) от OAuth2 и Open ID Connect.

      0

      Какая замечательная статья. Как раз разбирался в этой теме. Все статьи до этой были либо алверхностны либо запутанными и не понятными

        0

        Userinfo — защищённый ресурс, у него не должно быть права подписи токена, следовательно он не должен отвечать в jwt формате.

          0
          Нужно цитировать всю фразу до конца (https://openid.net/specs/openid-connect-core-1_0.html#UserInfo):
          Конечная точка UserInfo является защищенным ресурсом OAuth 2.0, который возвращает утверждения о прошедшем проверку подлинности конечного пользователя. Чтобы получить запрошенные утверждения о конечном пользователе, клиент отправляет запрос конечной точке UserInfo, используя токен доступа, полученный посредством аутентификации OpenID Connect. Эти утверждения обычно представлены объектом JSON, который содержит коллекцию пар имя и значение для утверждений
          JWT — стандарт для создания токенов доступа, имеющий json нагрузку. Где тут противоречие, непонятно. Да и сам OAuth ничего не имеет против — www.oauth.com/oauth2-servers/signing-in-with-google/verifying-the-user-info
          0

          В JWT данные (заголовок и пэйлоад) не шифруются, а передаются в открытом виде.

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

              Обычно это не данные шифрования, а криптохэш, электронная подпись.

            0

            Все прекрасно и хорошо с OpenID, JWT и OAuth пока logout не нужно делать. Как с logout дела обстоят в identity server? Особенно когда есть кластер из нескольких серверов?

              –2
              Видимо, это как раз и есть пример некомпетентности и разнообразия информации в интернете: logout — это прерогатива авторизации сессии, а JWT востребован только в запросе… нет токена — нет авторизации. Да и то, токен (что access, что refresh) имеет обязательное поле expire on.
                0
                Хочется что-то такое ехидное сказать по поводу компетентности, но я не буду, потому что воспитанный :)

                Меня интересует чисто практическая вещь. Механизм инвалидации access и refresh токена есть или нет в Identity Server 4? Особенно в ситуации, когда имеется несколько апп серверов.
                0

                А что значит логаут для вас в этом контексте?

                  0
                  Логаут означает завершить все сессии, после этого действия токены авторизации выданные ранее должны отвергаться системой как неверные.
                    –1

                    Это больше на бан похоже. Собственно во внутренних корпоративных системах очень частое требование от ИБ: "моментально" банить учетки сотрудников не то, что при подписании приказа об увольнении, а при любом подозрительном поведении, например активностях похожих на слив данных конкурентам или изучении данных клиентов, явно не относящихся к текущим задачам (а-ля "а пробью-ка я девушку, у которой номер телефона взял вчера, вдруг наш клиент").


                    И тут плюсы JWT превращаются если не в минусы, то в ограничения, для обхода которых нужно "убивать" плюсы. Например, таки делать запрос к базе данных при проверки токена. Подсластить пилюлю можно заменой тяжелого SQL запроса быстрым к key-value типа редиса чуть ли не с веб-сервера типа nginx, чтобы доходил до апп-сервера уже не просто провалидированный, но и проверенный на бан. А то и прямо в конфиге nginx вести список забаненных.

                      0

                      Нет, на бан это не похоже, хотя проблемы логаута и бана и правда общие.

                –1
                Инструмент созданный гуглем для убийства почты, вот что это такое.

                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                Самое читаемое