Поделиться через


Настройка проверки подлинности носителя JWT в ASP.NET Core

Дэмиен Боуден

Проверка подлинности носителя JWT (JSON Web Token) обычно используется для API. Хотя он работает аналогично аутентификации cookie, поставщик удостоверений выдает JWT или токены при успешной аутентификации. Затем эти маркеры можно отправлять на другие серверы для проверки подлинности, в отличие от файлов cookie, которые отправляются только в выданный домен. JWT — это автономный маркер, который инкапсулирует сведения для ресурса API или клиента. Клиент, запрашивающий JWT, может запрашивать данные из ресурса API с помощью заголовка авторизации и маркера носителя.

Проверка подлинности носителя JWT обеспечивает:

  • Проверка подлинности: При использовании JwtBearerHandler токены типа Bearer необходимы для проверки подлинности. JwtBearerHandler проверяет токен и извлекает идентификацию пользователя из утверждений.
  • Авторизация: токены типа Bearer позволяют выполнять авторизацию, предоставляя набор утверждений, представляющих права пользователя или приложения, так же как и cookie.
  • Делегированная авторизация. Если маркер доступа для конкретного пользователя используется для проверки подлинности между API вместо маркера доступа на уровне приложения, этот процесс называется делегированной авторизацией.

"Для ознакомления с проверкой подлинности на основе токенов JWT, см. JSON Web Tokens.Просмотр или загрузка примера кода"

В этой статье рассматриваются следующие области:

  • Типы токенов
  • Использование токенов JWT для защиты API
  • Как OIDC/OAuth вписывается в это?
  • Реализация проверки подлинности маркера носителя JWT
  • Рекомендуемые подходы к созданию JWT

Типы токенов

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

  • Может привести к уязвимостям системы безопасности.
  • Подходят только для закрытых систем.

Мы рекомендуем использовать OpenID Connect 1.0 или стандарт OAuth для создания маркеров доступа, предназначенных для доступа к API.

Токены доступа

Маркеры доступа:

  • Строки, используемые клиентским приложением для выполнения запросов к серверу, реализующим API.
  • Может отличаться в формате. Различные API могут использовать разные форматы для токенов.
  • Можно зашифровать.
  • Веб-клиент или приложение пользовательского интерфейса с маркером доступа никогда не должно читать или интерпретировать маркер доступа.
  • Предназначены исключительно для выполнения запросов к API.
  • Обычно отправляются в API в качестве маркера доступа в заголовке запроса авторизации .

См . платформу авторизации OAuth 2.0

Маркеры доступа приложений и делегированные маркеры доступа

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

Мы рекомендуем использовать делегированные токены доступа пользователя при каждом участии пользователя. Подчиненные API могут запрашивать делегированный маркер доступа пользователей от имени прошедшего проверку подлинности пользователя.

Токены доступа с ограничениями для отправителя

Маркеры доступа могут использоваться как носительские токены или токены, ограниченные отправителем , для доступа к ресурсам. Маркеры, зависящие от отправителя, требуют, чтобы клиент, запрашивающий маркер, подтвердил владение закрытым ключом для его использования. Подтверждение владения закрытым ключом гарантирует, что маркер нельзя использовать независимо. Токены с ограничением отправителя можно реализовать двумя способами:

Токены идентификации

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

Маркеры идентификаторов никогда не следует использовать для доступа к API.

Другие токены

Существует множество типов маркеров, включая маркеры доступа и идентификатора, как указано в стандартах OpenID Connect и OAuth. Маркеры обновления можно использовать для обновления приложения пользовательского интерфейса без повторной проверки подлинности пользователя. Токены OAuth JAR могут безопасно отправлять запросы на авторизацию. Проверяемые потоки учетных данных используют типы JWT для выдачи или проверки учетных данных. Важно использовать маркеры в соответствии с спецификациями. Дополнительные сведения см. в ссылках на стандарты, приведенные далее в этой статье.

Использование токенов JWT для защиты API

