OpenID Connect: правильный способ аутентификации пользователя - токен идентификатора или токен доступа? Обновить токены ID?

В нашем веб-приложении (ASP.NET) мы используем OpenID Connect с потоком кода авторизации:

  1. Пользователь перенаправляется к провайдеру удостоверений (например, Azure AD), аутентифицируется,
  2. Код авторизации отправляется обратно на страницу в нашем веб-приложении.
  3. Затем наше веб-приложение извлекает токен обновления, токен идентификатора и токен доступа с сервера идентификации, используя код авторизации. Они хранятся на клиентах как файлы cookie (для флага HttpOnly установлено значение true). Это сделано для того, чтобы избежать зависимости от состояния сервера, если балансировщик нагрузки перенаправляет пользователя на другой веб-сервер.
  4. Когда пользователь получает доступ к странице, мы проверяем подпись и срок действия токена идентификатора, а также проверяем утверждение, которое мы используем для идентификации (например, адрес электронной почты или UPN), по базе данных пользователей в нашем приложении.

Это работает - за исключением того, что мы не можем обновить токен идентификатора, поэтому время ожидания пользователей истекает через 1 час, что требует нового входа в систему. Согласно спецификациям OpenID Connect, при обновлении токенов с помощью конечной точки токена не все поставщики OpenID Connect будут предоставлять новый токен ID.

Альтернативы, которые мы видим на данный момент:

  1. Don't use the ID token at all. Use the access token to query the UserInfo endpoint for the user's claims, and cache it on the server (on cache miss, e.g. if routed to a different web server - simply use the provided access token from the cookie to request the UserInfo again). Since the access tokens can be refreshed, this would probably work fine.
    • Pros: We get a properly refreshed token, that are validated by the server.
    • Минусы: не все утверждения (например, aud и iss) предоставляются конечной точкой UserInfo, по крайней мере, для Azure AD.
  2. Don't verify expiry of the ID token, just that it's not older than e.g. 12 hours.
    • Pros: Simple, requires little effort to change from the current behavior. Has all the claims that we also have today.
    • Минусы: Может быть угроза безопасности? Комментарии?

Итак, каков рекомендуемый способ сохранить логин пользователя в течение более длительного периода времени? Будет ли подходящим решением использование токена доступа с конечной точкой UserInfo?


person Hallgeir    schedule 12.11.2018    source источник
comment
Используете ли вы токен доступа для доступа к некоторым удаленным ресурсам из серверной части приложения? Идентификация пользователя - единственное, что вам нужно от токенов (и OAuth2 в целом)? Вам нужна функция единого выхода в Azure AD?   -  person Ján Halaša    schedule 14.11.2018
comment
Нет, в настоящее время мы только используем токен доступа для конечной точки UserInfo. Наш основной вариант использования OpenID Connect - это аутентификация пользователя - в настоящее время авторизация выполняется нашим сервером другими способами.   -  person Hallgeir    schedule 17.11.2018


Ответы (2)


Это зависит от того, как используется токен идентификации. Обычно это только для клиента. Это позволяет клиенту аутентифицировать пользователя на основе обязательного утверждения sub. Его нельзя использовать для авторизации. Для этого нужен токен доступа.

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

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

Для доступа к конечной точке UserInfo вам понадобится токен доступа. Отсутствующие утверждения aud и iss могут не быть проблемой, поскольку вы запрашиваете токен самим органом. Мне кажется, что на этом этапе известны эмитент и аудитория.

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

Спецификации требуют, чтобы вы подтвердили полученный токен, как описано. Но если вы не получаете новый id_token, зачем снова проверять текущий? Возможно, он не обновлен, но уже подтвержден.

Итак, IMO оба варианта в порядке, хотя я думаю, что первый вариант более распространен. Вероятно, что id_token сбрасывается после использования. Поскольку токен доступа используется для доступа к ресурсам (включая конечную точку UserInfo), а токен обновления - для обновления токена доступа.

Одно замечание, согласие пользователя используется как фильтр. Если пользователь не дает согласия на информацию профиля, она вообще не будет доступна.

person Ruard van Elburg    schedule 13.11.2018
comment
Большое спасибо за понимание! Мы выбрали вариант №2 - мы проверяем подпись токена идентификатора при каждом запросе, чтобы убедиться, что он не был подделан, но у нас есть собственная проверка истечения срока действия на основе настройки в нашем приложении. Причина, по которой мы выбрали этот путь, заключалась, как вы сказали, в том, что мы знаем, что токен был действителен на момент выпуска, поэтому повторная его проверка (кроме подписи) не имела большого смысла. - person Hallgeir; 17.11.2018

Для начала нужно понять назначение каждого токена. Идентификационный токен используется клиентом (приложением). Он содержит утверждения, которые вы можете проверить для аутентификации конечного пользователя (аутентификация).

Токен доступа нужен для авторизации. Он предназначен для использования с защищенным ресурсом (например: - API, защищенный токенами OAuth 2.0). Когда API получает токен, он должен проверить его и предоставить доступ.

Токен обновления предназначен для обновления токена доступа. Теперь OpenID Connect, являющийся расширением OAuth 2.0, позволяет использовать токен обновления. Но, как вы выяснили, идентификационный токен может обновляться, а может и не обновляться. Я лично видел, как Auzre AD не обновляет токен идентификатора.

Лучшее решение - использовать сеанс между интерфейсом и сервером. Вы устанавливаете этот сеанс после проверки токенов из запроса токенов. Хранилище сеанса может содержать изначально отправленный токен доступа. Наряду с этим сохраните токен обновления. Вы можете просто подтвердить токен идентификатора и отказаться от него (при условии, что вы сохраняете всю необходимую информацию для сеанса). Убедитесь, что это сеанс HttpOnly и Secure (только Https). Срок действия сеанса может быть равен сроку действия токена доступа.

По истечении срока действия токена доступа вы можете использовать токен обновления для получения нового токена. И всякий раз, когда вы хотите, ваш бэкэнд может добавлять токен доступа к запросам API из бэкэнда. Таким образом, вы никогда не открываете токен доступа и не обновляете токен для внешнего интерфейса.

person Kavindu Dodanduwa    schedule 13.11.2018
comment
Привет, большое спасибо за ваш вклад в это. Проблема здесь в том, что мы не хотим полагаться на состояние на стороне сервера, что в основном означает создание сеанса, поскольку, если мы перенаправляемся на другой веб-сервер балансировщиком нагрузки, сеанс должен быть настроен снова, поэтому Идентификационный токен должен быть (или, по крайней мере, должен быть) снова проверен. - person Hallgeir; 17.11.2018