ASP.NET Core における HTTP.sys Web サーバーの実装

Note

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

Warning

このバージョンの ASP.NET Coreはサポートされなくなりました。 詳細については、.NETおよびコア サポート ポリシー.NETを参照してください。 現在のリリースについては、この記事の .NET 10 バージョンを参照してください。

作成者: Tom Dykstra、Chris Ross

HTTP.sys は、Windowsでのみ実行される ASP.NET Core用の Web サーバーです。 HTTP.sys は Kestrel サーバーの代替製品であり、Kestrel では提供されていない機能がいくつか用意されています。 この記事では、HTTP.sysを使用するタイミング、構成方法、および要求と TLS 情報を検査する方法について説明します。

Important

HTTP.sys は、ASP.NET Core モジュールと互換性がありません。IIS または IIS Express では使用できません。

HTTP.sys は、次の機能をサポートします。

  • Windows認証
  • ポート共有
  • SNI を使用する HTTPS
  • TLS 経由の HTTP/2 (Windows 10 以降)
  • TLS 経由の HTTP/3 (Windows 11 以降)
  • 直接ファイル伝送
  • 応答のキャッシュ
  • WebSocket (Windows 8 以降)
  • カスタマイズ可能なセキュリティ記述子
  • 自動メモリ プールの強制削除

オペレーティング システムは、アプリのターゲット バージョンである .NET でサポートされている必要があります。 サポートされているWindowsバージョンについては、「Windowsに.NETをインストールする」を参照してください。 古い Windows バージョンで HTTP.sys を利用できることは、現在の ASP.NET Core リリースによるこれらのバージョンのサポートを意味するものではありません。 個々の機能には、次のセクションで説明するように、追加のWindows要件があります。

サンプル コードを表示またはダウンロードします (ダウンロード方法)。

HTTP.sys を使用するタイミング

HTTP.sys は、次のような展開に適しています。

  • IIS を使用せず、インターネットに直接サーバーを公開する必要がある。

    HTTP.sys がインターネットと直接通信する

  • 内部の展開から Kestrel では使用できない機能が要求されている。 詳細については、Kestrel と HTTP.sys の比較に関するページを参照してください。

    HTTP.sys は内部ネットワークと直接通信します

HTTP.sys は、さまざまな種類の攻撃を防ぎ、フル機能の Web サーバーとして堅牢性、セキュリティ、スケーラビリティを提供する、成熟したテクノロジです。 IIS 自体が、HTTP.sys 上で HTTP リスナーとして実行されています。

HTTP/2 のサポート

次の基本要件が満たされている場合、ASP.NET Core アプリに対して HTTP/2 が有効になります。

Http/2 接続が確立されると、HttpRequest.Protocol が HTTP/2 を報告します。

HTTP/2 は既定で有効になっています。 Http/2 接続が確立されない場合、接続は http/1.1 にフォールバックします。 これをサポートする Windows バージョンでは、disablehttp2 SSL 証明書バインドの netsh http オプションによって、そのバインドの HTTP/2 が無効になります。 使用可能なオプションについては、 netsh http を参照してください。

HTTP/3 のサポート

次の基本要件が満たされている場合、ASP.NET Core アプリに対して HTTP/3 が有効になります。

上記の Windows 11 ビルド バージョンでは、Windows Insider ビルドの使用が必要になる場合があります。

HTTP/3 は、alt-svc ヘッダーを介して HTTP/1.1 または HTTP/2 からのアップグレードとして検出されます。 これは、最初の要求では HTTP/3 に切り替える前に、通常 HTTP/1.1 または HTTP/2 が使用されることを意味します。 Http.Sys によって alt-svc ヘッダーは自動的に追加されないため、アプリケーションで追加する必要があります。 次のコードは、alt-svc 応答ヘッダーを追加するミドルウェアの例を示しています。

app.Use((context, next) =>
{
    context.Response.Headers.AltSvc = "h3=\":443\"";
    return next(context);
});

上記のコードを要求パイプラインの早い段階に配置します。

Http.Sys では、HTTP/3 が使用可能であることをクライアントに通知するために、応答ヘッダーではなく AltSvc HTTP/2 プロトコル メッセージの送信もサポートされています。 EnableAltSvc レジストリ キーに関するページを参照してください。

Note

これには、IP アドレスではなくホスト名を使用する netsh sslcert バインドが必要です。 次のipport コマンドでhostnameportをnetsh http add sslcertに置き換え、IP アドレスをホスト名に置き換えます (例: www.example.com)。 hostnameport パラメーターを指定しない限り、certstorenameの使用が失敗する既知の問題もあります。 既定では、 certstorename=MYを使用します。

Kerberos を使用したカーネル モード認証

HTTP.sys では、Kerberos 認証プロトコルを使用したカーネル モード認証に処理が委任されます。 Kerberos および HTTP.sys ではユーザー モード認証がサポートされていません。 コンピューター アカウントを使用して、Active Directoryから取得した Kerberos トークン/チケットを復号化し、クライアントからサーバーに転送してユーザーを認証する必要があります。 アプリのユーザーではなく、ホストのサービス プリンシパル名 (SPN) を登録します。

チャネル バインド トークン (CBT) のセキュリティ強化を有効にする

チャネル バインド トークン (CBT) は、基になる TLS チャネルにWindows 認証を結び付け、NTLM リレーと中間者攻撃を軽減するのに役立ちます。

HttpAuthenticationHardeningLevelを使用して CBT のセキュリティ強化を構成します。 使用可能な HttpAuthenticationHardeningLevel 値は次のとおりです。

Value Behavior
Legacy チャネル バインド検証を適用したり、CBT バイトをアプリに公開したりしません。
Medium (既定値) クライアントが CBT を提供した場合は検証しますが、CBT がなくても許可します。 CBTバイトをアプリに提供します。
Strict 認証された要求に対して CBT を要求し、CBT がない要求を拒否します。 CBT バイトをアプリに公開します。

次の例では、Strict のセキュリティ強化を有効にします。

builder.WebHost.UseHttpSys(options =>
{
    options.HttpAuthenticationHardeningLevel =
        HttpAuthenticationHardeningLevel.Strict;
});

HTTP.sys が Strict のセキュリティ強化を適用できない場合、サーバーの起動は HttpSysException で失敗します。 Legacy または Medium の場合、設定を適用できなかったことがログに記録され、起動が続行されます。 構成された値だけでは、オペレーティング システムが設定を適用したとは限りません。

Warning

Strict CBT のセキュリティ強化により、有効な CBT を提供していないクライアントまたはプロキシの Windows 認証 が失敗する可能性があります。 運用環境で有効にする前に、環境内でクライアントの互換性と TLS 終端をテストします。

既存の要求キューにアタッチする場合は、URL グループを所有するリスナーに対してセキュリティ強化を構成します。 アタッチするアプリは、URL グループ構成を適用しません。

CBT バイトへのアクセスについては、「 チャネル バインド トークンの取得」を参照してください。

Microsoft.AspNetCore.Server.HttpSys.EnableCBTHardening AppContext スイッチを true に設定して、Windows 認証を使用する HTTPS エンドポイントの CBT セキュリティ強化を選択します。 このスイッチは、提供された CBT を検証するが、存在しなくても許可する中程度の強化を選択します。

プロジェクトの runtimeconfig.template.json ファイルでスイッチを有効にします。

{
  "configProperties": {
    "Microsoft.AspNetCore.Server.HttpSys.EnableCBTHardening": true
  }
}

または、 Program ファイルでホストをビルドする前に、プログラムでスイッチを設定します。

AppContext.SetSwitch("Microsoft.AspNetCore.Server.HttpSys.EnableCBTHardening", true);

Warning

CBT のセキュリティ強化は既定でオフになっています。 これを有効にすると、チャネル バインドをサポートしていないクライアントまたはプロキシのWindows 認証が失敗する可能性があります。 運用環境で有効にする前に、環境で十分にテストします。

カーネル モード応答バッファリングのサポート

一部のシナリオでは、待機時間の長い少量の書き込みが大量に発生すると、HTTP.sys のパフォーマンスに大きな影響を与える場合があります。 この影響は、Pipe に HTTP.sys バッファーが実装されていないことが原因です。 これらのシナリオでパフォーマンスを向上させるため、HTTP.sys では応答バッファリングがサポートされています。 EnableKernelResponseBufferingを true に設定して、バッファリングを有効にします。 応答バッファリングは、同期 I/O を実行するアプリで、または非同期 I/O で未処理の書き込みを一度に 1 つしか実行しないアプリで有効にする必要があります。 これらのシナリオでは、応答バッファリングにより、待機時間の長い接続に対してスループットが大幅に向上する場合があります。

非同期 I/O を使用し、未処理の書き込みを一度に複数実行する場合があるアプリでは、このフラグを使用しないでください。 このフラグを有効にすると、HTTP.Sys により CPU とメモリの使用率が高くなる場合があります。

HTTP.sys の使用方法

HTTP.sysを使用するように ASP.NET Core アプリを構成する

ホストを構築するときに UseHttpSys 拡張メソッドを呼び出し、必要な HttpSysOptions を指定します。 次の例では、既定値にオプションを設定しています。

using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.HttpSys;

var builder = WebApplication.CreateBuilder(args);

builder.WebHost.UseHttpSys(options =>
{
    options.AllowSynchronousIO = false;
    options.Authentication.Schemes = AuthenticationSchemes.None;
    options.Authentication.AllowAnonymous = true;
    options.MaxConnections = null;
    options.MaxRequestBodySize = 30_000_000;
    options.UrlPrefixes.Add("http://localhost:5005");
});

builder.Services.AddRazorPages();

var app = builder.Build();

HTTP.sys の追加の構成は、レジストリ設定を通じて処理されます。

HTTP.sys オプションの詳細については、「HttpSysOptions」を参照してください。

セキュリティ記述子をカスタマイズする

HTTP.sys の 要求キュー は、受信 HTTP 要求を処理する準備ができるまで一時的に格納するカーネル レベルの構造です。 RequestQueueSecurityDescriptorを使用して、要求キューへのアクセスを管理します。 HTTP.sys サーバーを構成するときに、 GenericSecurityDescriptor インスタンスに設定します。

セキュリティ記述子をカスタマイズすることで、要求キューへの特定のユーザーまたはグループのアクセスを許可または拒否できます。 これは、オペレーティング システム レベルで HTTP.sys 要求処理を制限または委任するシナリオで役立ちます。

たとえば、次のコードでは、認証されたすべてのユーザーが許可されますが、ゲストは拒否されます。

using System.Security.AccessControl;
using System.Security.Principal;
using Microsoft.AspNetCore.Server.HttpSys;

// Create a new security descriptor
var securityDescriptor = new CommonSecurityDescriptor(isContainer: false, isDS: false, sddlForm: string.Empty);

// Create a discretionary access control list (DACL)
var dacl = new DiscretionaryAcl(isContainer: false, isDS: false, capacity: 2);
dacl.AddAccess(
    AccessControlType.Allow,
    new SecurityIdentifier(WellKnownSidType.AuthenticatedUserSid, null),
    -1,
    InheritanceFlags.None,
    PropagationFlags.None
);
dacl.AddAccess(
    AccessControlType.Deny,
    new SecurityIdentifier(WellKnownSidType.BuiltinGuestsSid, null),
    -1,
    InheritanceFlags.None,
    PropagationFlags.None
);

// Assign the DACL to the security descriptor
securityDescriptor.DiscretionaryAcl = dacl;

// Configure HTTP.sys options
var builder = WebApplication.CreateBuilder();
builder.WebHost.UseHttpSys(options =>
{
    options.RequestQueueSecurityDescriptor = securityDescriptor;
});

