作成者: Damien Bowden
JWT (JSON Web トークン) ベアラー認証は、一般的に API に使用されます。 ID プロバイダーは、cookie 認証と同様に動作しますが、認証が成功すると JWT またはトークンを発行します。 これらのトークンは、発行ドメインにのみ送り返される Cookie とは異なり、他のサーバーに送信して認証に使用することができます。 JWT は、API リソースまたはクライアントの情報をカプセル化する自己完結型トークンです。 JWT を要求したクライアントは、Authorization ヘッダーとベアラー トークンを使用して API リソースからデータを要求できます。
JWT ベアラー認証では、次の機能が提供されます。
-
認証:
JwtBearerHandler
を使用する場合、ベアラー トークンは認証に不可欠です。JwtBearerHandler
はトークンを検証し、その要求からユーザーの ID を抽出します。 - 承認: ベアラー トークンは、 cookieと同様に、ユーザーまたはアプリケーションのアクセス許可を表すクレームのコレクションを提供することで承認を有効にします。
- 委任された承認: アプリケーション全体のアクセス トークンではなく、ユーザー固有のアクセス トークンを使用して API 間で認証を行う場合、このプロセスは 委任された承認と呼ばれます。
JWT ベアラー認証の概要については、JSON Web トークンに関するページを参照してください。サンプル コードを表示またはダウンロードする
この記事では、次の領域について説明します。
- トークンの種類
- JWT トークンを使用して API をセキュリティで保護する
- OIDC/OAuth はこれにどう適合するのか
- JWT ベアラー トークン認証の実装
- JWT を作成するための推奨される方法
トークンの種類
さまざまな種類のトークンと形式があります。 テスト以外の目的で、独自のアクセス トークンまたは ID トークンを生成することは推奨されません。 確立された標準に準拠していない自己作成トークンの場合、次が該当します。
- セキュリティの脆弱性につながる可能性があります。
- クローズド システムにのみ適しています。
API アクセスを目的としたアクセス トークンを作成するには、 OpenID Connect 1.0 または OAuth 標準を使用することをお勧めします。
アクセス トークン
アクセス トークン:
- API を実装するサーバーに要求を行うためにクライアント アプリによって使用される文字列です。
- 形式は異なる場合があります。 API によってトークンの形式が異なる場合があります。
- 暗号化できます。
- アクセス トークンを保持している Web クライアントまたは UI アプリによって読み取られたり解釈されたりしてはなりません。
- API に要求することのみを目的としています。
- 通常、ベアラー トークンとして Authorization 要求ヘッダーの API に送信されます。
OAuth 2.0 承認フレームワークを参照してください
アプリケーション アクセス トークンと委任されたアクセス トークン
アクセス トークンには、 アプリケーション アクセス トークン または 委任されたアクセス トークンのいずれかを指定できます。 トークンにはさまざまな要求が含まれ、異なる方法で管理および格納されます。 通常、アプリケーション アクセス トークンは有効期限が切れるまでアプリに 1 回格納されますが、委任されたアクセス トークンはユーザーごとに、cookieまたはセキュリティで保護されたサーバー キャッシュに格納されます。
ユーザーが関係する場合は常に、委任されたユーザー アクセス トークンを使用することをお勧めします。 ダウンストリーム API は認証済みユーザーに代わって、委任されたユーザー アクセス トークンを要求できます。
センダーの制約付きアクセス トークン
アクセス トークンは、リソースにアクセスするための ベアラー トークン または 送信者の制約付きトークン として使用できます。 センダーの制約付きトークンでは、要求元クライアントはトークンを使用するために秘密キーの所有を証明する必要があります。 秘密キーの所有を証明することで、トークンが単独で使用されないことが保証されます。 センダーの制約付きトークンは、次の 2 つの方法で実装できます。
ID トークン
ID トークンは、ユーザーが認証に成功したことを確認するセキュリティ トークンです。 トークンを使用すると、クライアントはユーザーの ID を確認できます。 JWT トークン サーバーは、ユーザー情報を持つ要求を含んだ ID トークンを発行します。 ID トークンは常に JWT 形式です。
API へのアクセスには ID トークンを使用 しないでください 。
その他のトークン
OpenID Connect および OAuth 標準で指定されているアクセス トークンや ID トークンなど、さまざまな種類のトークンがあります。 更新トークンを使用すると、ユーザーを再認証せずに UI アプリを更新できます。 OAuth JAR トークンは、 承認要求を安全に送信できます。 検証可能な資格情報フローでは、資格情報の発行または検証に JWT の種類が使用されます。 仕様に従ってトークンを使用することが重要です。 詳細については、この記事で後述する標準リンクを参照してください。
JWT トークンを使用して API をセキュリティで保護する
API 承認に JWT アクセス トークンを使用する場合、API は指定されたトークンに基づいてアクセスを許可または拒否します。 要求が承認されていない場合は、401 応答または 403 応答が返されます。 API は、新しいトークンを取得したり追加のアクセス許可を要求したりするために、ユーザーを ID プロバイダーにリダイレクトすべきではありません。 API を使用するアプリは、適切なトークンを取得する必要があります。 これにより、API (承認) と使用するクライアント アプリ (認証) の間で懸念事項が明確に分離されます。
メモ
HTTP では、承認されていないクライアントにリソースの存在に関する情報が漏洩しないように、404 を返すこともできます。
401 権限がありません
401 未承認の応答は、指定されたアクセス トークンが必要な標準を満たしていないことを示します。 これには、次のような理由がいくつか考えられます。
- 無効な署名: トークンの署名が一致せず、改ざんの可能性が示唆されます。
- 有効期限: トークンの有効期限が切れており、有効ではなくなりました。
-
不正な要求: 対象ユーザー (
aud
) や発行者 (iss
) など、トークン内の重要な要求が見つからないか無効です。
メモ
HTTP セマンティクス RFC 9110 から: 401 応答を生成するサーバーは、ターゲット リソースに適用できる少なくとも 1 つのチャレンジを含む WWW-Authenticate ヘッダー フィールド (セクション 11.6.1) を送信する必要があります。
OAuth 仕様では、必要な要求とその検証に関する詳細なガイドラインが提供されます。
403 許可されていません
通常、403 Forbidden 応答は、認証されたユーザーに、要求されたリソースにアクセスするために必要なアクセス許可がないことを示します。 これは認証の問題 (無効なトークンなど) とは異なり、アクセス トークン内の標準要求とは無関係です。
ASP.NET Core では、次を使用して承認を適用できます。
要件とポリシー: カスタム要件 ("管理者である必要があります" など) を定義し、ポリシーに関連付けます。 ロールベースの承認: "管理者"、"エディター" などのロールにユーザーを割り当て、それらのロールに基づいてアクセスを制限します。
ベアラー トークンの使用時に OIDC や OAuth が果たす役割とは
API が承認に JWT アクセス トークンを使用する場合、API はアクセス トークンのみを検証し、トークンの取得方法は検証しません。
OpenID Connect (OIDC) と OAuth 2.0 では、トークン取得用のセキュリティで保護された標準化フレームワークを使用できます。 トークンの取得は、アプリの種類によって異なります。 セキュリティで保護されたトークンの取得は複雑なため、次の標準に依存することを強くお勧めします。
- ユーザーとアプリケーションの代わりに動作するアプリの場合: OIDC が優先される選択肢であり、委任されたユーザー アクセスを有効にします。 Web アプリでは、セキュリティを強化するために、 Proof Key for Code Exchange (PKCE) を使用した機密コード フローが推奨されます。
- 呼び出し元のアプリがサーバー側 OIDC 認証を使用する ASP.NET Core アプリの場合は、 SaveTokens オプションを使用してアクセス トークンを cookie に格納し、後で
HttpContext.GetTokenAsync("access_token")
経由で使用できます。
- 呼び出し元のアプリがサーバー側 OIDC 認証を使用する ASP.NET Core アプリの場合は、 SaveTokens オプションを使用してアクセス トークンを cookie に格納し、後で
- アプリにユーザーがいない場合: OAuth 2.0 クライアント資格情報フローは、アプリケーション アクセス トークンの取得に適しています。
JWT ベアラー トークン認証の実装
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 この方法では、複数の認証スキームを定義し、トークンのプロパティ (発行者、クレームなど) に基づいて適切なスキームを選択するロジックを実装できます。 このアプローチにより、1 つの API 内で柔軟性が向上します。
ベアラー認証の強制
SetDefaultPolicy を使用すると、[Authorize]
属性を持たないエンドポイントにも、すべての要求に対して認証を要求できます。
SetDefaultPolicy は、[Authorize]
属性を持つエンドポイントに使用されるポリシーを構成し、既に既定で認証済みユーザーを要求するように設定されています。 詳細については、「認証されたユーザーを要求する」を参照してください。
var requireAuthPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
builder.Services.AddAuthorizationBuilder()
.SetDefaultPolicy(requireAuthPolicy);
Authorize 属性を使用して認証を強制することもできます。 複数のスキームを使用する場合は、通常、ベアラー スキームを既定の認証スキームとして設定するか、[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme])
を使用して指定する必要があります。
コントローラーでの承認:
[Authorize]
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
最小 API での承認:
app.MapGet("/hello", [Authorize] () => "Hi");
JWT を作成するための推奨される方法
アクセス トークンの不適切な取り扱い (脆弱な認証や、脆弱なクライアント側ストレージにトークンを保存することなど) は、重大なセキュリティの脆弱性につながる可能性があります。 例えば、アクセス トークンをローカル ストレージ、セッション ストレージ、または Web worker を使用してブラウザーに直接格納することです。 次のセクションでは、アクセス トークンを使用および作成するアプリのベスト プラクティスについて説明します。
標準を使用する
アクセス トークンの作成時は必ず、OpenID Connect や OAuth などの標準を使用する必要があります。 この記事で説明されているセキュリティ上の予防措置を遵守せずに、運用アプリでアクセス トークンを作成しないでください。 アクセス トークンの作成は、テスト シナリオに限定する必要があります。
非対称キーを使用する
アクセス トークンを作成するときは、必ず非対称キーを使用する必要があります。 公開キーは既知のエンドポイントで使用でき、API クライアントは公開キーを使用してアクセス トークンの署名を検証できます。
ユーザー名/パスワード要求からアクセス トークンを作成しない
ユーザー名/パスワード要求からアクセス トークンを作成しないでください。 ユーザー名/パスワード要求は、なりすましやフィッシング攻撃に対して脆弱であり、認証されません。 アクセス トークンは、OpenID Connect フローまたは OAuth 標準フローのみを使用して作成する必要があります。 これらの標準から逸脱すると、アプリが安全でなくなる可能性があります。
Cookie を使用する
セキュリティで保護された Web アプリの場合、信頼されたサーバーにアクセス トークンを格納するにはバックエンドが必要です。 クライアント ブラウザーで共有されるのは、セキュリティで保護された HTTP 専用 cookie のみです。 ASP.NET Core Web アプリでこれを行う方法については、 OIDC 認証のドキュメントを参照 してください。
ダウンストリームAPI
API では時折、呼び出し元アプリの認証済みユーザーの代わりにダウンストリーム API からユーザー データにアクセスする必要があります。 OAuth クライアント資格情報フローの実装はオプションですが、2 つの API アプリ間の完全な信頼が必要になります。 より安全なアプローチは、委任されたユーザー アクセス トークンを使用するゼロトラスト戦略を採用することです。 この方法の特徴は次のとおりです。
- 特定のユーザーに必要なアクセス許可のみを API に付与することでセキュリティを強化します。
- アプリと API を呼び出すユーザーに新しいアクセス トークンを API で作成する必要があります。
委任されたユーザー アクセス トークンを使用してゼロトラスト戦略を実装するには、いくつかの方法があります。
OAuth 2.0 Token Exchange を使用して新しい委任されたアクセス トークンを要求する
これは、この要件を実装する良い方法ですが、OAuth フローを実装する必要がある場合は複雑です。
OAuth 2.0 トークン交換を参照してください
フローの代わりに Microsoft Identity Web を使用して、新しい委任されたアクセス トークンを要求する
Microsoft Identity Web 認証ライブラリの使用は、最も簡単で安全な方法です。 Microsoft Entra ID、Microsoft Entra External ID でのみ機能します。
詳細については、「Microsoft ID プラットフォームと OAuth 2.0 On-Behalf-Of フローを参照してください。
API に送信されたのと同じ委任されたアクセス トークンを使用する
このアプローチを実装することは難しくありませんが、アクセス トークンはすべてのダウンストリーム API にアクセスできます。 この実装には、Yarp リバース プロキシを使用できます。
OAuth クライアント資格情報フローを使用し、アプリケーション アクセス トークンを使用する
これは簡単に実装できますが、クライアント アプリケーションには、委任されたアクセス トークンではなく、完全なアプリケーション アクセスが含まれます。 トークンはクライアント API アプリケーションにキャッシュする必要があります。
メモ
アプリ間のセキュリティも正常に機能しています。 証明書認証、または Azure ではマネージド ID を使用できます。
アクセス トークンの処理
クライアント アプリケーションでアクセス トークンを使用する場合、アクセス トークンをローテーションし、永続化して、サーバー上のどこかに格納する必要があります。 Web アプリケーションでは、Cookie はセッションをセキュリティで保護するために使用され、 SaveTokens オプションを使用してトークンを格納するために使用できます。
現在のところ、SaveTokens
ではアクセス トークンは自動的に更新されませんが、この機能は .NET 10 用に計画されています。 更新プログラムについては、https://github.com/dotnet/aspnetcore/issues/8175 に従ってください。 それまでの間、 OIDC ドキュメントを使用して Blazor Web App で示 されているように、アクセス トークンを手動で更新するか、 Duende.AccessTokenManagement.OpenIdConnect などのサードパーティの NuGet パッケージを使用して、クライアント アプリでのアクセス トークンの処理と管理を行うことができます。 詳細については、「 Duende トークン管理」を参照してください。
メモ
運用環境にデプロイする場合、キャッシュはマルチインスタンス デプロイで機能する必要があります。 通常、永続キャッシュが必要です。
セキュリティで保護されたトークン サーバーの中には、アクセス トークンを暗号化するものもあります。 アクセス トークンには形式は必要ありません。 OAuth イントロスペクションを使用する場合は、アクセス トークンの代わりに参照トークンが使用されます。 アクセス トークンはそういう目的のものではないため、クライアント (UI) アプリケーションでアクセス トークンを開かないでください。 アクセス トークンが作成された API のみでアクセス トークンを開く必要があります。
- UI アプリケーションでアクセス トークンを開かない
- ID トークンを API に送信しない
- アクセス トークンには任意の形式を使用できる
- アクセス トークンは暗号化できる
- アクセス トークンの有効期限が切れ、ローテーションする必要がある
- アクセス トークンは、セキュリティで保護されたバックエンド サーバーに保持される
YARP (さらに別のリバース プロキシ)
YARP (さらに別のリバース プロキシ) は、HTTP 要求を処理し、要求を他の API に転送するために役立つテクノロジです。 YARP は、新しいアクセス資格情報を取得するためのセキュリティ ロジックを実装できます。 YARP は、 フロントエンド (BFF) セキュリティ アーキテクチャのバックエンドを採用するときによく使用されます。
YARP を使用して BFF パターンを実装する Blazor 例については、次の記事を参照してください。
YARP を使用して BFF パターンを実装する Blazor 例については、「 OpenID Connect (OIDC) を使用して ASP.NET Core Blazor Web App をセキュリティで保護する」を参照してください。
詳細については、「 auth0: フロントエンド パターンのバックエンド」を参照してください。
API のテスト
統合テストと、アクセス トークンを持つコンテナーを使用して、セキュリティで保護された API をテストできます。 アクセス トークンは、 dotnet user-jwts ツールを使用して作成できます。
警告
テスト目的で API にセキュリティ上の問題が取り込まれないようにしてください。 委任されたアクセス トークンを使用する場合、テストはより困難になります。これらのトークンは UI と OpenID Connect フローを介してのみ作成できるためです。 テスト ツールを使用して委任されたアクセス トークンを作成する場合は、テストのためにセキュリティ機能を無効にする必要があります。 これらの機能をテスト環境でのみ無効にすることが重要です。
セキュリティ機能を安全に無効または変更できる、専用の分離されたテスト環境を作成します。 これらの変更がテスト環境のみに厳密に限定されていることを確認してください。
Swagger UI、Curl、およびその他の API UI ツールを使用する
Swagger UI と Curl は、API をテストするための優れた UI ツールです。 ツールを機能させるには、API で OpenAPI ドキュメントを生成し、クライアント テスト ツールに読み込むことができます。 新しいアクセス トークンを取得するためのセキュリティ フローを API OpenAPI ファイルに追加できます。
警告
セキュリティで保護されていないテスト フローを運用環境にデプロイしないでください。
API 用の Swagger UI を実装する場合、これを機能させるにはセキュリティを弱める必要があるため、通常は UI を運用環境にデプロイしないでください。
OpenID Connect からの要求をマップする
次のドキュメントを参照してください。
ASP.NET Core の要求のマッピング、カスタマイズ、変換
標準
OAuth 2.0 Demonstrating Proof of Possession (DPoP)
OAuth 2.0 JWTによるセキュリティ保護された認可リクエスト (JAR) RFC 9101
OAuth 2.0 Mutual-TLS クライアント認証と Certificate-Bound アクセス トークン
Microsoft ID プラットフォームと OAuth 2.0 On-Behalf-Of フロー
ASP.NET Core