При использовании токенов доступа JWT для авторизации API предоставляет или запрещает доступ на основе предоставленного токена. Если запрос не авторизован, возвращается ответ 401 или 403. API не должен перенаправлять пользователя поставщику удостоверений, чтобы получить новый маркер или запросить дополнительные разрешения. Приложение, потребляющее API, отвечает за получение соответствующего токена. Это обеспечивает четкое разделение проблем между API (авторизацией) и потребляющим клиентским приложением (аутентификацией).

Заметка

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

401 Несанкционированный доступ

401 Неавторизованный ответ указывает, что предоставленный маркер доступа не соответствует требуемым стандартам. Это может быть вызвано несколькими причинами, в том числе:

  • Недопустимая подпись: подпись токена не соответствует, что может указывать на возможную попытку подделки.
  • Срок действия: срок действия маркера истек и больше не является допустимым.
  • Неправильные заявления: критические заявления в токене, такие как аудитория (aud) или издатель (iss), отсутствуют или недопустимы.

Заметка

Из семантики HTTP RFC 9110: сервер, создающий ответ 401, должен отправить поле заголовка WWW-Authenticate (раздел 11.6.1), содержащее по крайней мере одну проблему, применимую к целевому ресурсу.

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

403 Запрещено

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

В ASP.NET Core можно применить авторизацию с помощью:

Требования и политики. Определите настраиваемые требования, например "Должен быть администратором" и свяжите их с политиками. Авторизация на основе ролей: назначение пользователям ролей, например "Администратор", "Редактор" и ограничение доступа на основе этих ролей.

Какая роль имеет OIDC и /или OAuth при использовании маркеров носителя?

Когда API использует маркеры доступа JWT для авторизации, API проверяет только маркер доступа, а не способ получения маркера.

OpenID Connect (OIDC) и OAuth 2.0 предоставляют стандартные безопасные фреймворки для получения токенов. Получение токена зависит от типа приложения. Из-за сложности приобретения маркеров безопасности настоятельно рекомендуется полагаться на следующие стандарты:

  • Для приложений, действующих от имени пользователя и приложения: OIDC — это предпочтительный вариант, который обеспечивает делегированный доступ пользователей. В веб-приложениях для повышения безопасности рекомендуется использовать поток кода конфиденциальности с ключом подтверждения для обмена (PKCE).
  • Если у приложения нет пользователя: поток учетных данных клиента OAuth 2.0 подходит для получения маркеров доступа к приложению.

Реализация проверки подлинности маркера носителя JWT

Пакет Nuget Microsoft.AspNetCore.Authentication.JwtBearer Nuget можно использовать для проверки маркеров носителя JWT.

Маркеры носителя JWT должны быть полностью проверены в API. Необходимо проверить следующее:

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

Для маркеров доступа OAuth 2.0 требуются следующие утверждения: iss, exp, aud, sub, client_id, iatи jti.

Если какие-либо из этих утверждений или значений неверны, API должен вернуть ответ 401.

Базовая проверка токена носителя JWT

Базовая реализация AddJwtBearer может проверить только пользовательскую группу и эмитента. Подпись должна быть проверена, чтобы токен мог быть надежным и не был изменен.

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(jwtOptions =>
{
	jwtOptions.Authority = "https://{--your-authority--}";
	jwtOptions.Audience = "https://{--your-audience--}";
});

Явная проверка JWT-токена

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

Явное определение параметров не требуется. Определения зависят от значений параметров утверждений маркера доступа и сервера безопасности маркеров, используемого для проверки маркера доступа. Если это возможно, следует использовать значения по умолчанию.

См. подробности MapInboundClaims о сопоставлении утверждений.

builder.Services.AddAuthentication()
.AddJwtBearer("some-scheme", jwtOptions =>
{
	jwtOptions.MetadataAddress = builder.Configuration["Api:MetadataAddress"];
	// Optional if the MetadataAddress is specified
	jwtOptions.Authority = builder.Configuration["Api:Authority"];
	jwtOptions.Audience = builder.Configuration["Api:Audience"];
	jwtOptions.TokenValidationParameters = new TokenValidationParameters
	{
		ValidateIssuer = true,
		ValidateAudience = true,
		ValidateIssuerSigningKey = true,
		ValidAudiences = builder.Configuration.GetSection("Api:ValidAudiences").Get<string[]>(),
		ValidIssuers = builder.Configuration.GetSection("Api:ValidIssuers").Get<string[]>()
	};

	jwtOptions.MapInboundClaims = false;
});