RequestQueueSecurityDescriptor プロパティは、新しい要求キューを作成する場合にのみ適用されます。 このプロパティは、既存の要求キューには影響しません。 RequestQueueModeがAttach既存のキューを開くと、RequestQueueSecurityDescriptorやRequestQueueLimitなどのキュー レベルのオプションは適用されません。 Attach モードでは、タイムアウトや認証のセキュリティ強化などの URL グループ設定を URL グループを所有するリスナーによって構成する必要があり、UrlPrefixesはPathBaseの計算にのみ使用されます。 CreateOrAttach は、キューが既に存在する場合でも、独自の URL グループを構成し、その UrlPrefixesを登録します。別のリスナーによって既に登録されているプレフィックスの設定は、そのリスナーによって引き続き制御されます。

MaxRequestBodySize

要求本文の最大許容サイズ (バイト単位) です。 null に設定する場合、要求本文の最大サイズは制限されません。 この制限は、アップグレード済みの接続 (常に無制限) には影響しません。

1 つの IActionResult の ASP.NET Core MVC アプリの制限をオーバーライドするには、アクション メソッドで RequestSizeLimitAttribute 属性を使用することをお勧めします。

[RequestSizeLimit(100000000)]
public IActionResult MyActionMethod()

アプリが要求の読み取りを開始した後に、アプリが要求に対する制限を構成しようとすると、例外がスローされます。 IsReadOnly プロパティを使用して、MaxRequestBodySize プロパティが読み取り専用状態にあるかどうか、つまり制限を構成するには遅すぎるかどうかを示すことができます。

要求ごとにアプリで MaxRequestBodySize をオーバーライドする必要がある場合は、IHttpMaxRequestBodySizeFeature を使います。

app.Use((context, next) =>
{
    context.Features.GetRequiredFeature<IHttpMaxRequestBodySizeFeature>()
                                             .MaxRequestBodySize = 10 * 1024;

    var server = context.RequestServices
        .GetRequiredService<IServer>();
    var serverAddressesFeature = server.Features
                                 .GetRequiredFeature<IServerAddressesFeature>();

    var addresses = string.Join(", ", serverAddressesFeature.Addresses);

    var loggerFactory = context.RequestServices
        .GetRequiredService<ILoggerFactory>();
    var logger = loggerFactory.CreateLogger("Sample");

    logger.LogInformation("Addresses: {addresses}", addresses);

    return next(context);
});

Visual Studioを使用している場合は、アプリが IIS または IIS Express を実行するように構成されていないことを確認します。

Visual Studioでは、既定の起動プロファイルは IIS Express 用です。 プロジェクトをコンソール アプリとして実行するには、次のスクリーンショットに示すように、選択したプロファイルを手動で変更します。

コンソール アプリ プロファイルを選択する

