セキュリティに関する考慮事項 ASP.NET Core SignalR

提供 : Andrew AndrewTon-Nurse

この記事では、 のセキュリティ保護に関する情報を提供します SignalR 。

クロス オリジン リソース共有

クロスオリジン リソース共有 (CORS) を使用すると、ブラウザーでクロスオリジン SignalR 接続を許可できます。 JavaScript コードがアプリとは別のドメインでホストされている場合、JavaScript がアプリに接続するには SignalR、CORS ミドルウェアを有効にする必要 SignalR があります。 信頼または制御するドメインからのクロスオリジン要求のみを許可します。 次に例を示します。

  • サイトがでホストされている http://www.example.com
  • アプリ SignalR がでホストされている http://signalr.example.com

CORS は、オリジン のみを SignalR 許可するようにアプリで構成する必要があります www.example.com

CORS の構成の詳細については、「クロスオリジン要求を有効にする (CORS)」を参照してください。 SignalRには 、次の CORS ポリシーが必要です。

  • 特定の予期されるオリジンを許可します。 任意のオリジンを許可できますが、 セキュリティで保護されていない か、推奨されません。
  • HTTP メソッドと GETPOST 許可する必要があります。
  • ベースのスティッキー セッションが正しく機能するには、 cookie 資格情報を許可する必要があります。 認証が使用されていない場合でも有効にする必要があります。

ただし、5.0 では、資格情報を使用しないオプションが TypeScript クライアントに用意されています。 資格情報を使用しないオプションは、アプリで のような資格情報が不要であることが 100% わかっている場合にのみ使用する必要があります (スティッキー セッションに複数のサーバーを使用する場合は、Azure App Service によって使用されます Cookiecookie )。

たとえば、次の CORS ポリシーでは、 でホストされているブラウザー クライアントが、 でホスト SignalRhttps://example.com されている SignalR アプリにアクセスできます https://signalr.example.com

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    // ... other middleware ...

    // Make sure the CORS middleware is ahead of SignalR.
    app.UseCors(builder =>
    {
        builder.WithOrigins("https://example.com")
            .AllowAnyHeader()
            .WithMethods("GET", "POST")
            .AllowCredentials();
    });

    // ... other middleware ...
    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapHub<ChatHub>("/chathub");
    });

    // ... other middleware ...
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    // ... other middleware ...

    // Make sure the CORS middleware is ahead of SignalR.
    app.UseCors(builder =>
    {
        builder.WithOrigins("https://example.com")
            .AllowAnyHeader()
            .WithMethods("GET", "POST")
            .AllowCredentials();
    });

    // ... other middleware ...

    app.UseSignalR(routes =>
    {
        routes.MapHub<ChatHub>("/chathub");
    });

    // ... other middleware ...
}

WebSocket のオリジン制限

CORS で提供される保護は、WebSocket には適用されません。 WebSockets のオリジン制限については 、WebSockets のオリジン制限に関するページを参照してください

CORS で提供される保護は、WebSocket には適用されません。 ブラウザーでは以下を実行しません

  • CORS の事前要求を実行する。
  • WebSocket 要求を行うときに Access-Control ヘッダーに指定された制限を考慮する。

ただし、WebSocket 要求を発行するときにはブラウザーから Origin ヘッダーが送信されます。 予期した配信元からの WebSocket のみが許可されるように、アプリケーションでこれらのヘッダーが検証されるように構成する必要があります。

2\.1 ASP.NET Core以降では、 の前に配置されたカスタム ミドルウェアと、 の認証ミドルウェアを使用して、ヘッダーの検証 UseSignalR を実現できます Configure


// In Startup, add a static field listing the allowed Origin values:
private static readonly HashSet<string> _allowedOrigins = new HashSet<string>()
{
    // Add allowed origins here. For example:
    "https://www.mysite.com",
    "https://mysite.com",
};

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    // ... other middleware ...

    // Validate Origin header on WebSocket requests to prevent unexpected cross-site 
    // WebSocket requests.
    app.Use((context, next) =>
    {
        // Check for a WebSocket request.
        if (string.Equals(context.Request.Headers["Upgrade"], "websocket"))
        {
            var origin = context.Request.Headers["Origin"];

            // If there is an origin header, and the origin header doesn't match 
            // an allowed value:
            if (!string.IsNullOrEmpty(origin) && !_allowedOrigins.Contains(origin))
            {
                // The origin is not allowed, reject the request
                context.Response.StatusCode = (int) HttpStatusCode.Forbidden;
                return Task.CompletedTask;
            }
        }

        // The request is a valid Origin or not a WebSocket request, so continue.
        return next();
    });

    // ... other middleware ...

    app.UseSignalR(routes =>
    {
        routes.MapHub<ChatHub>("/chathub");
    });

    // ... other middleware ...
}

