ASP.NET Core Blazor WebAssembly をセキュリティで保護する

注意

これは、この記事の最新バージョンではありません。 現在のリリースについては、この記事の .NET 8 バージョンを参照してください。

重要

この情報はリリース前の製品に関する事項であり、正式版がリリースされるまでに大幅に変更される可能性があります。 Microsoft はここに示されている情報について、明示か黙示かを問わず、一切保証しません。

現在のリリースについては、この記事の .NET 8 バージョンを参照してください。

Blazor WebAssembly アプリは、シングル ページ アプリケーション (SPA) と同じ方法でセキュリティ保護します。 ユーザーを SPA で認証する方法はいくつかありますが、最も一般的で包括的な方法は、OpenID Connect (OIDC) などの OAuth 2.0 プロトコルに基づく実装を使用することです。

Blazor WebAssembly のセキュリティ ドキュメントでは、主にユーザー認証と承認のタスクを実行する方法に焦点を当てています。 OAuth 2.0/OIDC の一般的な概念の対象範囲については、主要な概要に関する記事の「その他のリソース」セクションのリソースを参照してください。

クライアント側/SPA セキュリティ

Blazor WebAssembly アプリの .NET/C# コードベースはクライアントに提供されるので、アプリのコードをユーザーによる検査や改ざんから保護することはできません。 非公開の .NET/C# コード、セキュリティ キー、パスワード、その他の種類の機密情報など、何らかの秘密の性質を持つものを Blazor WebAssembly アプリ内に決して配置しないでください。

.NET/C# コードを保護し、ASP.NET Core データ保護機能を使用してデータをセキュリティで保護するには、サーバー側 ASP.NET Core Web API を使用します。 セキュリティで保護されたアプリ機能とデータ処理のためには、クライアント側 Blazor WebAssembly アプリがサーバー側 Web API を呼び出すようにします。 詳細については、「ASP.NET Core Blazor アプリからの Web API の呼び出し」とこのノード内の記事を参照してください。

認証ライブラリ

Blazor WebAssembly では、Microsoft Identity Platform を使った Microsoft.AspNetCore.Components.WebAssembly.Authentication ライブラリ経由の OIDC を使ったアプリの認証と認可がサポートされています。 ライブラリには、ASP.NET Core バックエンドに対してシームレスに認証を行うための一連のプリミティブが用意されています。 このライブラリは、OpenID Provider (OP) と呼ばれる OIDC をサポートするすべてのサードパーティ Identity プロバイダー (IP) に対して認証できます。

Blazor WebAssembly ライブラリ (Authentication.js) の認証のサポートは、基になる認証プロトコルの詳細を処理するために使用される、Microsoft Authentication Library (MSAL、msal.js) に基づいて構築されています。 Blazor WebAssembly ライブラリでは、Proof Key for Code Exchange (PKCE) 認可コード フローのみがサポートされます。 暗黙的な許可はサポートされていません。