Windows Serverの構成

  1. アプリ用に開くポートを決定し、Windows Firewall または New-NetFirewallRule PowerShell コマンドレットを使用してファイアウォール ポートを開き、トラフィックが HTTP.sysに到達できるようにします。 次のコマンドとアプリの構成では、ポート 443 を使用します。

  2. Azure VM にデプロイするときは、Network セキュリティ グループでポートを開きます。 次のコマンドとアプリの構成では、ポート 443 を使用します。

  3. 必要に応じて、X.509 証明書を取得してインストールします。

    Windowsで、New-SelfSignedCertificate PowerShell コマンドレットを使用して自己署名証明書を作成します。 サポート対象外の例については、UpdateIISExpressSSLForChrome.ps1 を参照してください。

    自己署名証明書か CA 署名証明書のいずれかをサーバーの Local Machine>Personal ストアにインストールします。

  4. アプリがフレームワークに依存する展開である場合は、一致する ASP.NET Core Runtime と .NET Runtime を .NET ダウンロードからインストールします。 .NET SDK はサーバーでは必要ありません。 ASP.NET Coreは、.NET Framework を対象としていません。 インストーラーの内容については、「適切なランタイムの選択」を参照してください。

    アプリが自己完結型の展開の場合、アプリの展開内にランタイムが含まれています。 サーバーにフレームワークをインストールする必要はありません。

  5. アプリに URL とポートを構成します。

    既定では、ASP.NET Coreは http://localhost:5000 にバインドされます。 URL プレフィックスとポートを構成するには、次のオプションがあります。

    次のコード例は、サーバーのローカル IP アドレス UrlPrefixes を使ってポート 443 上で 10.0.0.4 を使う方法を示しています。

    var builder = WebApplication.CreateBuilder(args);
    
    builder.WebHost.UseHttpSys(options =>
    {
        options.UrlPrefixes.Add("https://10.0.0.4:443");
    });
    
    builder.Services.AddRazorPages();
    
    var app = builder.Build();
    

    UrlPrefixes の利点は、プレフィックスの形式が正しくなかった場合、すぐにエラー メッセージが生成されることです。

    UrlPrefixes の設定は UseUrls/urls/ASPNETCORE_URLS の設定をオーバーライドします。 したがって、UseUrls、urls、および ASPNETCORE_URLS 環境変数の利点は、Kestrel と HTTP.sys を簡単に切り替えられることです。

    HTTP.sys は、URL プレフィックスで次の 2 種類のワイルドカードを認識します:

    • * は 弱いバインディングであり、 フォールバック バインディングとも呼ばれます。 URL プレフィックスが http://*:5000 で、他の何かがポート 5000 にバインドされている場合、このバインディングは使用されません。
    • + は 強いバインドです。 URL プレフィックスが http://+:5000 の場合、このバインディングは他のポート 5000 バインドの前に使用されます。

    詳細については、「UrlPrefix 文字列」を参照してください。

    Warning

    最上位のワイルドカードのバインド ( http://*:80/ と http://+:80 ) は使用しては いけません 。 最上位のワイルドカードのバインドを使用すると、アプリにセキュリティの脆弱性が生じます。 これは、強力と脆弱の両方のワイルドカードに適用されます。 ワイルドカードではなく、明示的なホスト名か IP アドレスを使用してください。 親ドメイン全体を制御する場合、サブドメインのワイルドカードのバインド (たとえば、*.mysub.com) がセキュリティ リスクになることはありません (脆弱である *.com とは対照的)。 詳細については、RFC 9110: セクション 7.2: Host and :authorityを参照してください。

    アプリとコンテナーのほとんどの構成では、ホストやパスなどの他の制約を指定せずに、ポート 80 のようにリッスンするポートのみを定義します。 HTTP_PORTS HTTPS_PORTSは、Kestrelおよび HTTP.sys サーバーのリッスン ポートを指定する構成キーです。 キーは、 DOTNET_ または ASPNETCORE_ プレフィックスで定義された環境変数として指定することも、 appsettings.json ファイルなどの他の構成入力を使用して直接設定することもできます。 各構成は、次の例に示すように、ポート値のセミコロン区切りのリストです。

    ASPNETCORE_HTTP_PORTS=80;8080
    ASPNETCORE_HTTPS_PORTS=443;8081
    

    この例の構成は、スキーム (HTTP または HTTPS) と任意のホストまたは IP を定義する次の仕様の短縮形です。

    ASPNETCORE_URLS=http://*:80/;http://*:8080/;https://*:443/;https://*:8081/
    

    HTTP_PORTSおよびHTTPS_PORTS構成キーの優先順位は低くなります。 他の URL または値がコードで直接設定されている場合は、構成キーをオーバーライドできます。 HTTPS のサーバー固有のメカニズムを使用して、証明書を個別に構成します。

    Note

    Kestrel/HTTP.sys エンドポイント構成のポートを設定する HTTPS_PORTS 構成キーおよび ASPNETCORE_HTTPS_PORTS 環境変数と、HTTPS リダイレクト ミドルウェア のポートを設定する HTTPS_PORT 構成キーおよび ASPNETCORE_HTTPS_PORT 環境変数を混同しないでください。

    これらの構成キーは、最上位のワイルドカード バインドと同等です。 これらは開発およびコンテナーのシナリオには便利ですが、他のサービスもホストする可能性があるコンピューター上で実行する場合は、ワイルドカードを避けてください。

  6. サーバーで URL プレフィックスを事前登録します。

    HTTP.sys を構成するための組み込みツールは、netsh.exe です。 netsh.exe は、URL プレフィックスを予約し、X.509 証明書を割り当てるために使用されます。 ツールを使用するには管理者特権が必要です。

    netsh.exe ツールを使用して、アプリ用に URL を登録します。

    netsh http add urlacl url=<URL> user=<USER>
    
    • <URL>: 完全修飾 Uniform Resource Locator (URL)。 ワイルドカードのバインドは使用しないでください。 有効なホスト名かローカル IP アドレスを使用してください。 URL には末尾のスラッシュを含める必要があります。
    • <USER>: ユーザーまたはユーザー グループ名を指定します。

    次の例では、サーバーのローカル IP アドレスは 10.0.0.4 です。

    netsh http add urlacl url=https://10.0.0.4:443/ user=Users
    

    URL が登録されると、ツールから URL reservation successfully added という応答があります。

    登録済みの URL を削除するには、delete urlacl コマンドを使用します。

    netsh http delete urlacl url=<URL>
    
  7. サーバーで X.509 証明書を登録します。

    netsh.exe ツールを使用して、アプリ用の証明書を登録します。

    netsh http add sslcert ipport=<IP>:<PORT> certhash=<THUMBPRINT> appid="{<GUID>}"
    
    • <IP>: バインディングのローカル IP アドレスを指定します。 ワイルドカードのバインドは使用しないでください。 有効な IP アドレスを使用してください。
    • <PORT>: バインディングのポートを指定します。
    • <THUMBPRINT>: X.509 証明書のサムプリント。
    • <GUID>: 参考情報としてアプリを表す開発者が生成した GUID。

    参照用に、この GUID をパッケージ タグとしてアプリに格納します。

    • Visual Studio で:
      • アプリのプロジェクト プロパティを開くには、ソリューション エクスプローラー でアプリを右クリックし、Properties を選択します。
      • [パッケージ] タブを選択します。
      • 作成した GUID を [タグ] フィールドに入力します。
    • Visual Studioを使用しない場合:
      • アプリのプロジェクト ファイルを開きます。

      • 作成した GUID を指定した <PackageTags> プロパティを、新規または既存の <PropertyGroup> に追加します。

        <PropertyGroup>
          <PackageTags>00001111-aaaa-2222-bbbb-3333cccc4444</PackageTags>
        </PropertyGroup>
        

    次に例を示します。

    • サーバーのローカル IP アドレスは 10.0.0.4 です。
    • オンラインのランダム GUID ジェネレーターによって、appid の値が提供されます。
    netsh http add sslcert 
        ipport=10.0.0.4:443 
        certhash=b66ee04419d4ee37464ab8785ff02449980eae10 
        appid="{00001111-aaaa-2222-bbbb-3333cccc4444}"
    

    証明書が登録されると、ツールから SSL Certificate successfully added という応答があります。

    証明書の登録を削除するには、delete sslcert コマンドを使用します。

    netsh http delete sslcert ipport=<IP>:<PORT>
    

    以下は、netsh.exe のリファレンス ドキュメントです。

  8. アプリを実行します。

    URL 予約によって承認されたアカウントでアプリを実行します。 URL の予約と証明書のバインドを構成するには管理者特権が必要ですが、ID に必要な名前空間のアクセス許可を持つアプリを実行する必要はありません。 ローカル IP アドレスまたはポート 443 へのバインドだけでは、昇格されたアプリケーション プロセスを必要としません。 詳細については、「名前空間の予約、登録、ルーティング」を参照してください。

    サーバーのパブリック IP アドレスでアプリが応答します。 この例では、サーバーは自身のパブリック IP アドレス 104.214.79.47 でインターネットからアクセスされます。

    この例では開発証明書が使用されています。 証明書が信頼できないというブラウザーの警告がバイパスされた後に、ページが安全に読み込まれます。

    読み込まれたアプリの [インデックス] ページを示すブラウザー ウィンドウ

プロキシ サーバーとロード バランサーのシナリオ

インターネットや企業ネットワークからの要求とやりとりする HTTP.sys でホストされるアプリの場合、プロキシ サーバーやロード バランサーの背後でホストするとき、追加の構成が必要になることがあります。 詳細については、「プロキシ サーバーとロード バランサーを操作するための構成 ASP.NET Coreを参照してください。

Content-Length ヘッダーと最終的なコーディングがchunkedTransfer-Encoding ヘッダーの両方で要求を処理する場合、HTTP.sys はアプリに表示された要求ヘッダーからContent-Lengthを削除し、既定で応答した後に接続を閉じます。 プロキシは、競合する要求メッセージのフレーミングを送信しないでください。 この動作は、要求の密輸を防ぐのに役立ちます。これは、アプリに到達する前に、そのようなすべての要求が拒否されることを意味するわけではありません。

TLS と要求のプロパティを検査する

HTTP.sys は、TLS 情報を検査するための要求を検査するための機能を公開します。 可用性は、要求、Windowsバージョン、および HTTP.sys 構成によって異なります。

ネゴシエートされた TLS 暗号スイートを取得する

ITlsHandshakeFeature は、HTTP.sysの NegotiatedCipherSuite プロパティを介してネゴシエートされた暗号スイートを公開します。 この機能は、TLS 以外の要求では使用できません。 このプロパティは、Windowsがクエリをサポートしていない場合、またはクエリが失敗した場合にnullになることがあります。

var handshake = context.Features.Get<ITlsHandshakeFeature>();
if (handshake?.NegotiatedCipherSuite is { } cipherSuite)
{
    logger.LogInformation("Negotiated TLS cipher suite: {CipherSuite}", cipherSuite);
}
else
{
    logger.LogInformation("The negotiated TLS cipher suite isn't available.");
}

TLS ClientHello の読み取り

TryGetTlsClientHelloを使用して、必要に応じて生の TLS ClientHello バイトを取得します。 HTTPS サービス構成で HTTP_SERVICE_CONFIG_SSL_FLAG_ENABLE_CACHE_CLIENT_HELLOを有効にする必要があります。 HTTP.sys を使用するように ASP.NET Coreを構成しても、このネイティブ フラグは有効になりません。 「HttpSetServiceConfiguration」と「HTTP_SERVICE_CONFIG_ID」を参照してください。

まず、空のスパンでメソッドを呼び出して必要なバッファー サイズを取得し、バッファーを割り当てて再試行します。

var feature = context.Features.GetRequiredFeature<IHttpSysRequestPropertyFeature>();
_ = feature.TryGetTlsClientHello(Span<byte>.Empty, out var requiredSize);

var pooled = requiredSize <= 1024 ? ArrayPool<byte>.Shared.Rent(requiredSize) : null;
var buffer = pooled ?? new byte[requiredSize];
try
{
    if (!feature.TryGetTlsClientHello(buffer, out var bytesReturned))
    {
        throw new InvalidOperationException(
            $"The TLS ClientHello buffer must be resized to {bytesReturned} bytes.");
    }

    logger.LogInformation("Retrieved {ByteCount} TLS ClientHello bytes.", bytesReturned);
}
finally
{
    if (pooled is not null)
    {
        ArrayPool<byte>.Shared.Return(pooled);
    }
}

その他のネイティブ リクエスト プロパティを照会する

TryGetRequestProperty は、任意のネイティブ要求プロパティに対して HttpQueryRequestProperty を提供します。

  • propertyId は、ネイティブ HTTP_REQUEST_PROPERTY 列挙型の値を識別します。
  • qualifier には、省略可能なプロパティ固有のバイトが含まれています。 空のスパンは、null ポインターとしてWindowsに渡されます。
  • output はネイティブ バイトを受け取ります。 呼び出し元は、対応するネイティブ データ構造を使用してそれらを解釈する必要があります。
  • bytesReturned には、成功時に書き込まれたバイトが含まれます。 バッファー不足エラーの場合、必須サイズのレポートはネイティブ プロパティによって異なります。 固定サイズのプロパティの場合は、空のバッファー クエリが必要なサイズを報告すると想定するのではなく、対応するネイティブ構造体のサイズのバッファーを割り当てます。

次の例では、汎用 API を使用して TLS ClientHello プロパティに対してクエリを実行します。 TryGetTlsClientHelloと同じネイティブ ClientHello キャッシュ構成が必要です。

const int HttpRequestPropertyTlsClientHello = 11;
var feature = context.Features.GetRequiredFeature<IHttpSysRequestPropertyFeature>();
_ = feature.TryGetRequestProperty(
    HttpRequestPropertyTlsClientHello, qualifier: default, output: default,
    out var requiredSize);
var buffer = new byte[requiredSize];

if (!feature.TryGetRequestProperty(
    HttpRequestPropertyTlsClientHello, qualifier: default, output: buffer,
    out var bytesReturned))
{
    throw new InvalidOperationException(
        $"The request property buffer must be resized to {bytesReturned} bytes.");
}

logger.LogInformation("Retrieved {ByteCount} native request property bytes.", bytesReturned);

チャネル バインド トークンを取得する

TryGetChannelBindingBytes は、TLS チャネル バインド バイトへのアクセスを提供します。

var tls = context.Features.Get<ITlsConnectionFeature>();
if (tls is not null &&
    tls.TryGetChannelBindingBytes(ChannelBindingKind.Endpoint, out var token))
{
    logger.LogInformation("TLS endpoint binding contains {ByteCount} bytes.", token.Length);
}
else
{
    logger.LogInformation("TLS endpoint channel binding isn't available.");
}

HTTP.sys は をサポートしており、これは ChannelBindingKind.Endpoint で定義されている tls-server-end-point バインディングに対応します。 その他のバインドの種類では、 falseが返されます。 使用できないトークンもfalse返されます。 CBT 露出では、HTTP.sys によって適用される Medium または Strict認証のセキュリティ強化 が必要です。

CBT バイトを取得しても、それ自体でリクエストを認証したり、Strict のハードニングを強制したりすることはありません。 返されるバイトには、証明書ハッシュだけでなく、Windows SEC_CHANNEL_BINDINGS構造体とそのバインド データが含まれます。

IHttpSysRequestTimingFeature を使用して詳細なタイミング情報を取得する

IHttpSysRequestTimingFeature は、リクエストの詳細なタイミング情報を提供します:

  • タイムスタンプは、QueryPerformanceCounter を使用して取得されます。
  • タイムスタンプの頻度は、QueryPerformanceFrequency を使用して取得できます。
  • タイミングのインデックスを HttpSysRequestTimingType にキャストして、タイミングが何を表しているのかを把握できます。
  • 現在の要求でタイミングを利用できない場合、値は 0 になることがあります。
  • Windows 10 バージョン 2004、Windows Server 2022 以降が必要です。
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.HttpSys;

var builder = WebApplication.CreateBuilder(args);

builder.WebHost.UseHttpSys();

var app = builder.Build();

app.Use((context, next) =>
{
    var feature = context.Features.GetRequiredFeature<IHttpSysRequestTimingFeature>();
    
    var loggerFactory = context.RequestServices.GetRequiredService<ILoggerFactory>();
    var logger = loggerFactory.CreateLogger("Sample");

    var timestamps = feature.Timestamps;

    for (var i = 0; i < timestamps.Length; i++)
    {
        var timestamp = timestamps[i];
        var timingType = (HttpSysRequestTimingType)i;

        logger.LogInformation("Timestamp {timingType}: {timestamp}",
                                          timingType, timestamp);
    }

    return next(context);
});

app.MapGet("/", () => Results.Ok());

app.Run();

IHttpSysRequestTimingFeature.TryGetTimestamp は、指定されたタイミングの種類のタイムスタンプを取得します。

using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.HttpSys;
var builder = WebApplication.CreateBuilder(args);

builder.WebHost.UseHttpSys();

var app = builder.Build();

app.Use((context, next) =>
{
    var feature = context.Features.GetRequiredFeature<IHttpSysRequestTimingFeature>();

    var loggerFactory = context.RequestServices.GetRequiredService<ILoggerFactory>();
    var logger = loggerFactory.CreateLogger("Sample");

    var timingType = HttpSysRequestTimingType.RequestRoutingEnd;

    if (feature.TryGetTimestamp(timingType, out var timestamp))
    {
        logger.LogInformation("Timestamp {timingType}: {timestamp}",
                                          timingType, timestamp);
    }
    else
    {
        logger.LogInformation("Timestamp {timingType}: not available for the "
                                           + "current request",    timingType);
    }

    return next(context);
});

app.MapGet("/", () => Results.Ok());

app.Run();

IHttpSysRequestTimingFeature.TryGetElapsedTime は、指定された 2 つのタイミング間の経過時間を生成します。

using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.HttpSys;

var builder = WebApplication.CreateBuilder(args);

builder.WebHost.UseHttpSys();

var app = builder.Build();

app.Use((context, next) =>
{
    var feature = context.Features.GetRequiredFeature<IHttpSysRequestTimingFeature>();

    var loggerFactory = context.RequestServices.GetRequiredService<ILoggerFactory>();
    var logger = loggerFactory.CreateLogger("Sample");

    var startingTimingType = HttpSysRequestTimingType.RequestRoutingStart;
    var endingTimingType = HttpSysRequestTimingType.RequestRoutingEnd;

    if (feature.TryGetElapsedTime(startingTimingType, endingTimingType, out var elapsed))
    {
        logger.LogInformation(
            "Elapsed time {startingTimingType} to {endingTimingType}: {elapsed}",
            startingTimingType,
            endingTimingType,
            elapsed);
    }
    else
    {
        logger.LogInformation(
            "Elapsed time {startingTimingType} to {endingTimingType}:"
            + " not available for the current request.",
            startingTimingType,
            endingTimingType);
    }

    return next(context);
});

app.MapGet("/", () => Results.Ok());

app.Run();

gRPC をサポートする高度な HTTP/2 機能

HTTP.sys 内の追加の HTTP/2 機能によって、gRPC がサポートされています。これには、応答トレーラーやリセット フレームの送信に関するサポートが含まれます。

HTTP.sys で gRPC を実行するための要件:

  • ビルド 22000 以降Windows 11、ビルド 20348 以降Windows Server 2022。
  • TLS 1.2 またはそれ以降の接続。

Trailers

HTTP トレーラーは HTTP ヘッダーに似ていますが、応答本文の送信後に送信される点が異なります。 IIS と HTTP.sys の場合は、HTTP/2 応答トレーラーのみがサポートされています。

if (httpContext.Response.SupportsTrailers())
{
    httpContext.Response.DeclareTrailer("trailername");	

    // Write body
    httpContext.Response.WriteAsync("Hello world");

    httpContext.Response.AppendTrailer("trailername", "TrailerValue");
}

上記のコード例では次のようになっています。

  • SupportsTrailers によって、応答におけるトレーラーがサポートされることが確実になります。
  • DeclareTrailer によって、指定したトレーラー名が Trailer 応答ヘッダーに追加されます。 応答のトレーラーを宣言することは省略可能ですが、推奨されています。 DeclareTrailer を呼び出す場合、それは、応答ヘッダーを送信する前に行う必要があります。
  • AppendTrailer によって、トレーラーが追加されます。

Reset

リセットを使用すると、指定されたエラー コードを使用してサーバーに HTTP/2 要求をリセットさせることができます。 リセット要求は中止されたと見なされます。

var resetFeature = httpContext.Features.Get<IHttpResetFeature>();
resetFeature.Reset(errorCode: 2);

上記のコード例の Reset により、INTERNAL_ERROR エラー コードが指定されています。 HTTP/2 エラー コードの詳細については、HTTP/2 仕様の「エラーコード」セクションを参照してください。

Tracing

HTTP.sys からトレースを取得する方法については、「HTTP.sys 管理のシナリオ」を参照してください。

メモリ プールからの自動削除

Kestrel、IIS、および HTTP.sys によって使用されるメモリ プールは、アプリケーションがアイドル状態または負荷が低い場合に、メモリ ブロックを自動的に削除します。 この機能は自動的に実行され、手動で有効または構成する必要はありません。

.NET 10 より前のバージョンでは、プールによって割り当てられたメモリは、使用されていない場合でも予約されたままになります。 この自動削除機能は、全体的なメモリ使用量を削減し、さまざまなワークロードでアプリケーションの応答性を維持するのに役立ちます。

メモリプールの指標を使用する

ASP.NET Core サーバーの実装で使用される既定のメモリ プールには、メモリ使用量パターンの監視と分析に使用できるメトリックが含まれています。 メトリックは "Microsoft.AspNetCore.MemoryPool" という名前の下にあります。

メトリックとその使用方法については、「ASP.NET Core metrics」を参照してください。

メモリ プールの管理

不要なメモリ ブロックを削除してメモリ プールを効率的に使用するだけでなく、ASP.NET Coreは組み込みの IMemoryPoolFactory と実装を提供します。 依存関係の挿入により、アプリケーションで実装を使用できるようになります。

次のコード例は、組み込みのメモリ プール ファクトリ実装を使用してメモリ プールを作成する単純なバックグラウンド サービスを示しています。 これらのプールは、自動削除機能の利点があります。

public class MyBackgroundService : BackgroundService
{
    private readonly MemoryPool<byte> _memoryPool;

    public MyBackgroundService(IMemoryPoolFactory<byte> factory)
    {
        _memoryPool = factory.Create();
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
                await Task.Delay(20, stoppingToken);
                // do work that needs memory
                // consider checking _memoryPool.MaxBufferSize
                var rented = _memoryPool.Rent(100);
                rented.Dispose();
            }
            catch (OperationCanceledException)
            {
                return;
            }
        }
    }
}