Note

Origin ヘッダーは、クライアントによって制御され、Referer のように偽装することができます。 これらのヘッダーを認証メカニズムとして使用しないでください

ConnectionId

公開すると ConnectionId 、サーバーまたはクライアントのバージョンが SignalR 2.2 以前 ASP.NET Core偽装される可能性があります。 サーバーと SignalR クライアントのバージョンが 3.0 以降 ASP.NET Core場合は、 ではなく をシークレット ConnectionTokenConnectionId に保持する必要があります。 は ConnectionToken 、特に API では公開されません。 古いクライアントがサーバーに接続されていないことを確認するのは困難な場合があります。そのため、サーバーのバージョンが SignalRSignalR ASP.NET Core 3.0 以降の場合でも、 は公開されません ConnectionId

アクセス トークンのログ記録

WebSockets または Server-Sent Events を使用する場合、ブラウザー クライアントはクエリ文字列でアクセス トークンを送信します。 通常、クエリ文字列を使用したアクセス トークンの受信は、標準ヘッダーを使用する場合と同様に安全 Authorization です。 常に HTTPS を使用して、クライアントとサーバー間の安全なエンドツーエンド接続を確保します。 多くの Web サーバーは、クエリ文字列を含む各要求の URL をログに記録します。 URL をログに記録すると、アクセス トークンがログに記録される場合があります。 ASP.NET Core要求の URL が既定でログに記録されます。この URL にはクエリ文字列が含まれます。 次に例を示します。

info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
      Request starting HTTP/1.1 GET http://localhost:5000/chathub?access_token=1234

このデータをサーバー ログでログに記録することについて懸念がある場合は、ロガーをレベル以上に構成することで、このログ記録を完全に無効にできます (これらのメッセージはレベル Microsoft.AspNetCore.HostingWarning で書き込 Info まれます)。 詳細については、「コードでログ フィルター規則を適用する」 を参照してください。 引き続き特定の要求情報をログに記録する場合は、必要なデータをログに記録するミドルウェアを記述し、クエリ文字列値 (存在する場合) を access_token フィルターで削除できます。

例外

例外メッセージは、通常、クライアントに公開してはいけない機密データと見なされます。 既定では、 は、ハブ メソッドによってスローされた例外の詳細を SignalR クライアントに送信しません。 クライアントはその代わりに、エラーが発生したことを示す一般的なメッセージを受信します。 クライアントへの例外メッセージ配信は 、EnableDetailedErrorsを使用してオーバーライドできます (開発やテストなど)。 例外メッセージは、実稼働アプリでクライアントに公開すべきではありません。

バッファー管理

SignalR では、接続ごとのバッファーを使用して、受信メッセージと送信メッセージを管理します。 既定では、 SignalR これらのバッファーは 32 KB に制限されます。 クライアントまたはサーバーが送信できる最大メッセージは 32 KB です。 メッセージの接続で使用される最大メモリは 32 KB です。 メッセージが常に 32 KB 未満の場合は、制限を減らして次の処理を行います。

  • クライアントが大きなメッセージを送信できない。
  • サーバーは、メッセージを受け入れる大きなバッファーを割り当てる必要はありません。

メッセージが 32 KB を超える場合は、制限を増やします。 この制限を増やすとは、次の意味を意味します。

  • クライアントによって、サーバーが大きなメモリ バッファーを割り当てる可能性があります。
  • 大きなバッファーのサーバー割り当てにより、同時接続の数が減る可能性があります。

受信メッセージと送信メッセージには制限があります。両方とも、 で構成された HttpConnectionDispatcherOptions オブジェクトで構成できます MapHub

  • ApplicationMaxBufferSize は、サーバーがバッファーするクライアントからの最大バイト数を表します。 クライアントが、この制限を超えるメッセージを送信しようとすると、接続が閉じられます。
  • TransportMaxBufferSize は、サーバーが送信できる最大バイト数を表します。 サーバーが、この制限を超えるメッセージ (ハブ メソッドからの戻り値を含む) を送信しようとすると、例外がスローされます。

制限を に設定すると 0 、制限が無効にされます。 制限を削除すると、クライアントは任意のサイズのメッセージを送信できます。 悪意のあるクライアントが大きなメッセージを送信すると、余分なメモリが割り当てられる可能性があります。 メモリ使用量が多い場合、同時接続の数が大幅に減少する可能性があります。