SameSite cookie の使用など、SPA を認証するためのその他のオプションも存在します。 ただし、Blazor WebAssembly のエンジニアリング設計では、Blazor WebAssembly アプリでの認証に最適なオプションとして OAuth および OIDC が使用されます。 JSON Web トークン (JWT) に基づくトークンベースの認証は、機能とセキュリティ上の理由により、cookie ベースの認証に基づいて選択されています。

  • トークンベースのプロトコルを使用すると、トークンがすべての要求で送信されないため、攻撃対象領域が小さくなります。
  • サーバー エンドポイントでは、トークンが明示的に送信されるため、クロスサイト リクエスト フォージェリ (CSRF) に対する保護が必要ありません。 これにより、MVC または Razor ページ アプリと共に、Blazor WebAssembly アプリをホストすることができます。
  • トークンの権限は cookie よりも狭くなります。 たとえば、該当する機能が明示的に実装されていない限り、トークンを使用してユーザー アカウントを管理したり、ユーザーのパスワードを変更したりできません。
  • トークンの有効期間は短く、既定では 1 時間です。これにより、攻撃時間が制限されます。 トークンは、いつでも取り消すことができます。
  • 自己完結型の JWT は、クライアントとサーバーの認証プロセスを保証します。 たとえば、クライアントには、受信したトークンが正当であり、指定した認証プロセスの一環として出力されたことを検出して検証する手段があります。 サード パーティが認証プロセスの途中でトークンを切り替えようとすると、クライアントは切り替えられたトークンを検出して使用しないようにすることができます。
  • OAuth および OIDC を使用したトークンは、アプリが安全であることを確認するために、正しく動作しているユーザー エージェントに依存しません。
  • OAuth や OIDC などのトークンベースのプロトコルでは、同じセキュリティ特性のセットを使用して、スタンドアロンの Blazor Webassembly アプリのユーザーの認証と認可を行うことができます。
  • トークンベースのプロトコルを使用すると、トークンがすべての要求で送信されないため、攻撃対象領域が小さくなります。
  • サーバー エンドポイントでは、トークンが明示的に送信されるため、クロスサイト リクエスト フォージェリ (CSRF) に対する保護が必要ありません。 これにより、MVC または Razor ページ アプリと共に、Blazor WebAssembly アプリをホストすることができます。
  • トークンの権限は cookie よりも狭くなります。 たとえば、該当する機能が明示的に実装されていない限り、トークンを使用してユーザー アカウントを管理したり、ユーザーのパスワードを変更したりできません。
  • トークンの有効期間は短く、既定では 1 時間です。これにより、攻撃時間が制限されます。 トークンは、いつでも取り消すことができます。
  • 自己完結型の JWT は、クライアントとサーバーの認証プロセスを保証します。 たとえば、クライアントには、受信したトークンが正当であり、指定した認証プロセスの一環として出力されたことを検出して検証する手段があります。 サード パーティが認証プロセスの途中でトークンを切り替えようとすると、クライアントは切り替えられたトークンを検出して使用しないようにすることができます。
  • OAuth および OIDC を使用したトークンは、アプリが安全であることを確認するために、正しく動作しているユーザー エージェントに依存しません。
  • OAuth や OIDC などのトークンベースのプロトコルを使うと、ホストされた Blazor WebAssembly ソリューションのクライアントとスタンドアロン Blazor Webassembly アプリのユーザーを、同じセキュリティ特性のセットを使用して認証および認可できます。

重要

Blazor プロジェクト テンプレートで Duende Identity Server を採用する ASP.NET Core のバージョンの場合、Duende Software から Duende Identity Server の運用環境での使用に対してライセンス料金の支払いを要求されることがあります。 詳細については、「ASP.NET Core 5.0 から 6.0 への移行」を参照してください。

OIDC を使用した認証プロセス

Microsoft.AspNetCore.Components.WebAssembly.Authentication ライブラリには、OIDC を使用した認証と認可を実装するためのいくつかのプリミティブが用意されています。 大まかにいうと、認証は次のようにして行われます。

  • 匿名ユーザーがログイン ボタンを選択するか、[Authorize] 属性が適用された Razor コンポーネントまたはページを要求すると、そのユーザーはアプリのログイン ページ (/authentication/login) にリダイレクトされます。
  • ログイン ページで、認証ライブラリが承認エンドポイントへのリダイレクトを準備します。 承認エンドポイントは、Blazor WebAssembly アプリの外部にあり、別のオリジンでホストすることができます。 エンドポイントは、ユーザーが認証されているかどうかを判断し、応答として 1 つ以上のトークンを発行する役割を担います。 認証ライブラリは、認証応答を受信するためのログイン コールバックを提供します。
    • ユーザーが認証されていない場合、そのユーザーは基になる認証システム (通常は ASP.NET Core の Identity) にリダイレクトされます。
    • ユーザーが既に認証されている場合、承認エンドポイントは適切なトークンを生成し、ブラウザーをログイン コールバック エンドポイント (/authentication/login-callback) にリダイレクトします。
  • Blazor WebAssembly アプリでログイン コールバック エンドポイント (/authentication/login-callback) が読み込まれると、認証応答が処理されます。
    • 認証プロセスが正常に完了した場合、ユーザーは認証され、必要に応じてユーザーが要求した元の保護された URL に戻されます。
    • 何らかの理由で認証プロセスが失敗した場合、ユーザーはエラーが表示されたログイン失敗ページ (/authentication/login-failed) に送られます。