カスタム メモリ プール ファクトリを使用するには、次の例のように、 IMemoryPoolFactory を実装するクラスを作成し、依存関係の挿入に登録します。 この方法で作成されたメモリ プールは、カスタム ファクトリで同様の削除ロジックを実装しない限り、自動削除機能の恩恵を受けません。

services.AddSingleton<IMemoryPoolFactory<byte>,
CustomMemoryPoolFactory>();

public class CustomMemoryPoolFactory : IMemoryPoolFactory<byte>
{
    public MemoryPool<byte> Create()
    {
        // Return a custom MemoryPool implementation
        // or the default, as is shown here.
        return MemoryPool<byte>.Shared;
    }
}

メモリ プールを使用している場合は、プールの MaxBufferSizeに注意してください。

HTTP.sys は、Windowsでのみ実行される ASP.NET Core用の Web サーバーです。 HTTP.sys は Kestrel サーバーの代替製品であり、Kestrel では提供されていない機能がいくつか用意されています。

Important

HTTP.sys は、ASP.NET Core モジュールと互換性がありません。IIS または IIS Express では使用できません。

HTTP.sys は、次の機能をサポートします。

  • Windows認証
  • ポート共有
  • SNI を使用する HTTPS
  • TLS 経由の HTTP/2 (Windows 10 以降)
  • 直接ファイル伝送
  • 応答のキャッシュ
  • WebSocket (Windows 8 以降)

サポートされているWindowsバージョン:

  • Windows 7以降
  • Windows Server 2008 R2 以降

サンプル コードを表示またはダウンロードします (ダウンロード方法)。

HTTP.sys を使用するタイミング

HTTP.sys は、次のような展開に適しています。

  • IIS を使用せず、インターネットに直接サーバーを公開する必要がある。

    HTTP.sys がインターネットと直接通信する

  • 内部の展開から Kestrel では使用できない機能が要求されている。 詳細については、Kestrel と HTTP.sys の比較に関するページを参照してください。

    HTTP.sys は内部ネットワークと直接通信します

HTTP.sys は、さまざまな種類の攻撃を防ぎ、フル機能の Web サーバーとして堅牢性、セキュリティ、スケーラビリティを提供する、成熟したテクノロジです。 IIS 自体が、HTTP.sys 上で HTTP リスナーとして実行されています。

HTTP/2 のサポート

次の基本要件が満たされている場合、ASP.NET Core アプリに対して HTTP/2 が有効になります。

Http/2 接続が確立されると、HttpRequest.Protocol が HTTP/2 を報告します。

HTTP/2 は既定で有効になっています。 Http/2 接続が確立されない場合、接続は http/1.1 にフォールバックします。 Windowsの今後のリリースでは、HTTP.sysで HTTP/2 を無効にする機能など、HTTP/2 構成フラグを使用できるようになります。

HTTP/3 のサポート

次の基本要件が満たされている場合、ASP.NET Core アプリに対して HTTP/3 が有効になります。

上記の Windows 11 ビルド バージョンでは、Windows Insider ビルドの使用が必要になる場合があります。

HTTP/3 は、alt-svc ヘッダーを介して HTTP/1.1 または HTTP/2 からのアップグレードとして検出されます。 これは、最初の要求では HTTP/3 に切り替える前に、通常 HTTP/1.1 または HTTP/2 が使用されることを意味します。 Http.Sys によって alt-svc ヘッダーは自動的に追加されないため、アプリケーションで追加する必要があります。 次のコードは、alt-svc 応答ヘッダーを追加するミドルウェアの例を示しています。

app.Use((context, next) =>
{
    context.Response.Headers.AltSvc = "h3=\":443\"";
    return next(context);
});

上記のコードを要求パイプラインの早い段階に配置します。

Http.Sys では、HTTP/3 が使用可能であることをクライアントに通知するために、応答ヘッダーではなく AltSvc HTTP/2 プロトコル メッセージの送信もサポートされています。 EnableAltSvc レジストリ キーに関するページを参照してください。 これには、IP アドレスではなくホスト名を使用する netsh sslcert バインドが必要です。

Kerberos を使用したカーネル モード認証

HTTP.sys では、Kerberos 認証プロトコルを使用したカーネル モード認証に処理が委任されます。 Kerberos および HTTP.sys ではユーザー モード認証がサポートされていません。 コンピューター アカウントを使用して、Active Directoryから取得した Kerberos トークン/チケットを復号化し、クライアントからサーバーに転送してユーザーを認証する必要があります。 アプリのユーザーではなく、ホストのサービス プリンシパル名 (SPN) を登録します。

HTTP.sys の使用方法

HTTP.sysを使用するように ASP.NET Core アプリを構成する

ホストを構築するときに UseHttpSys 拡張メソッドを呼び出し、必要な HttpSysOptions を指定します。 次の例では、既定値にオプションを設定しています。

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseHttpSys(options =>
            {
                options.AllowSynchronousIO = false;
                options.Authentication.Schemes = AuthenticationSchemes.None;
                options.Authentication.AllowAnonymous = true;
                options.MaxConnections = null;
                options.MaxRequestBodySize = 30000000;
                options.UrlPrefixes.Add("http://localhost:5005");
            });
            webBuilder.UseStartup<Startup>();
        });

HTTP.sys の追加の構成は、レジストリ設定を通じて処理されます。

HTTP.sys オプションの詳細については、「HttpSysOptions」を参照してください。

MaxRequestBodySize

要求本文の最大許容サイズ (バイト単位) です。 null に設定する場合、要求本文の最大サイズは制限されません。 この制限は、アップグレード済みの接続 (常に無制限) には影響しません。

1 つの IActionResult の ASP.NET Core MVC アプリの制限をオーバーライドするには、アクション メソッドで RequestSizeLimitAttribute 属性を使用することをお勧めします。

[RequestSizeLimit(100000000)]
public IActionResult MyActionMethod()

アプリが要求の読み取りを開始した後に、アプリが要求に対する制限を構成しようとすると、例外がスローされます。 IsReadOnly プロパティを使用して、MaxRequestBodySize プロパティが読み取り専用状態にあるかどうか、つまり制限を構成するには遅すぎるかどうかを示すことができます。

要求ごとにアプリで MaxRequestBodySize をオーバーライドする必要がある場合は、IHttpMaxRequestBodySizeFeature を使います。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, 
    ILogger<Startup> logger, IServer server)
{
    app.Use(async (context, next) =>
    {
        context.Features.Get<IHttpMaxRequestBodySizeFeature>()
            .MaxRequestBodySize = 10 * 1024;

        var serverAddressesFeature = 
            app.ServerFeatures.Get<IServerAddressesFeature>();
        var addresses = string.Join(", ", serverAddressesFeature?.Addresses);

        logger.LogInformation("Addresses: {Addresses}", addresses);

        await next.Invoke();
    });

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
    }

    app.UseStaticFiles();
    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

Visual Studioを使用している場合は、アプリが IIS または IIS Express を実行するように構成されていないことを確認します。

Visual Studioでは、既定の起動プロファイルは IIS Express 用です。 プロジェクトをコンソール アプリとして実行するには、次のスクリーンショットに示すように、選択したプロファイルを手動で変更します。

コンソール アプリ プロファイルを選択する