JWT с несколькими схемами

API часто необходимо принимать токены доступа от различных эмитентов. Поддержка нескольких издателей токенов в API может выполняться следующим образом:

  • Отдельные API: создание отдельных API с выделенными схемами проверки подлинности для каждого издателя.
  • AddPolicyScheme Этот метод может определить несколько схем проверки подлинности и реализовать логику для выбора соответствующей схемы на основе свойств токена (например, издателя, утверждений). Такой подход обеспечивает большую гибкость в рамках одного API.

Принудительное применение проверки подлинности носителя

Проверку подлинности с помощью SetDefaultPolicy можно использовать для всех запросов, даже к конечным точкам без атрибута [Authorize]. SetDefaultPolicy настраивает политику, используемую для конечных точек с атрибутом [Authorize], и уже по умолчанию требует проверки подлинности пользователей. Для получения дополнительной информации см. документацию по требованиям к аутентифицированным пользователям.

var requireAuthPolicy = new AuthorizationPolicyBuilder()
	.RequireAuthenticatedUser()
	.Build();

builder.Services.AddAuthorizationBuilder()
	.SetDefaultPolicy(requireAuthPolicy);

Атрибут авторизации также можно использовать для принудительной проверки подлинности. Если используются несколько схем, схема носителя обычно должна быть задана в качестве схемы проверки подлинности по умолчанию или указана с помощью [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme]).

Авторизация в контроллерах:

[Authorize]
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{

Авторизация в минимальных API:

app.MapGet("/hello", [Authorize] () => "Hi");

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

Использование стандартов

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

Использование асимметричных ключей

Асимметричные ключи всегда следует использовать при создании маркеров доступа. Открытый ключ доступен в известных конечных точках, а клиенты API могут проверить подпись маркера доступа с помощью открытого ключа.

Никогда не создавайте токен доступа из запроса с именем пользователя и паролем

Не следует создавать токен доступа из запроса имени пользователя или пароля. Запросы на ввод имени пользователя и пароля не проходят проверку подлинности и уязвимы для имперсонации и фишинговых атак. Маркеры доступа должны создаваться только с помощью потока OpenID Connect или стандартного потока OAuth. При переходе от этих стандартов может возникнуть небезопасное приложение.

Использование файлов cookie

Для безопасных веб-приложений серверная часть требуется для хранения маркеров доступа на доверенном сервере. Только защищённый, доступный через HTTP, cookie передаётся в клиентском браузере. См. документацию по проверке подлинности OIDC в веб-приложении ASP.NET Core.

Подчиненные API

Иногда API-интерфейсы должны получать доступ к данным пользователей из подчиненных API от имени прошедшего проверку подлинности пользователя в вызывающем приложении. Хотя реализация потока учетных данных клиента OAuth является вариантом, он требует полного доверия между двумя приложениями API. Более безопасный подход включает использование стратегии нулевого доверия с делегированным маркером доступа пользователей. Такой подход:

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

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

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

Это хороший способ реализовать это требование, но это сложно, если необходимо реализовать поток OAuth.

См. раздел OAuth 2.0 Token Exchange

Чтобы запросить новый токен делегированного доступа, используйте Microsoft Identity Web от имени потока.

Использование библиотеки веб-проверки подлинности Identity является самым простым и безопасным подходом. Он работает только с Microsoft Entra ID и Microsoft Entra External ID.

Дополнительные сведения см. в разделе "Платформа удостоверений Майкрософт" и поток OAuth 2.0 on-Behalf-Of.

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

Этот подход не сложно реализовать, но маркер доступа имеет доступ ко всем нижестоящим API. Для реализации этого можно использовать обратный прокси-сервер Yarp.

Используйте процесс учетных данных клиента OAuth и маркер доступа к приложению.

Это легко реализовать, но клиентское приложение имеет полные права доступа к возможностям приложения, а не токен делегированного доступа. Токен должен кэшироваться в клиентском API-приложении.

Заметка

Межприложная безопасность также работает. Проверку подлинности на основе сертификатов или в Azure можно использовать управляемое удостоверение.

Обработка токенов доступа

При использовании маркеров доступа в клиентском приложении маркеры доступа необходимо повернуть, сохранить и хранить где-то на сервере. В веб-приложении файлы cookie используются для защиты сеанса и могут использоваться для хранения маркеров с помощью параметра SaveTokens .

SaveTokens сейчас не будет автоматически обновлять маркеры доступа, но эта функция планируется для .NET 10. Следуйте за https://github.com/dotnet/aspnetcore/issues/8175 для обновлений. В то же время можно вручную обновить маркер доступа, как показано в Blazor Web App документации по OIDC или использовать сторонний пакет NuGet, например Duende.AccessTokenManagement.OpenIdConnect для обработки маркеров доступа и управления ими в клиентском приложении. Дополнительные сведения см. в разделе "Управление маркерами Duende".

Заметка

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

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

  • Не открывайте маркеры доступа в приложении пользовательского интерфейса
  • Не отправляйте маркер идентификатора в API
  • Маркеры доступа могут иметь любой формат
  • Маркеры доступа можно шифровать
  • Токены доступа имеют срок действия и нуждаются в обновлении.
  • Маркеры доступа сохраняются на защищенном сервере.

YARP (еще один обратный прокси-сервер)

YARP (еще один обратный прокси-сервер) — это полезная технология для обработки HTTP-запросов и перенаправления запросов в другие API. YARP может реализовать логику безопасности для получения новых учетных данных доступа. YARP часто используется при внедрении серверной части для архитектуры безопасности Frontend (BFF).

Примеры Blazor, которые используют YARP для реализации шаблона BFF, см. в следующих статьях:

Blazor Пример, использующий YARP для реализации шаблона BFF, см. в разделе "Защита ASP.NET Core Blazor Web App с помощью OpenID Connect (OIDC)".

Дополнительную информацию см. в auth0: Backend for Frontend Pattern.

Тестирование API

Тесты интеграции и контейнеры с маркерами доступа можно использовать для тестирования безопасных API. Маркеры доступа можно создать с помощью средства dotnet user-jwts.

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

Убедитесь, что проблемы безопасности не вводятся в API для тестирования. Тестирование становится более сложным при использовании маркеров делегированного доступа, так как эти маркеры можно создать только с помощью пользовательского интерфейса и потока OpenID Connect. Если средство тестирования используется для создания делегированных маркеров доступа, для тестирования необходимо отключить функции безопасности. Важно, чтобы эти функции были отключены только в тестовой среде.

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

Использование пользовательского интерфейса Swagger, Curl и других средств пользовательского интерфейса API

Пользовательский интерфейс Swagger и Curl — это отличные инструменты пользовательского интерфейса для тестирования API. Чтобы средства работали, API может создать документ OpenAPI, и его можно загрузить в клиентское средство тестирования. Поток безопасности для получения нового токена доступа можно добавить в файл API OpenAPI.

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

Не развертывайте небезопасные потоки тестов безопасности в рабочей среде.

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

Сопоставление утверждений из OpenID Connect

См. следующий документ:

Сопоставление, настройка и преобразование утверждений в ASP.NET Core

Стандарты

Веб-токен JSON (JWT)

Фреймворк авторизации OAuth 2.0

OAuth 2.0, демонстрирующий подтверждение владения DPoP

OAuth 2.0 JWT-Secured запрос авторизации (JAR) RFC 9101

Аутентификация клиента OAuth 2.0 Mutual-TLS и токены доступа Certificate-Bound

OpenID Connect 1.0

Платформа удостоверений Майкрософт и потокBehalf-Of OAuth 2.0

Обмен токенами OAuth 2.0

Профиль веб-маркера JSON (JWT) для маркеров доступа OAuth 2.0

Семантика HTTP RFC 9110