Authentication コンポーネント

Authentication コンポーネント (Authentication.razor) はリモート認証操作を処理し、次のことをアプリに許可します。

  • 認証状態のアプリのルートを構成する。
  • 認証状態の UI コンテンツを設定する。
  • 認証状態を管理する。

ユーザーの登録やサインインなどの認証アクションは、Blazor フレームワークの RemoteAuthenticatorViewCore<TAuthenticationState> コンポーネントに渡されます。ここでは認証操作全体で状態が保持され、制御されます。

詳細と例については、「ASP.NET Core Blazor WebAssembly のその他のセキュリティ シナリオ」をご覧ください。

承認

Blazor WebAssembly アプリでは、すべてのクライアント側コードがユーザーによって変更される可能性があるため、承認チェックがバイパスされる可能性があります。 JavaScript SPA フレームワークや任意のオペレーティング システム用のネイティブ アプリを含め、すべてのクライアント側アプリのテクノロジにも同じことが当てはまります。

常に、クライアント側アプリからアクセスされるすべての API エンドポイント内のサーバー上で承認チェックを実行します。

認証をカスタマイズする

Blazor WebAssembly には、基になる認証ライブラリのその他のパラメーターを追加および取得して、外部 ID プロバイダーを使ってリモート認証操作を行う方法が備わっています。

追加のパラメーターを渡すために、NavigationManager では、外部の場所を変更する際の履歴エントリ状態の受け渡しと取得がサポートされます。 詳細については、次のリソースを参照してください。

履歴 API によって保存される状態には、リモート認証において次の利点があります。

  • セキュリティで保護されたアプリ エンドポイントに渡される状態は、authentication/login エンドポイントでユーザーを認証するために実行されるナビゲーションに関連付けられます。
  • データをエンコードおよびデコードする余分な作業を避けられます。
  • 攻撃面の領域が減少します。 クエリ文字列を使用してナビゲーション状態を保存するのとは異なり、最上位レベルのナビゲーションまたは別の配信元からの影響によって、履歴 API によって保存される状態を設定することはできません。
  • 履歴エントリは認証に成功すると置き換えられるため、履歴エントリにアタッチされている状態は削除され、クリーンアップの必要はありません。

InteractiveRequestOptions は、アクセス トークンにログインまたはプロビジョニングするための ID プロバイダーへの要求を表します。

NavigationManagerExtensions は、ログイン操作の NavigateToLogin メソッドとログアウト操作の NavigateToLogout を提供します。 メソッドは NavigationManager.NavigateTo を呼び出し、次のために渡された InteractiveRequestOptions またはメソッドによって作成された新しい InteractiveRequestOptions インスタンスを使用して、履歴エントリの状態を設定します。

次の認証シナリオについては、「ASP.NET Core Blazor WebAssembly のセキュリティに関するその他のシナリオ」の記事で説明します。

  • ログイン プロセスをカスタマイズする
  • カスタムの戻り先 URL を使用してログアウトする
  • トークンを対話的に取得する前にオプションをカスタマイズする
  • IAccessTokenProvider を使用する場合のオプションをカスタマイズする
  • 認証オプションからログイン パスを取得する

アプリ全体での承認を要求する

次の "いずれか" の方法を使用して、[Authorize] 属性 (API ドキュメント) をアプリの各 Razor コンポーネントに適用します。

  • アプリのインポート ファイルで、Microsoft.AspNetCore.Authorization 名前空間の @using ディレクティブと、 属性の [Authorize]@attribute ディレクティブを追加します。

    _Imports.razor:

    @using Microsoft.AspNetCore.Authorization
    @attribute [Authorize]
    

    Authentication コンポーネントへの匿名アクセスを許可して、ID プロバイダーへのリダイレクトを許可します。 次の Razor コードを、@page ディレクティブの下の Authentication コンポーネントに追加します。

    Authentication.razor:

    @using Microsoft.AspNetCore.Components.WebAssembly.Authentication
    @attribute [AllowAnonymous]
    
  • @page ディレクティブの各 Razor コンポーネントに属性を追加します。

    @using Microsoft.AspNetCore.Authorization
    @attribute [Authorize]
    