Windows Serverの構成

  1. アプリ用に開くポートを決定し、Windows Firewall または New-NetFirewallRule PowerShell コマンドレットを使用してファイアウォール ポートを開き、トラフィックが HTTP.sysに到達できるようにします。 次のコマンドとアプリの構成では、ポート 443 を使用します。

  2. Azure VM にデプロイするときは、Network セキュリティ グループでポートを開きます。 次のコマンドとアプリの構成では、ポート 443 を使用します。

  3. 必要に応じて、X.509 証明書を取得してインストールします。

    Windowsで、New-SelfSignedCertificate PowerShell コマンドレットを使用して自己署名証明書を作成します。 サポート対象外の例については、UpdateIISExpressSSLForChrome.ps1 を参照してください。

    自己署名証明書か CA 署名証明書のいずれかをサーバーの Local Machine>Personal ストアにインストールします。

  4. アプリが framework 依存のデプロイの場合は、.NET、.NET Framework、またはその両方をインストールします (アプリが .NET Framework を対象とする.NET アプリの場合)。

    • .NET: アプリで .NET が必要な場合は、.NET ダウンロード から .NET ランタイム インストーラーを取得して実行します。 サーバーに SDK 全体をインストールしないでください。
    • .NET Framework: アプリに .NET Framework が必要な場合は、.NET Framework のインストール ガイドを参照してください。 必要な .NET Framework をインストールします。 最新の .NET Framework のインストーラーは、.NET ダウンロード ページから入手できます。

    アプリが自己完結型の展開の場合、アプリの展開内にランタイムが含まれています。 サーバーにフレームワークをインストールする必要はありません。

  5. アプリに URL とポートを構成します。

    既定では、ASP.NET Coreは http://localhost:5000 にバインドされます。 URL プレフィックスとポートを構成するには、次のオプションがあります。

    次のコード例は、サーバーのローカル IP アドレス UrlPrefixes を使ってポート 443 上で 10.0.0.4 を使う方法を示しています。

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseHttpSys(options =>
                {
                    options.UrlPrefixes.Add("https://10.0.0.4:443");
                });
                webBuilder.UseStartup<Startup>();
            });
    

    UrlPrefixes の利点は、プレフィックスの形式が正しくなかった場合、すぐにエラー メッセージが生成されることです。

    UrlPrefixes の設定は UseUrls/urls/ASPNETCORE_URLS の設定をオーバーライドします。 したがって、UseUrls、urls、および ASPNETCORE_URLS 環境変数の利点は、Kestrel と HTTP.sys を簡単に切り替えられることです。

    HTTP.sys では、HTTP サーバー API の UrlPrefix 文字列形式が使用されます。

    Warning

    最上位のワイルドカードのバインド ( http://*:80/ と http://+:80 ) は使用しては いけません 。 最上位のワイルドカードのバインドを使用すると、アプリにセキュリティの脆弱性が生じます。 これは、強力と脆弱の両方のワイルドカードに適用されます。 ワイルドカードではなく、明示的なホスト名か IP アドレスを使用してください。 親ドメイン全体を制御する場合、サブドメインのワイルドカードのバインド (たとえば、*.mysub.com) がセキュリティ リスクになることはありません (脆弱である *.com とは対照的)。 詳細については、RFC 9110: セクション 7.2: Host and :authorityを参照してください。

  6. サーバーで URL プレフィックスを事前登録します。

    HTTP.sys を構成するための組み込みツールは、netsh.exe です。 netsh.exe は、URL プレフィックスを予約し、X.509 証明書を割り当てるために使用されます。 ツールを使用するには管理者特権が必要です。

    netsh.exe ツールを使用して、アプリ用に URL を登録します。

    netsh http add urlacl url=<URL> user=<USER>
    
    • <URL>: 完全修飾 Uniform Resource Locator (URL)。 ワイルドカードのバインドは使用しないでください。 有効なホスト名かローカル IP アドレスを使用してください。 URL には末尾のスラッシュを含める必要があります。
    • <USER>: ユーザーまたはユーザー グループ名を指定します。

    次の例では、サーバーのローカル IP アドレスは 10.0.0.4 です。

    netsh http add urlacl url=https://10.0.0.4:443/ user=Users
    

    URL が登録されると、ツールから URL reservation successfully added という応答があります。

    登録済みの URL を削除するには、delete urlacl コマンドを使用します。

    netsh http delete urlacl url=<URL>
    
  7. サーバーで X.509 証明書を登録します。

    netsh.exe ツールを使用して、アプリ用の証明書を登録します。

    netsh http add sslcert ipport=<IP>:<PORT> certhash=<THUMBPRINT> appid="{<GUID>}"
    
    • <IP>: バインディングのローカル IP アドレスを指定します。 ワイルドカードのバインドは使用しないでください。 有効な IP アドレスを使用してください。
    • <PORT>: バインディングのポートを指定します。
    • <THUMBPRINT>: X.509 証明書のサムプリント。
    • <GUID>: 参考情報としてアプリを表す開発者が生成した GUID。

    参照用に、この GUID をパッケージ タグとしてアプリに格納します。

    • Visual Studio で:
      • アプリのプロジェクト プロパティを開くには、ソリューション エクスプローラー でアプリを右クリックし、Properties を選択します。
      • [パッケージ] タブを選択します。
      • 作成した GUID を [タグ] フィールドに入力します。
    • Visual Studioを使用しない場合:
      • アプリのプロジェクト ファイルを開きます。

      • 作成した GUID を指定した <PackageTags> プロパティを、新規または既存の <PropertyGroup> に追加します。

        <PropertyGroup>
          <PackageTags>00001111-aaaa-2222-bbbb-3333cccc4444</PackageTags>
        </PropertyGroup>
        

    次に例を示します。

    • サーバーのローカル IP アドレスは 10.0.0.4 です。
    • オンラインのランダム GUID ジェネレーターによって、appid の値が提供されます。
    netsh http add sslcert 
        ipport=10.0.0.4:443 
        certhash=b66ee04419d4ee37464ab8785ff02449980eae10 
        appid="{00001111-aaaa-2222-bbbb-3333cccc4444}"
    

    証明書が登録されると、ツールから SSL Certificate successfully added という応答があります。

    証明書の登録を削除するには、delete sslcert コマンドを使用します。

    netsh http delete sslcert ipport=<IP>:<PORT>
    

    以下は、netsh.exe のリファレンス ドキュメントです。

  8. アプリを実行します。

    1024 より大きいポート番号で (HTTPS ではなく) HTTP を使用して localhost にバインドする場合、アプリの実行に管理者権限は必要ありません。 その他の構成の場合 (たとえば、ローカル IP アドレスを使用する場合やポート 443 にバインドする場合)、管理者権限でアプリを実行します。

    サーバーのパブリック IP アドレスでアプリが応答します。 この例では、サーバーは自身のパブリック IP アドレス 104.214.79.47 でインターネットからアクセスされます。

    この例では開発証明書が使用されています。 証明書が信頼できないというブラウザーの警告がバイパスされた後に、ページが安全に読み込まれます。

    読み込まれたアプリの [インデックス] ページを示すブラウザー ウィンドウ

プロキシ サーバーとロード バランサーのシナリオ

インターネットや企業ネットワークからの要求とやりとりする HTTP.sys でホストされるアプリの場合、プロキシ サーバーやロード バランサーの背後でホストするとき、追加の構成が必要になることがあります。 詳細については、「プロキシ サーバーとロード バランサーを操作するための構成 ASP.NET Coreを参照してください。

gRPC をサポートする高度な HTTP/2 機能

HTTP.sys 内の追加の HTTP/2 機能によって、gRPC がサポートされています。これには、応答トレーラーやリセット フレームの送信に関するサポートが含まれます。

HTTP.sys で gRPC を実行するための要件:

  • ビルド 22000 以降Windows 11、ビルド 20348 以降Windows Server 2022。
  • TLS 1.2 またはそれ以降の接続。

Trailers

HTTP トレーラーは HTTP ヘッダーに似ていますが、応答本文の送信後に送信される点が異なります。 IIS と HTTP.sys の場合は、HTTP/2 応答トレーラーのみがサポートされています。

if (httpContext.Response.SupportsTrailers())
{
    httpContext.Response.DeclareTrailer("trailername");	

    // Write body
    httpContext.Response.WriteAsync("Hello world");

    httpContext.Response.AppendTrailer("trailername", "TrailerValue");
}

上記のコード例では次のようになっています。

  • SupportsTrailers によって、応答におけるトレーラーがサポートされることが確実になります。
  • DeclareTrailer によって、指定したトレーラー名が Trailer 応答ヘッダーに追加されます。 応答のトレーラーを宣言することは省略可能ですが、推奨されています。 DeclareTrailer を呼び出す場合、それは、応答ヘッダーを送信する前に行う必要があります。
  • AppendTrailer によって、トレーラーが追加されます。

Reset

リセットを使用すると、指定されたエラー コードを使用してサーバーに HTTP/2 要求をリセットさせることができます。 リセット要求は中止されたと見なされます。

var resetFeature = httpContext.Features.Get<IHttpResetFeature>();
resetFeature.Reset(errorCode: 2);

上記のコード例の Reset により、INTERNAL_ERROR エラー コードが指定されています。 HTTP/2 エラー コードの詳細については、HTTP/2 仕様の「エラーコード」セクションを参照してください。

HTTP.sys は、Windowsでのみ実行される ASP.NET Core用の Web サーバーです。 HTTP.sys は Kestrel サーバーの代替製品であり、Kestrel では提供されていない機能がいくつか用意されています。

Important

HTTP.sys は、ASP.NET Core モジュールと互換性がありません。IIS または IIS Express では使用できません。

HTTP.sys は、次の機能をサポートします。

  • Windows認証
  • ポート共有
  • SNI を使用する HTTPS
  • TLS 経由の HTTP/2 (Windows 10 以降)
  • 直接ファイル伝送
  • 応答のキャッシュ
  • WebSocket (Windows 8 以降)

サポートされているWindowsバージョン:

  • Windows 7以降
  • Windows Server 2008 R2 以降

サンプル コードを表示またはダウンロードします (ダウンロード方法)。

HTTP.sys を使用するタイミング

HTTP.sys は、次のような展開に適しています。

  • IIS を使用せず、インターネットに直接サーバーを公開する必要がある。

    HTTP.sys がインターネットと直接通信する

  • 内部の展開から Kestrel では使用できない機能が要求されている。 詳細については、Kestrel と HTTP.sys の比較に関するページを参照してください。

    HTTP.sys は内部ネットワークと直接通信します

HTTP.sys は、さまざまな種類の攻撃を防ぎ、フル機能の Web サーバーとして堅牢性、セキュリティ、スケーラビリティを提供する、成熟したテクノロジです。 IIS 自体が、HTTP.sys 上で HTTP リスナーとして実行されています。

HTTP/2 のサポート

次の基本要件が満たされている場合、ASP.NET Core アプリに対して HTTP/2 が有効になります。

Http/2 接続が確立されると、HttpRequest.Protocol が HTTP/2 を報告します。

HTTP/2 は既定で有効になっています。 Http/2 接続が確立されない場合、接続は http/1.1 にフォールバックします。 Windowsの今後のリリースでは、HTTP.sysで HTTP/2 を無効にする機能など、HTTP/2 構成フラグを使用できるようになります。

Kerberos を使用したカーネル モード認証

HTTP.sys では、Kerberos 認証プロトコルを使用したカーネル モード認証に処理が委任されます。 Kerberos および HTTP.sys ではユーザー モード認証がサポートされていません。 コンピューター アカウントを使用して、Active Directoryから取得した Kerberos トークン/チケットを復号化し、クライアントからサーバーに転送してユーザーを認証する必要があります。 アプリのユーザーではなく、ホストのサービス プリンシパル名 (SPN) を登録します。

HTTP.sys の使用方法

HTTP.sysを使用するように ASP.NET Core アプリを構成する

ホストを構築するときに UseHttpSys 拡張メソッドを呼び出し、必要な HttpSysOptions を指定します。 次の例では、既定値にオプションを設定しています。

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseHttpSys(options =>
            {
                options.AllowSynchronousIO = false;
                options.Authentication.Schemes = AuthenticationSchemes.None;
                options.Authentication.AllowAnonymous = true;
                options.MaxConnections = null;
                options.MaxRequestBodySize = 30000000;
                options.UrlPrefixes.Add("http://localhost:5005");
            });
            webBuilder.UseStartup<Startup>();
        });

HTTP.sys の追加の構成は、レジストリ設定を通じて処理されます。

HTTP.sys オプション

Property Description Default
AllowSynchronousIO HttpContext.Request.Body および HttpContext.Response.Body に対して、入力/出力の同期を許可するかどうかを制御します。 false
Authentication.AllowAnonymous 匿名要求を許可します。 true
Authentication.Schemes 許可される認証方式を指定します。 リスナーを破棄する前ならいつでも変更できます。 値は AuthenticationSchemes 列挙型 (Basic、Kerberos、Negotiate、None、および NTLM) によって指定します。 None
EnableResponseCaching 対象となるヘッダーを持つ応答に対して、カーネル モードのキャッシュを試行します。 Set-Cookie、Vary、または Pragma ヘッダーを含む応答は対象外です。 Cache-Control ヘッダーである public を含み、shared-max-age または max-age のいずれかの値か、Expires ヘッダーを含む必要があります。 true
Http503Verbosity 調整条件によって要求を拒否する場合の HTTP.sys の動作。 Http503VerbosityLevel
基本的な
MaxAccepts 同時受け入れの最大数です。 5 × 環境。
プロセッサ数
MaxConnections 受け入れるコンカレント接続の最大数です。 無限にするには、-1 を使用します。 コンピューター全体のレジストリ設定を使用するには、null を使用します。 null
(machine-wide
setting)
MaxRequestBodySize 「MaxRequestBodySize」セクションを参照してください。 30000000 バイト
(最大 28.6 MB)
RequestQueueLimit キューに置くことができる要求の最大数。 1000
RequestQueueMode これは、サーバーで要求キューの作成と構成を行う必要があるかどうか、または既存のキューにアタッチする必要があるかを示します。
既存のキューにアタッチする場合、既存の構成オプションのほとんどは適用されません。
RequestQueueMode.Create
RequestQueueName HTTP.sys 要求キューの名前。 null (匿名キュー)
ThrowWriteExceptions 応答本文の書き込みがクライアントの接続の切断によって失敗した場合、例外をスローするか、または正常に完了するかどうかを指定します。 false
(正常に完了)
Timeouts HTTP.sys TimeoutManager 構成を公開します。これはレジストリでも構成できます。 各設定に関する既定値などの詳細については、API のリンクを参照してください。
UrlPrefixes HTTP.sys に登録する UrlPrefixCollection を指定します。 最も便利なのは UrlPrefixCollection.Add です。これを使用して、コレクションにプレフィックスを追加できます。 これらは、リスナーを破棄する前ならいつでも変更できます。

MaxRequestBodySize

要求本文の最大許容サイズ (バイト単位) です。 null に設定する場合、要求本文の最大サイズは制限されません。 この制限は、アップグレード済みの接続 (常に無制限) には影響しません。

1 つの IActionResult の ASP.NET Core MVC アプリの制限をオーバーライドするには、アクション メソッドで RequestSizeLimitAttribute 属性を使用することをお勧めします。

[RequestSizeLimit(100000000)]
public IActionResult MyActionMethod()

アプリが要求の読み取りを開始した後に、アプリが要求に対する制限を構成しようとすると、例外がスローされます。 IsReadOnly プロパティを使用して、MaxRequestBodySize プロパティが読み取り専用状態にあるかどうか、つまり制限を構成するには遅すぎるかどうかを示すことができます。

要求ごとにアプリで MaxRequestBodySize をオーバーライドする必要がある場合は、IHttpMaxRequestBodySizeFeature を使います。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, 
    ILogger<Startup> logger, IServer server)
{
    app.Use(async (context, next) =>
    {
        context.Features.Get<IHttpMaxRequestBodySizeFeature>()
            .MaxRequestBodySize = 10 * 1024;

        var serverAddressesFeature = 
            app.ServerFeatures.Get<IServerAddressesFeature>();
        var addresses = string.Join(", ", serverAddressesFeature?.Addresses);

        logger.LogInformation("Addresses: {Addresses}", addresses);

        await next.Invoke();
    });

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
    }

    app.UseStaticFiles();
    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

Visual Studioを使用している場合は、アプリが IIS または IIS Express を実行するように構成されていないことを確認します。

Visual Studioでは、既定の起動プロファイルは IIS Express 用です。 プロジェクトをコンソール アプリとして実行するには、次のスクリーン ショットに示すように、選択したプロファイルを手動で変更します。

コンソール アプリ プロファイルを選択する