Note

RequireAuthenticatedUser を持つポリシーに AuthorizationOptions.FallbackPolicy を設定することはサポートされていません

アプリごとに 1 つの ID プロバイダー アプリ登録を使用する

この概要の下にある記事の一部は、2 つ以上のアプリが関わる Blazor ホスティング シナリオに関連しています。 スタンドアロン Blazor WebAssembly アプリは、認証されたユーザーと共に Web API を使用してサーバー アプリによって提供されるサーバーのリソースとデータにアクセスします。

これらのシナリオがドキュメントの例で実装されている場合、2 つの ID プロバイダー登録が使用されます。1 つはクライアント アプリ用、1 つはサーバー アプリ用です。 個別の登録を使用すること (たとえば Microsoft Entra ID で) は、厳密には必要ありません。 ただし、2 つの登録を使用することは、登録がアプリ別に分離されるため、セキュリティ上のベスト プラクティスです。 個別の登録を使用すると、クライアントとサーバーの登録を個別に構成することも可能になります。

この "概要" の下にある記事の一部は、2 つ以上のアプリを使用する次の Blazor ホスティング シナリオのいずれかに関連しています。

  • 2 つのアプリで構成された、ホストされている Blazor WebAssembly ソリューション: クライアント側 Blazor WebAssembly アプリとサーバー側 ASP.NET Core ホスト アプリ。 クライアント アプリに対して認証されたユーザーは、サーバー アプリによって提供されるサーバーのリソースとデータにアクセスします。
  • 認証されたユーザーと共に Web API を使用してサーバー アプリによって提供されるサーバーのリソースとデータにアクセスする、スタンドアロン Blazor WebAssembly アプリ。 このシナリオはホストされている Blazor WebAssembly ソリューションの使用に似ていますが、このケースでは、クライアント アプリはサーバー アプリによってホストされません。

これらのシナリオがドキュメントの例で実装されている場合、"2 つの" ID プロバイダー登録が使用されます。すなわち、1 つはクライアント アプリ用、1 つはサーバー アプリ用です。 個別の登録を使用すること (たとえば Microsoft Entra ID で) は、厳密には必要ありません。 ただし、2 つの登録を使用することは、登録がアプリ別に分離されるため、セキュリティ上のベスト プラクティスです。 個別の登録を使用すると、クライアントとサーバーの登録を個別に構成することも可能になります。

更新トークン

更新トークンは Blazor WebAssembly アプリではセキュリティで保護できませんが、適切なセキュリティ戦略と共に実装すれば使用できます。

.NET 6 以降の ASP.NET Core のスタンドアロン Blazor WebAssembly アプリの場合は、次を使用することをおすすめします。

ホストされている Blazor WebAssembly ソリューションの場合、更新トークンはサーバー側アプリで、サードパーティの API にアクセスするために保持および使用することができます。 詳細については、「ASP.NET Core Blazor WebAssembly のその他のセキュリティ シナリオ」を参照してください。

詳細については、次のリソースを参照してください。

ユーザーに対するクレームを確立する

アプリでは、サーバーへの Web API 呼び出しに基づくユーザーへのクレームが必要になることがよくあります。 たとえば、クレームは、アプリで承認を確立するためによく使用されます。 このようなシナリオにおいて、アプリでは、サービスにアクセスするためのアクセス トークンを要求し、そのトークンを使用してクレームを作成するためのユーザー データを取得します。

例については、次のリソースを参照してください。

プリレンダリングのサポート

プリレンダリングは認証エンドポイントではサポートされていません (/authentication/ パス セグメント)。

プリレンダリングは認証エンドポイントではサポートされていません (/authentication/ パス セグメント)。

詳細については、「ASP.NET Core Blazor WebAssembly のその他のセキュリティ シナリオ」を参照してください。

Identity Server を使用した Azure App Service on Linux

Identity Server を使用して Azure App Service on Linux にデプロイするときに、発行者を明示的に指定します。

詳しくは、Identity を使用して SPA の Web API バックエンドをセキュリティで保護する方法に関する記事を参照してください。

Windows 認証