Windows Serverの構成

  1. アプリ用に開くポートを決定し、Windows Firewall または New-NetFirewallRule PowerShell コマンドレットを使用してファイアウォール ポートを開き、トラフィックが HTTP.sysに到達できるようにします。 次のコマンドとアプリの構成では、ポート 443 を使用します。

  2. Azure VM にデプロイするときは、Network セキュリティ グループでポートを開きます。 次のコマンドとアプリの構成では、ポート 443 を使用します。

  3. 必要に応じて、X.509 証明書を取得してインストールします。

    Windowsで、New-SelfSignedCertificate PowerShell コマンドレットを使用して自己署名証明書を作成します。 サポート対象外の例については、UpdateIISExpressSSLForChrome.ps1 を参照してください。

    自己署名証明書か CA 署名証明書のいずれかをサーバーの Local Machine>Personal ストアにインストールします。

  4. アプリが framework 依存のデプロイの場合は、.NET、.NET Framework、またはその両方をインストールします (アプリが .NET Framework を対象とする.NET アプリの場合)。

    • .NET: アプリで .NET が必要な場合は、.NET ダウンロード から .NET ランタイム インストーラーを取得して実行します。 サーバーに SDK 全体をインストールしないでください。
    • .NET Framework: アプリに .NET Framework が必要な場合は、.NET Framework のインストール ガイドを参照してください。 必要な .NET Framework をインストールします。 最新の .NET Framework のインストーラーは、.NET ダウンロード ページから入手できます。

    アプリが自己完結型の展開の場合、アプリの展開内にランタイムが含まれています。 サーバーにフレームワークをインストールする必要はありません。

  5. アプリに URL とポートを構成します。

    既定では、ASP.NET Coreは http://localhost:5000 にバインドされます。 URL プレフィックスとポートを構成するには、次のオプションがあります。

    次のコード例は、サーバーのローカル IP アドレス UrlPrefixes を使ってポート 443 上で 10.0.0.4 を使う方法を示しています。

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseHttpSys(options =>
                {
                    options.UrlPrefixes.Add("https://10.0.0.4:443");
                });
                webBuilder.UseStartup<Startup>();
            });
    

    UrlPrefixes の利点は、プレフィックスの形式が正しくなかった場合、すぐにエラー メッセージが生成されることです。

    UrlPrefixes の設定は UseUrls/urls/ASPNETCORE_URLS の設定をオーバーライドします。 したがって、UseUrls、urls、および ASPNETCORE_URLS 環境変数の利点は、Kestrel と HTTP.sys を簡単に切り替えられることです。

    HTTP.sys では、HTTP サーバー API の UrlPrefix 文字列形式が使用されます。

    Warning

    最上位のワイルドカードのバインド ( http://*:80/ と http://+:80 ) は使用しては いけません 。 最上位のワイルドカードのバインドを使用すると、アプリにセキュリティの脆弱性が生じます。 これは、強力と脆弱の両方のワイルドカードに適用されます。 ワイルドカードではなく、明示的なホスト名か IP アドレスを使用してください。 親ドメイン全体を制御する場合、サブドメインのワイルドカードのバインド (たとえば、*.mysub.com) がセキュリティ リスクになることはありません (脆弱である *.com とは対照的)。 詳細については、RFC 9110: セクション 7.2: Host and :authorityを参照してください。

  6. サーバーで URL プレフィックスを事前登録します。

    HTTP.sys を構成するための組み込みツールは、netsh.exe です。 netsh.exe は、URL プレフィックスを予約し、X.509 証明書を割り当てるために使用されます。 ツールを使用するには管理者特権が必要です。

    netsh.exe ツールを使用して、アプリ用に URL を登録します。

    netsh http add urlacl url=<URL> user=<USER>
    
    • <URL>: 完全修飾 Uniform Resource Locator (URL)。 ワイルドカードのバインドは使用しないでください。 有効なホスト名かローカル IP アドレスを使用してください。 URL には末尾のスラッシュを含める必要があります。
    • <USER>: ユーザーまたはユーザー グループ名を指定します。

    次の例では、サーバーのローカル IP アドレスは 10.0.0.4 です。

    netsh http add urlacl url=https://10.0.0.4:443/ user=Users
    

    URL が登録されると、ツールから URL reservation successfully added という応答があります。

    登録済みの URL を削除するには、delete urlacl コマンドを使用します。

    netsh http delete urlacl url=<URL>
    
  7. サーバーで X.509 証明書を登録します。

    netsh.exe ツールを使用して、アプリ用の証明書を登録します。

    netsh http add sslcert ipport=<IP>:<PORT> certhash=<THUMBPRINT> appid="{<GUID>}"
    
    • <IP>: バインディングのローカル IP アドレスを指定します。 ワイルドカードのバインドは使用しないでください。 有効な IP アドレスを使用してください。
    • <PORT>: バインディングのポートを指定します。
    • <THUMBPRINT>: X.509 証明書のサムプリント。
    • <GUID>: 参考情報としてアプリを表す開発者が生成した GUID。

    参照用に、この GUID をパッケージ タグとしてアプリに格納します。

    • Visual Studio で:
      • アプリのプロジェクト プロパティを開くには、ソリューション エクスプローラー でアプリを右クリックし、Properties を選択します。
      • [パッケージ] タブを選択します。
      • 作成した GUID を [タグ] フィールドに入力します。
    • Visual Studioを使用しない場合:
      • アプリのプロジェクト ファイルを開きます。

      • 作成した GUID を指定した <PackageTags> プロパティを、新規または既存の <PropertyGroup> に追加します。

        <PropertyGroup>
          <PackageTags>00001111-aaaa-2222-bbbb-3333cccc4444</PackageTags>
        </PropertyGroup>
        

    次に例を示します。

    • サーバーのローカル IP アドレスは 10.0.0.4 です。
    • オンラインのランダム GUID ジェネレーターによって、appid の値が提供されます。
    netsh http add sslcert 
        ipport=10.0.0.4:443 
        certhash=b66ee04419d4ee37464ab8785ff02449980eae10 
        appid="{00001111-aaaa-2222-bbbb-3333cccc4444}"
    

    証明書が登録されると、ツールから SSL Certificate successfully added という応答があります。

    証明書の登録を削除するには、delete sslcert コマンドを使用します。

    netsh http delete sslcert ipport=<IP>:<PORT>
    

    以下は、netsh.exe のリファレンス ドキュメントです。

  8. アプリを実行します。

    1024 より大きいポート番号で (HTTPS ではなく) HTTP を使用して localhost にバインドする場合、アプリの実行に管理者権限は必要ありません。 その他の構成の場合 (たとえば、ローカル IP アドレスを使用する場合やポート 443 にバインドする場合)、管理者権限でアプリを実行します。

    サーバーのパブリック IP アドレスでアプリが応答します。 この例では、サーバーは自身のパブリック IP アドレス 104.214.79.47 でインターネットからアクセスされます。

    この例では開発証明書が使用されています。 証明書が信頼できないというブラウザーの警告がバイパスされた後に、ページが安全に読み込まれます。

    読み込まれたアプリの [インデックス] ページを示すブラウザー ウィンドウ

プロキシ サーバーとロード バランサーのシナリオ

インターネットや企業ネットワークからの要求とやりとりする HTTP.sys でホストされるアプリの場合、プロキシ サーバーやロード バランサーの背後でホストするとき、追加の構成が必要になることがあります。 詳細については、「プロキシ サーバーとロード バランサーを操作するための構成 ASP.NET Coreを参照してください。

gRPC をサポートする高度な HTTP/2 機能

HTTP.sys 内の追加の HTTP/2 機能によって、gRPC がサポートされています。これには、応答トレーラーやリセット フレームの送信に関するサポートが含まれます。

HTTP.sys で gRPC を実行するための要件:

  • Windows 10、OS ビルド 19041.508 以降
  • TLS 1.2 以降の接続

Trailers

HTTP トレーラーは HTTP ヘッダーに似ていますが、応答本文の送信後に送信される点が異なります。 IIS と HTTP.sys の場合は、HTTP/2 応答トレーラーのみがサポートされています。

if (httpContext.Response.SupportsTrailers())
{
    httpContext.Response.DeclareTrailer("trailername");	

    // Write body
    httpContext.Response.WriteAsync("Hello world");

    httpContext.Response.AppendTrailer("trailername", "TrailerValue");
}

上記のコード例では次のようになっています。

  • SupportsTrailers によって、応答におけるトレーラーがサポートされることが確実になります。
  • DeclareTrailer によって、指定したトレーラー名が Trailer 応答ヘッダーに追加されます。 応答のトレーラーを宣言することは省略可能ですが、推奨されています。 DeclareTrailer を呼び出す場合、それは、応答ヘッダーを送信する前に行う必要があります。
  • AppendTrailer によって、トレーラーが追加されます。

Reset

リセットを使用すると、指定されたエラー コードを使用してサーバーに HTTP/2 要求をリセットさせることができます。 リセット要求は中止されたと見なされます。

var resetFeature = httpContext.Features.Get<IHttpResetFeature>();
resetFeature.Reset(errorCode: 2);

上記のコード例の Reset により、INTERNAL_ERROR エラー コードが指定されています。 HTTP/2 エラー コードの詳細については、HTTP/2 仕様の「エラーコード」セクションを参照してください。

HTTP.sys は、Windowsでのみ実行される ASP.NET Core用の Web サーバーです。 HTTP.sys は Kestrel サーバーの代替製品であり、Kestrel では提供されていない機能がいくつか用意されています。

Important

HTTP.sys は、ASP.NET Core モジュールと互換性がありません。IIS または IIS Express では使用できません。

HTTP.sys は、次の機能をサポートします。

  • Windows認証
  • ポート共有
  • SNI を使用する HTTPS
  • TLS 経由の HTTP/2 (Windows 10 以降)
  • TLS 経由の HTTP/3 (Windows 11 以降)
  • 直接ファイル伝送
  • 応答のキャッシュ
  • WebSocket (Windows 8 以降)
  • カスタマイズ可能なセキュリティ記述子

サポートされているWindowsバージョン:

  • Windows 7以降
  • Windows Server 2008 R2 以降

サンプル コードを表示またはダウンロードします (ダウンロード方法)。

HTTP.sys を使用するタイミング

HTTP.sys は、次のような展開に適しています。

  • IIS を使用せず、インターネットに直接サーバーを公開する必要がある。

    HTTP.sys がインターネットと直接通信する

  • 内部の展開から Kestrel では使用できない機能が要求されている。 詳細については、Kestrel と HTTP.sys の比較に関するページを参照してください。

    HTTP.sys は内部ネットワークと直接通信します

HTTP.sys は、さまざまな種類の攻撃を防ぎ、フル機能の Web サーバーとして堅牢性、セキュリティ、スケーラビリティを提供する、成熟したテクノロジです。 IIS 自体が、HTTP.sys 上で HTTP リスナーとして実行されています。

HTTP/2 のサポート

次の基本要件が満たされている場合、ASP.NET Core アプリに対して HTTP/2 が有効になります。

Http/2 接続が確立されると、HttpRequest.Protocol が HTTP/2 を報告します。

HTTP/2 は既定で有効になっています。 Http/2 接続が確立されない場合、接続は http/1.1 にフォールバックします。 Windowsの今後のリリースでは、HTTP.sysで HTTP/2 を無効にする機能など、HTTP/2 構成フラグを使用できるようになります。

HTTP/3 のサポート

次の基本要件が満たされている場合、ASP.NET Core アプリに対して HTTP/3 が有効になります。

上記の Windows 11 ビルド バージョンでは、Windows Insider ビルドの使用が必要になる場合があります。

HTTP/3 は、alt-svc ヘッダーを介して HTTP/1.1 または HTTP/2 からのアップグレードとして検出されます。 これは、最初の要求では HTTP/3 に切り替える前に、通常 HTTP/1.1 または HTTP/2 が使用されることを意味します。 Http.Sys によって alt-svc ヘッダーは自動的に追加されないため、アプリケーションで追加する必要があります。 次のコードは、alt-svc 応答ヘッダーを追加するミドルウェアの例を示しています。

app.Use((context, next) =>
{
    context.Response.Headers.AltSvc = "h3=\":443\"";
    return next(context);
});

上記のコードを要求パイプラインの早い段階に配置します。

Http.Sys では、HTTP/3 が使用可能であることをクライアントに通知するために、応答ヘッダーではなく AltSvc HTTP/2 プロトコル メッセージの送信もサポートされています。 EnableAltSvc レジストリ キーに関するページを参照してください。 これには、IP アドレスではなくホスト名を使用する netsh sslcert バインドが必要です。

Kerberos を使用したカーネル モード認証

HTTP.sys では、Kerberos 認証プロトコルを使用したカーネル モード認証に処理が委任されます。 Kerberos および HTTP.sys ではユーザー モード認証がサポートされていません。 コンピューター アカウントを使用して、Active Directoryから取得した Kerberos トークン/チケットを復号化し、クライアントからサーバーに転送してユーザーを認証する必要があります。 アプリのユーザーではなく、ホストのサービス プリンシパル名 (SPN) を登録します。

チャネル バインド トークン (CBT) のセキュリティ強化を有効にする

チャネル バインド トークン (CBT) は、基になる TLS チャネルにWindows 認証を結び付け、NTLM リレーと中間者攻撃を軽減するのに役立ちます。 HTTP.sysでWindows 認証を使用する HTTPS エンドポイントの場合は、Microsoft.AspNetCore.Server.HttpSys.EnableCBTHardening AppContext スイッチを true に設定することで、CBT のセキュリティ強化を選択できます。

プロジェクトの runtimeconfig.template.json ファイルでスイッチを有効にします。

{
  "configProperties": {
    "Microsoft.AspNetCore.Server.HttpSys.EnableCBTHardening": true
  }
}

または、 Program.csでホストをビルドする前に、プログラムでスイッチを設定します。

AppContext.SetSwitch("Microsoft.AspNetCore.Server.HttpSys.EnableCBTHardening", true);

Warning

CBT のセキュリティ強化は既定でオフになっています。 これを有効にすると、チャネル バインドをサポートしていないクライアントまたはプロキシのWindows 認証が失敗する可能性があります。 運用環境で有効にする前に、環境で十分にテストします。

カーネル モード応答バッファリングのサポート

一部のシナリオでは、待機時間の長い少量の書き込みが大量に発生すると、HTTP.sys のパフォーマンスに大きな影響を与える場合があります。 この影響は、Pipe に HTTP.sys バッファーが実装されていないことが原因です。 これらのシナリオでパフォーマンスを向上させるため、HTTP.sys では応答バッファリングがサポートされています。 HttpSysOptions.EnableKernelResponseBuffering を true に設定して、バッファリングを有効にします。 応答バッファリングは、同期 I/O を実行するアプリで、または非同期 I/O で未処理の書き込みを一度に 1 つしか実行しないアプリで有効にする必要があります。 これらのシナリオでは、応答バッファリングにより、待機時間の長い接続に対してスループットが大幅に向上する場合があります。

非同期 I/O を使用し、未処理の書き込みを一度に複数実行する場合があるアプリでは、このフラグを使用しないでください。 このフラグを有効にすると、HTTP.Sys により CPU とメモリの使用率が高くなる場合があります。

HTTP.sys の使用方法

HTTP.sysを使用するように ASP.NET Core アプリを構成する

ホストを構築するときに UseHttpSys 拡張メソッドを呼び出し、必要な HttpSysOptions を指定します。 次の例では、既定値にオプションを設定しています。

using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.HttpSys;

var builder = WebApplication.CreateBuilder(args);

builder.WebHost.UseHttpSys(options =>
{
    options.AllowSynchronousIO = false;
    options.Authentication.Schemes = AuthenticationSchemes.None;
    options.Authentication.AllowAnonymous = true;
    options.MaxConnections = null;
    options.MaxRequestBodySize = 30_000_000;
    options.UrlPrefixes.Add("http://localhost:5005");
});

builder.Services.AddRazorPages();

var app = builder.Build();

HTTP.sys の追加の構成は、レジストリ設定を通じて処理されます。

HTTP.sys オプションの詳細については、「HttpSysOptions」を参照してください。

MaxRequestBodySize

要求本文の最大許容サイズ (バイト単位) です。 null に設定する場合、要求本文の最大サイズは制限されません。 この制限は、アップグレード済みの接続 (常に無制限) には影響しません。

1 つの IActionResult の ASP.NET Core MVC アプリの制限をオーバーライドするには、アクション メソッドで RequestSizeLimitAttribute 属性を使用することをお勧めします。

[RequestSizeLimit(100000000)]
public IActionResult MyActionMethod()

アプリが要求の読み取りを開始した後に、アプリが要求に対する制限を構成しようとすると、例外がスローされます。 IsReadOnly プロパティを使用して、MaxRequestBodySize プロパティが読み取り専用状態にあるかどうか、つまり制限を構成するには遅すぎるかどうかを示すことができます。

要求ごとにアプリで MaxRequestBodySize をオーバーライドする必要がある場合は、IHttpMaxRequestBodySizeFeature を使います。

app.Use((context, next) =>
{
    context.Features.GetRequiredFeature<IHttpMaxRequestBodySizeFeature>()
                                             .MaxRequestBodySize = 10 * 1024;

    var server = context.RequestServices
        .GetRequiredService<IServer>();
    var serverAddressesFeature = server.Features
                                 .GetRequiredFeature<IServerAddressesFeature>();

    var addresses = string.Join(", ", serverAddressesFeature.Addresses);

    var loggerFactory = context.RequestServices
        .GetRequiredService<ILoggerFactory>();
    var logger = loggerFactory.CreateLogger("Sample");

    logger.LogInformation("Addresses: {addresses}", addresses);

    return next(context);
});

Visual Studioを使用している場合は、アプリが IIS または IIS Express を実行するように構成されていないことを確認します。

Visual Studioでは、既定の起動プロファイルは IIS Express 用です。 プロジェクトをコンソール アプリとして実行するには、次のスクリーンショットに示すように、選択したプロファイルを手動で変更します。

コンソール アプリ プロファイルを選択する

Windows Serverの構成

  1. アプリ用に開くポートを決定し、Windows Firewall または New-NetFirewallRule PowerShell コマンドレットを使用してファイアウォール ポートを開き、トラフィックが HTTP.sysに到達できるようにします。 次のコマンドとアプリの構成では、ポート 443 を使用します。

  2. Azure VM にデプロイするときは、Network セキュリティ グループでポートを開きます。 次のコマンドとアプリの構成では、ポート 443 を使用します。

  3. 必要に応じて、X.509 証明書を取得してインストールします。

    Windowsで、New-SelfSignedCertificate PowerShell コマンドレットを使用して自己署名証明書を作成します。 サポート対象外の例については、UpdateIISExpressSSLForChrome.ps1 を参照してください。

    自己署名証明書か CA 署名証明書のいずれかをサーバーの Local Machine>Personal ストアにインストールします。

  4. アプリが framework 依存のデプロイの場合は、.NET、.NET Framework、またはその両方をインストールします (アプリが .NET Framework を対象とする.NET アプリの場合)。

    • .NET: アプリで .NET が必要な場合は、.NET ダウンロード から .NET ランタイム インストーラーを取得して実行します。 サーバーに SDK 全体をインストールしないでください。
    • .NET Framework: アプリに .NET Framework が必要な場合は、.NET Framework のインストール ガイドを参照してください。 必要な .NET Framework をインストールします。 最新の .NET Framework のインストーラーは、.NET ダウンロード ページから入手できます。

    アプリが自己完結型の展開の場合、アプリの展開内にランタイムが含まれています。 サーバーにフレームワークをインストールする必要はありません。

  5. アプリに URL とポートを構成します。

    既定では、ASP.NET Coreは http://localhost:5000 にバインドされます。 URL プレフィックスとポートを構成するには、次のオプションがあります。

    次のコード例は、サーバーのローカル IP アドレス UrlPrefixes を使ってポート 443 上で 10.0.0.4 を使う方法を示しています。

    var builder = WebApplication.CreateBuilder(args);
    
    builder.WebHost.UseHttpSys(options =>
    {
        options.UrlPrefixes.Add("https://10.0.0.4:443");
    });
    
    builder.Services.AddRazorPages();
    
    var app = builder.Build();
    

    UrlPrefixes の利点は、プレフィックスの形式が正しくなかった場合、すぐにエラー メッセージが生成されることです。

    UrlPrefixes の設定は UseUrls/urls/ASPNETCORE_URLS の設定をオーバーライドします。 したがって、UseUrls、urls、および ASPNETCORE_URLS 環境変数の利点は、Kestrel と HTTP.sys を簡単に切り替えられることです。

    HTTP.sys は、URL プレフィックスで次の 2 種類のワイルドカードを認識します:

    • * は 弱いバインディングであり、 フォールバック バインディングとも呼ばれます。 URL プレフィックスが http://*:5000 で、他の何かがポート 5000 にバインドされている場合、このバインディングは使用されません。
    • + は 強いバインドです。 URL プレフィックスが http://+:5000 の場合、このバインディングは他のポート 5000 バインドの前に使用されます。

    詳細については、「UrlPrefix 文字列」を参照してください。

    Warning

    最上位のワイルドカードのバインド ( http://*:80/ と http://+:80 ) は使用しては いけません 。 最上位のワイルドカードのバインドを使用すると、アプリにセキュリティの脆弱性が生じます。 これは、強力と脆弱の両方のワイルドカードに適用されます。 ワイルドカードではなく、明示的なホスト名か IP アドレスを使用してください。 親ドメイン全体を制御する場合、サブドメインのワイルドカードのバインド (たとえば、*.mysub.com) がセキュリティ リスクになることはありません (脆弱である *.com とは対照的)。 詳細については、RFC 9110: セクション 7.2: Host and :authorityを参照してください。

    アプリとコンテナーのほとんどの構成では、ホストやパスなどの他の制約を指定せずに、ポート 80 のようにリッスンするポートのみを定義します。 HTTP_PORTS HTTPS_PORTSは、Kestrelおよび HTTP.sys サーバーのリッスン ポートを指定する構成キーです。 キーは、 DOTNET_ または ASPNETCORE_ プレフィックスで定義された環境変数として指定することも、 appsettings.json ファイルなどの他の構成入力を使用して直接設定することもできます。 各構成は、次の例に示すように、ポート値のセミコロン区切りのリストです。

    ASPNETCORE_HTTP_PORTS=80;8080
    ASPNETCORE_HTTPS_PORTS=443;8081
    

    この例の構成は、スキーム (HTTP または HTTPS) と任意のホストまたは IP を定義する次の仕様の短縮形です。

    ASPNETCORE_URLS=http://*:80/;http://*:8080/;https://*:443/;https://*:8081/
    

    HTTP_PORTSおよびHTTPS_PORTS構成キーの優先順位は低くなります。 他の URL または値がコードで直接設定されている場合は、構成キーをオーバーライドできます。 HTTPS のサーバー固有のメカニズムを使用して、証明書を個別に構成します。

    Note

    Kestrel/HTTP.sys エンドポイント構成のポートを設定する HTTPS_PORTS 構成キーおよび ASPNETCORE_HTTPS_PORTS 環境変数と、HTTPS リダイレクト ミドルウェア のポートを設定する HTTPS_PORT 構成キーおよび ASPNETCORE_HTTPS_PORT 環境変数を混同しないでください。

    これらの構成キーは、最上位のワイルドカード バインドと同等です。 これらは開発およびコンテナーのシナリオには便利ですが、他のサービスもホストする可能性があるコンピューター上で実行する場合は、ワイルドカードを避けてください。

  6. サーバーで URL プレフィックスを事前登録します。

    HTTP.sys を構成するための組み込みツールは、netsh.exe です。 netsh.exe は、URL プレフィックスを予約し、X.509 証明書を割り当てるために使用されます。 ツールを使用するには管理者特権が必要です。

    netsh.exe ツールを使用して、アプリ用に URL を登録します。

    netsh http add urlacl url=<URL> user=<USER>
    
    • <URL>: 完全修飾 Uniform Resource Locator (URL)。 ワイルドカードのバインドは使用しないでください。 有効なホスト名かローカル IP アドレスを使用してください。 URL には末尾のスラッシュを含める必要があります。
    • <USER>: ユーザーまたはユーザー グループ名を指定します。

    次の例では、サーバーのローカル IP アドレスは 10.0.0.4 です。

    netsh http add urlacl url=https://10.0.0.4:443/ user=Users
    

    URL が登録されると、ツールから URL reservation successfully added という応答があります。

    登録済みの URL を削除するには、delete urlacl コマンドを使用します。

    netsh http delete urlacl url=<URL>
    
  7. サーバーで X.509 証明書を登録します。

    netsh.exe ツールを使用して、アプリ用の証明書を登録します。

    netsh http add sslcert ipport=<IP>:<PORT> certhash=<THUMBPRINT> appid="{<GUID>}"
    
    • <IP>: バインディングのローカル IP アドレスを指定します。 ワイルドカードのバインドは使用しないでください。 有効な IP アドレスを使用してください。
    • <PORT>: バインディングのポートを指定します。
    • <THUMBPRINT>: X.509 証明書のサムプリント。
    • <GUID>: 参考情報としてアプリを表す開発者が生成した GUID。

    参照用に、この GUID をパッケージ タグとしてアプリに格納します。

    • Visual Studio で:
      • アプリのプロジェクト プロパティを開くには、ソリューション エクスプローラー でアプリを右クリックし、Properties を選択します。
      • [パッケージ] タブを選択します。
      • 作成した GUID を [タグ] フィールドに入力します。
    • Visual Studioを使用しない場合:
      • アプリのプロジェクト ファイルを開きます。

      • 作成した GUID を指定した <PackageTags> プロパティを、新規または既存の <PropertyGroup> に追加します。

        <PropertyGroup>
          <PackageTags>00001111-aaaa-2222-bbbb-3333cccc4444</PackageTags>
        </PropertyGroup>
        

    次に例を示します。

    • サーバーのローカル IP アドレスは 10.0.0.4 です。
    • オンラインのランダム GUID ジェネレーターによって、appid の値が提供されます。
    netsh http add sslcert 
        ipport=10.0.0.4:443 
        certhash=b66ee04419d4ee37464ab8785ff02449980eae10 
        appid="{00001111-aaaa-2222-bbbb-3333cccc4444}"
    

    証明書が登録されると、ツールから SSL Certificate successfully added という応答があります。

    証明書の登録を削除するには、delete sslcert コマンドを使用します。

    netsh http delete sslcert ipport=<IP>:<PORT>
    

    以下は、netsh.exe のリファレンス ドキュメントです。

  8. アプリを実行します。

    1024 より大きいポート番号で (HTTPS ではなく) HTTP を使用して localhost にバインドする場合、アプリの実行に管理者権限は必要ありません。 その他の構成の場合 (たとえば、ローカル IP アドレスを使用する場合やポート 443 にバインドする場合)、管理者権限でアプリを実行します。

    サーバーのパブリック IP アドレスでアプリが応答します。 この例では、サーバーは自身のパブリック IP アドレス 104.214.79.47 でインターネットからアクセスされます。

    この例では開発証明書が使用されています。 証明書が信頼できないというブラウザーの警告がバイパスされた後に、ページが安全に読み込まれます。

    読み込まれたアプリの [インデックス] ページを示すブラウザー ウィンドウ

プロキシ サーバーとロード バランサーのシナリオ

インターネットや企業ネットワークからの要求とやりとりする HTTP.sys でホストされるアプリの場合、プロキシ サーバーやロード バランサーの背後でホストするとき、追加の構成が必要になることがあります。 詳細については、「プロキシ サーバーとロード バランサーを操作するための構成 ASP.NET Coreを参照してください。

IHttpSysRequestTimingFeature を使用して詳細なタイミング情報を取得する

IHttpSysRequestTimingFeature は、リクエストの詳細なタイミング情報を提供します:

  • タイムスタンプは、QueryPerformanceCounter を使用して取得されます。
  • タイムスタンプの頻度は、QueryPerformanceFrequency を使用して取得できます。
  • タイミングのインデックスを HttpSysRequestTimingType にキャストして、タイミングが何を表しているのかを把握できます。
  • 現在の要求でタイミングを利用できない場合、値は 0 になることがあります。
  • Windows 10 バージョン 2004、Windows Server 2022 以降が必要です。
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.HttpSys;

var builder = WebApplication.CreateBuilder(args);

builder.WebHost.UseHttpSys();

var app = builder.Build();

app.Use((context, next) =>
{
    var feature = context.Features.GetRequiredFeature<IHttpSysRequestTimingFeature>();
    
    var loggerFactory = context.RequestServices.GetRequiredService<ILoggerFactory>();
    var logger = loggerFactory.CreateLogger("Sample");

    var timestamps = feature.Timestamps;

    for (var i = 0; i < timestamps.Length; i++)
    {
        var timestamp = timestamps[i];
        var timingType = (HttpSysRequestTimingType)i;

        logger.LogInformation("Timestamp {timingType}: {timestamp}",
                                          timingType, timestamp);
    }

    return next(context);
});

app.MapGet("/", () => Results.Ok());

app.Run();

IHttpSysRequestTimingFeature.TryGetTimestamp は、指定されたタイミングの種類のタイムスタンプを取得します。

using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.HttpSys;
var builder = WebApplication.CreateBuilder(args);

builder.WebHost.UseHttpSys();

var app = builder.Build();

app.Use((context, next) =>
{
    var feature = context.Features.GetRequiredFeature<IHttpSysRequestTimingFeature>();

    var loggerFactory = context.RequestServices.GetRequiredService<ILoggerFactory>();
    var logger = loggerFactory.CreateLogger("Sample");

    var timingType = HttpSysRequestTimingType.RequestRoutingEnd;

    if (feature.TryGetTimestamp(timingType, out var timestamp))
    {
        logger.LogInformation("Timestamp {timingType}: {timestamp}",
                                          timingType, timestamp);
    }
    else
    {
        logger.LogInformation("Timestamp {timingType}: not available for the "
                                           + "current request",    timingType);
    }

    return next(context);
});

app.MapGet("/", () => Results.Ok());

app.Run();

[IHttpSysRequestTimingFeature.TryGetElapsedTime](/dotnet/api/microsoft.aspnetcore.server.httpsys.ihttpsysrequesttimingfeature.trygetelapsedtime は、指定された 2 つのタイミング間の経過時間を生成します。

using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.HttpSys;

var builder = WebApplication.CreateBuilder(args);

builder.WebHost.UseHttpSys();

var app = builder.Build();

app.Use((context, next) =>
{
    var feature = context.Features.GetRequiredFeature<IHttpSysRequestTimingFeature>();

    var loggerFactory = context.RequestServices.GetRequiredService<ILoggerFactory>();
    var logger = loggerFactory.CreateLogger("Sample");

    var startingTimingType = HttpSysRequestTimingType.RequestRoutingStart;
    var endingTimingType = HttpSysRequestTimingType.RequestRoutingEnd;

    if (feature.TryGetElapsedTime(startingTimingType, endingTimingType, out var elapsed))
    {
        logger.LogInformation(
            "Elapsed time {startingTimingType} to {endingTimingType}: {elapsed}",
            startingTimingType,
            endingTimingType,
            elapsed);
    }
    else
    {
        logger.LogInformation(
            "Elapsed time {startingTimingType} to {endingTimingType}:"
            + " not available for the current request.",
            startingTimingType,
            endingTimingType);
    }

    return next(context);
});

app.MapGet("/", () => Results.Ok());

app.Run();

gRPC をサポートする高度な HTTP/2 機能

HTTP.sys 内の追加の HTTP/2 機能によって、gRPC がサポートされています。これには、応答トレーラーやリセット フレームの送信に関するサポートが含まれます。

HTTP.sys で gRPC を実行するための要件:

  • ビルド 22000 以降Windows 11、ビルド 20348 以降Windows Server 2022。
  • TLS 1.2 またはそれ以降の接続。

Trailers

HTTP トレーラーは HTTP ヘッダーに似ていますが、応答本文の送信後に送信される点が異なります。 IIS と HTTP.sys の場合は、HTTP/2 応答トレーラーのみがサポートされています。

if (httpContext.Response.SupportsTrailers())
{
    httpContext.Response.DeclareTrailer("trailername");	

    // Write body
    httpContext.Response.WriteAsync("Hello world");

    httpContext.Response.AppendTrailer("trailername", "TrailerValue");
}

上記のコード例では次のようになっています。

  • SupportsTrailers によって、応答におけるトレーラーがサポートされることが確実になります。
  • DeclareTrailer によって、指定したトレーラー名が Trailer 応答ヘッダーに追加されます。 応答のトレーラーを宣言することは省略可能ですが、推奨されています。 DeclareTrailer を呼び出す場合、それは、応答ヘッダーを送信する前に行う必要があります。
  • AppendTrailer によって、トレーラーが追加されます。

Reset

リセットを使用すると、指定されたエラー コードを使用してサーバーに HTTP/2 要求をリセットさせることができます。 リセット要求は中止されたと見なされます。

var resetFeature = httpContext.Features.Get<IHttpResetFeature>();
resetFeature.Reset(errorCode: 2);

上記のコード例の Reset により、INTERNAL_ERROR エラー コードが指定されています。 HTTP/2 エラー コードの詳細については、HTTP/2 仕様の「エラーコード」セクションを参照してください。

Tracing

HTTP.sys からトレースを取得する方法については、「HTTP.sys 管理のシナリオ」を参照してください。

Note

通常、.NET 参照ソースへのドキュメント リンクを使用すると、リポジトリの既定のブランチが読み込まれます。このブランチは、.NET の次回リリースに向けて行われている現在の開発を表します。 特定のリリースのタグを選択するには、[Switch branches or tags](ブランチまたはタグの切り替え) ドロップダウン リストを使います。