Blazor WebAssembly またはその他の SPA フレームワークでは、Windows 認証を使用しないことをお勧めします。 Windows 認証の代わりにトークンベースのプロトコルを使用することをお勧めします (Active Directory フェデレーション サービス (AD FS) を使用する OIDC など)。

Windows 認証が Blazor WebAssembly またはその他の SPA フレームワークで使用されている場合、クロスサイト リクエスト フォージェリ (CSRF) トークンからアプリを保護するために追加の手段が必要になります。 cookie に当てはまるのと同じ問題が Windows 認証にも当てはまります。これに加えて、Windows 認証では、オリジン間での認証コンテキストの共有を防ぐメカニズムは提供されません。 CSRF からの追加の保護なしで Windows 認証を使用するアプリは、少なくとも組織のイントラネットに限定する必要があり、オープンなインターネットでは使用すべきではありません。

詳細については、「ASP.NET Core でのクロスサイト リクエスト フォージェリ (XSRF/CSRF) 攻撃の防止」を参照してください。

SignalR ハブをセキュリティで保護する

サーバー API プロジェクトで SignalR ハブをセキュリティで保護するには、[Authorize] 属性をハブ クラスまたはハブ クラスのメソッドに適用します。

ホステッド Blazor WebAssembly (.NET 7 以前の ASP.NET Core) または Blazor Web アプリ (.NET 8 以降の ASP.NET Core) など、プリレンダリングを使うクライアント プロジェクトでは、「ASP.NET Core BlazorSignalR ガイダンス」のガイダンスを参照してください。

スタンドアロンの Blazor WebAssembly や非ブラウザー アプリなど、プリレンダリングを使わないクライアント プロジェクト コンポーネントでは、次の例に示すように、ハブ接続へのアクセス トークンを指定します。 詳細については、「ASP.NET Core の認証と承認SignalR」を参照してください。

@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject IAccessTokenProvider TokenProvider
@inject NavigationManager Navigation

...

var tokenResult = await TokenProvider.RequestAccessToken();

if (tokenResult.TryGetToken(out var token))
{
    hubConnection = new HubConnectionBuilder()
        .WithUrl(Navigation.ToAbsoluteUri("/chathub"), 
            options => { options.AccessTokenProvider = () => Task.FromResult(token?.Value); })
        .Build();

  ...
}

ログ機能

このセクションは、.NET 7 以降の ASP.NET Core の Blazor WebAssembly アプリに適用されます。

デバッグまたはトレース ログを有効にするには、記事「ASP.NET Core Blazor のログ」のバージョン 7.0 以降の「認証ログ (Blazor WebAssembly)」セクションを参照してください。

WebAssembly サンドボックス

WebAssembly "サンドボックス" では、WebAssembly コードを実行するシステムの環境へのアクセスが制限されます (I/O サブシステム、システム ストレージとリソース、オペレーティング システムへのアクセスなど)。 WebAssembly コードとコードを実行するシステム間の分離により、WebAssembly がシステムにとって安全なコーディング フレームワークになります。 ただし、WebAssembly は、ハードウェア レベルでのサイドチャネル攻撃に対して脆弱です。 ハードウェア調達における通常の予防措置およびデュー デリジェンスと、ハードウェアへのアクセスに対する制限を設けることが該当します。

"WebAssembly は、Microsoftによって所有も管理もされていません。"

詳細については、次の W3C リソースを参照してください。

実装ガイダンス

この「概要」の記事では、特定のプロバイダーに対して Blazor WebAssembly アプリのユーザーを認証する方法について説明します。

スタンドアロン Blazor WebAssembly アプリ:

ホストされている Blazor WebAssembly アプリ:

構成に関するその他のガイダンスについては、次の記事を参照してください。

PKCE で承認コード フローを使用する

Microsoft ID プラットフォームの Microsoft Authentication Library for JavaScript (MSAL) v2.0 以降では、Proof Key for Code Exchange (PKCE) を使用した認可コード フローおよび Blazor を含むシングルページ アプリケーション用のクロスオリジン リソース共有 (CORS) のサポートが提供されています。

Microsoft は、暗黙的な許可の使用をお勧めしていません。

詳細については、次のリソースを参照してください。

その他のリソース