为 ASP.NET Core Kestrel Web 服务器配置终结点
注意
此版本不是本文的最新版本。 有关当前版本,请参阅本文的 .NET 9 版本。
警告
此版本的 ASP.NET Core 不再受支持。 有关详细信息,请参阅 .NET 和 .NET Core 支持策略。 有关当前版本,请参阅本文的 .NET 9 版本。
注意
此版本不是本文的最新版本。 有关当前版本,请参阅本文的 .NET 9 版本。
警告
此版本的 ASP.NET Core 不再受支持。 有关详细信息,请参阅 .NET 和 .NET Core 支持策略。 有关当前版本,请参阅本文的 .NET 9 版本。
Kestrel 终结点提供用于侦听传入请求并将其路由到相应中间件的基础结构。 地址和协议的组合定义了终结点。
- 地址指定服务器侦听传入请求的网络接口,例如 TCP 端口。
- 协议指定客户端与服务器之间的通信,例如 HTTP/1.1、HTTP/2 或 HTTP/3。
- 可以使用
https
URL 方案或UseHttps
方法来保护终结点。
可以使用 URL、appsettings.json
中的 JSON 和代码配置终结点。 本文讨论如何使用每个选项来配置终结点:
默认终结点
新 ASP.NET Core 项目配置为绑定到 5000-5300 之间的随机 HTTP 端口和 7000-7300 之间的随机 HTTPS 端口。 所选端口存储在生成的 Properties/launchSettings.json
文件中,开发人员可以对其进行修改。 launchSetting.json
文件仅用于本地开发。
如果没有终结点配置,则 Kestrel 绑定到 http://localhost:5000
。
配置终结点
Kestrel 终结点侦听传入连接。 创建终结点时,必须使用它将侦听的地址对其进行配置。 通常,这是一个 TCP 地址和端口号。
有多种选项可用于配置终结点:
使用 URL 配置终结点
以下部分介绍如何使用以下方式配置终结点:
ASPNETCORE_URLS
环境变量。--urls
命令行参数。urls
主机配置键。- UseUrls 扩展方法。
- WebApplication.Urls 属性。
URL 格式
URL 指示服务器应侦听的端口和协议的 IP 或主机地址。 如果端口是协议的默认值(通常为 80 和 443),则可以省略该端口。 URL 可以采用以下任意格式。
包含端口号的 IPv4 地址
http://65.55.39.10:80/
0.0.0.0
是一种绑定到所有 IPv4 地址的特殊情况。包含端口号的 IPv6 地址
http://[0:0:0:0:0:ffff:4137:270a]:80/
[::]
是 IPv40.0.0.0
的 IPv6 等效项。具有端口号的通配符主机
http://contoso.com:80/ http://*:80/
任何未识别为有效 IP 地址或
localhost
的内容被视为绑定到所有 IPv4 和 IPv6 地址的通配符。 有些人喜欢使用*
或+
以便更加明确。 若要将不同主机名绑定到相同端口上的不同 ASP.NET Core 应用,请使用 HTTP.sys 或反向代理服务器。反向代理服务器示例包括 IIS、YARP、Nginx 和 Apache。
包含端口号的主机名称
localhost
或包含端口号的环回 IPhttp://localhost:5000/ http://127.0.0.1:5000/ http://[::1]:5000/
指定
localhost
后,Kestrel 将尝试绑定到 IPv4 和 IPv6 环回接口。 如果其他服务正在任一环回接口上使用请求的端口,则 Kestrel 将无法启动。 如果任一环回接口出于任何其他原因(通常是因为 IPv6 不受支持)而不可用,则 Kestrel 将记录一个警告。
可以使用分号 (;
) 分隔符指定多个 URL 前缀:
http://*:5000;http://localhost:5001;https://hostname:5002
有关详细信息,请参阅重写配置。
HTTPS URL 前缀
仅当 HTTPS 终结点配置中提供默认证书时,HTTPS URL 前缀才可用于定义终结点。 例如,使用 KestrelServerOptions 配置或配置文件,如本文稍后所示。
有关详细信息,请参阅配置 HTTPS。
仅指定端口
应用和容器通常只能侦听一个端口(比如端口 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 配置密钥的优先级较低,会被 URLS 或代码中直接提供的值覆盖。 证书仍需通过特定于服务器的 HTTPS 机制单独配置。
在 appsettings.json 中配置终结点
Kestrel 可以从 IConfiguration 实例加载终结点。 默认情况下,Kestrel 配置从 Kestrel
部分加载,终结点在 Kestrel:Endpoints
中配置:
{
"Kestrel": {
"Endpoints": {
"MyHttpEndpoint": {
"Url": "http://localhost:8080"
}
}
}
}
上面的示例:
- 使用
appsettings.json
作为配置源。 但是,可以使用任何IConfiguration
源。 - 在端口 8080 上添加名为
MyHttpEndpoint
的终结点。
有关使用 JSON 配置终结点的详细信息,请参阅本文后面讨论的在 appsettings.json 中配置 HTTPS 和配置 HTTP 协议的部分。
从配置重新加载终结点
默认情况下,“在配置源更改时重新加载终结点配置”处于启用状态。 可以使用 KestrelServerOptions.Configure(IConfiguration, Boolean) 来禁用它。
如果发出更改信号,请执行以下步骤:
- 新配置与旧配置相比,不会修改任何没有配置更改的终结点。
- 已删除或已修改的终结点将在 5 秒内完成处理请求并关闭。
- 启动新的或已修改的终结点。
重启终结点时,连接到已修改的终结点的客户端可能会断开连接或被拒绝。
ConfigurationLoader
KestrelServerOptions.Configure 返回 KestrelConfigurationLoader。 加载程序的 Endpoint(String, Action<EndpointConfiguration>) 方法,可用于补充配置的终结点的设置:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel((context, serverOptions) =>
{
var kestrelSection = context.Configuration.GetSection("Kestrel");
serverOptions.Configure(kestrelSection)
.Endpoint("HTTPS", listenOptions =>
{
// ...
});
});
可以直接访问 KestrelServerOptions.ConfigurationLoader
以继续迭代现有加载程序,例如由 WebApplicationBuilder.WebHost 提供的加载程序。
- 每个终结点的配置节都可用于 Endpoint 方法中的选项,以便读取自定义设置。
- 可以多次调用 KestrelServerOptions.Configure(IConfiguration),但除非在之前的实例上显式调用了
Load
,否则只使用最新配置。 默认主机不会调用Load
,因此可能会替换它的默认配置部分。 KestrelConfigurationLoader
从KestrelServerOptions
将 API 的Listen
簇反射为Endpoint
重载,因此可在同样的位置配置代码和配置终结点。 这些重载不使用名称,且只使用配置中的默认设置。
在代码中配置终结点
KestrelServerOptions 提供用于在代码中配置终结点的方法:
如果同时使用 Listen
和 UseUrls API,Listen
终结点将覆盖 UseUrls
终结点。
绑定到 TCP 套接字
Listen、ListenLocalhost 和 ListenAnyIP 方法绑定到 TCP 套接字:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel((context, serverOptions) =>
{
serverOptions.Listen(IPAddress.Loopback, 5000);
serverOptions.Listen(IPAddress.Loopback, 5001, listenOptions =>
{
listenOptions.UseHttps("testCert.pfx", "testPassword");
});
});
上面的示例:
- 配置侦听端口 5000 和 5001 的终结点。
- 使用 ListenOptions 上的 UseHttps 扩展方法为终结点配置 HTTPS。 有关详细信息,请参阅在代码中配置 HTTPS。
在 Windows 上,可以使用 New-SelfSignedCertificate
PowerShell cmdlet 创建自签名证书。 有关不受支持的示例,请参阅 UpdateIISExpressSSLForChrome.ps1
。
在 macOS、Linux 和 Windows 上,可以使用 OpenSSL 创建证书。
绑定到 Unix 套接字
可通过 ListenUnixSocket 侦听 Unix 套接字以提高 Nginx 的性能,如以下示例所示:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel((context, serverOptions) =>
{
serverOptions.ListenUnixSocket("/tmp/kestrel-test.sock");
});
- 在 Nginx 配置文件中,将
server
>location
>proxy_pass
条目设置为http://unix:/tmp/{KESTREL SOCKET}:/;
。{KESTREL SOCKET}
是提供给 ListenUnixSocket 的套接字的名称(例如,上述示例中的kestrel-test.sock
)。 - 确保套接字可由 Nginx (例如
chmod go+w /tmp/kestrel-test.sock
)进行写入。
配置终结点默认值
ConfigureEndpointDefaults(Action<ListenOptions>)
指定为每个指定的终结点运行的配置。 多次调用 ConfigureEndpointDefaults
将替换以前的配置。
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.ConfigureEndpointDefaults(listenOptions =>
{
// ...
});
});
注意
通过在调用 ConfigureEndpointDefaults 之前调用 Listen 创建的终结点将不会应用默认值。
动态端口绑定
如果指定端口号 0
,Kestrel 将动态绑定到可用端口。 以下示例演示如何确定 Kestrel 在运行时绑定到的端口:
app.Run(async (context) =>
{
var serverAddressFeature = context.Features.Get<IServerAddressesFeature>();
if (serverAddressFeature is not null)
{
var listenAddresses = string.Join(", ", serverAddressFeature.Addresses);
// ...
}
});
在某些情况下,动态绑定端口不可用:
- KestrelServerOptions.ListenLocalhost
- 将基于 TCP 的 HTTP/1.1 或 HTTP/2 和基于 QUIC 的 HTTP/3 绑定在一起。
配置 HTTPS
Kestrel 支持使用 HTTPS 保护终结点。 通过 HTTPS 发送的数据使用传输层安全性 (TLS) 进行加密,以提高在客户端和服务器之间传输的数据的安全性。
HTTPS 需要 TLS 证书。 TLS 证书存储在服务器上,并将 Kestrel 配置为使用该证书。 应用可以在本地开发环境中使用 ASP.NET Core HTTPS 开发证书。 开发证书未安装在非开发环境中。 在生产环境中,必须显式配置 TLS 证书。 至少必须提供默认证书。
配置 HTTPS 和 TLS 证书的方式取决于终结点的配置方式:
- 如果 URL 前缀或仅指定端口用于定义终结点,则仅当 HTTPS 终结点配置中提供了默认证书时,才能使用 HTTPS。 可以使用以下选项之一配置默认证书:
- 在 appsettings.json 中配置 HTTPS
- 在代码中配置 HTTPS
在 appsettings.json 中配置 HTTPS
Kestrel 可以使用默认 HTTPS 应用设置配置架构。 从磁盘上的文件或从证书存储中配置多个终结点,包括要使用的 URL 和证书。
任何未指定证书的 HTTPS 终结点(下例中的 HttpsDefaultCert
)会回退至在 Certificates:Default
下定义的证书或开发证书。
以下示例适用于 appsettings.json
,但可以使用任何配置源:
{
"Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://localhost:5000"
},
"HttpsInlineCertFile": {
"Url": "https://localhost:5001",
"Certificate": {
"Path": "<path to .pfx file>",
"Password": "$CREDENTIAL_PLACEHOLDER$"
}
},
"HttpsInlineCertAndKeyFile": {
"Url": "https://localhost:5002",
"Certificate": {
"Path": "<path to .pem/.crt file>",
"KeyPath": "<path to .key file>",
"Password": "$CREDENTIAL_PLACEHOLDER$"
}
},
"HttpsInlineCertStore": {
"Url": "https://localhost:5003",
"Certificate": {
"Subject": "<subject; required>",
"Store": "<certificate store; required>",
"Location": "<location; defaults to CurrentUser>",
"AllowInvalid": "<true or false; defaults to false>"
}
},
"HttpsDefaultCert": {
"Url": "https://localhost:5004"
}
},
"Certificates": {
"Default": {
"Path": "<path to .pfx file>",
"Password": "$CREDENTIAL_PLACEHOLDER$"
}
}
}
}
警告
在上一示例中,证书密码以纯文本形式存储在 appsettings.json
中。 $CREDENTIAL_PLACEHOLDER$
令牌用作证书密码的占位符。 若要在开发环境中安全地存储证书密码,请参阅在开发过程中保护机密。 若要在生产环境中安全地存储证书密码,请参阅 Azure Key Vault 配置提供程序。 不应将开发机密用于生产或测试。
架构的注意事项
- 终结点的名称不区分大小写。 例如,由于再也无法解析标识符“Families”,因此
HTTPS
andHttps
是等效的。 - 每个终结点都要具备
Url
参数。 此参数的格式和顶层Urls
配置参数一样,只不过它只能有单个值。 请参阅本文前面部分的 URL 格式。 - 这些终结点不会添加在顶层
Urls
配置中定义的终结点,而是替换它们。 通过Listen
在代码中定义的终结点与在配置节中定义的终结点相累积。 Certificate
部分是可选的。 如果未指定Certificate
部分,则使用Certificates:Default
中定义的默认值。 如果没有可用的默认值,则使用开发证书。 如果没有默认值,且开发证书不存在,则服务器将引发异常,并且无法启动。Certificate
部分支持多个证书源。- 只要不会导致端口冲突,就能在
Configuration
中定义任何数量的终结点。
证书源
可以将证书节点配置为从多个源加载证书:
Path
和Password
用于加载 .pfx 文件。Path
、KeyPath
和Password
用于加载 .pem/.crt 和 .key 文件。Subject
和Store
用于从证书存储中加载。
例如,可将 Certificates:Default
证书指定为:
"Default": {
"Subject": "<subject; required>",
"Store": "<cert store; required>",
"Location": "<location; defaults to CurrentUser>",
"AllowInvalid": "<true or false; defaults to false>"
}
在 appsettings.json 中配置客户端证书
ClientCertificateMode 用于配置客户端证书行为。
{
"Kestrel": {
"Endpoints": {
"MyHttpsEndpoint": {
"Url": "https://localhost:5001",
"ClientCertificateMode": "AllowCertificate",
"Certificate": {
"Path": "<path to .pfx file>",
"Password": "$CREDENTIAL_PLACEHOLDER$"
}
}
}
}
}
警告
在上一示例中,证书密码以纯文本形式存储在 appsettings.json
中。 $CREDENTIAL_PLACEHOLDER$
令牌用作证书密码的占位符。 若要在开发环境中安全地存储证书密码,请参阅在开发过程中保护机密。 若要在生产环境中安全地存储证书密码,请参阅 Azure Key Vault 配置提供程序。 不应将开发机密用于生产或测试。
默认值为 ClientCertificateMode.NoCertificate
,其中 Kestrel 不会从客户端请求或要求证书。
有关详细信息,请参阅在 ASP.NET Core 中配置证书身份验证。
在 appsettings.json 中配置 SSL/TLS 协议
SSL 协议是用于在两个对等机(传统上是客户端和服务器)之间加密和解密流量的协议。
{
"Kestrel": {
"Endpoints": {
"MyHttpsEndpoint": {
"Url": "https://localhost:5001",
"SslProtocols": ["Tls12", "Tls13"],
"Certificate": {
"Path": "<path to .pfx file>",
"Password": "$CREDENTIAL_PLACEHOLDER$"
}
}
}
}
}
警告
在上一示例中,证书密码以纯文本形式存储在 appsettings.json
中。 $CREDENTIAL_PLACEHOLDER$
令牌用作证书密码的占位符。 若要在开发环境中安全地存储证书密码,请参阅在开发过程中保护机密。 若要在生产环境中安全地存储证书密码,请参阅 Azure Key Vault 配置提供程序。 不应将开发机密用于生产或测试。
默认值 SslProtocols.None
会导致 Kestrel 使用操作系统默认值来选择最佳协议。 除非你有特定原因要选择协议,否则请使用默认值。
在代码中配置 HTTPS
使用 Listen
API 时,ListenOptions 上的 UseHttps 扩展方法可用于配置 HTTPS。
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel((context, serverOptions) =>
{
serverOptions.Listen(IPAddress.Loopback, 5000);
serverOptions.Listen(IPAddress.Loopback, 5001, listenOptions =>
{
listenOptions.UseHttps("testCert.pfx", "testPassword");
});
});
ListenOptions.UseHttps
参数:
filename
是证书文件的路径和文件名,关联包含应用内容文件的目录。password
是访问 X.509 证书数据所需的密码。configureOptions
是配置HttpsConnectionAdapterOptions
的Action
。 返回ListenOptions
。storeName
是从中加载证书的证书存储。subject
是证书的主题名称。allowInvalid
指示是否存在需要留意的无效证书,例如自签名证书。location
是从中加载证书的存储位置。serverCertificate
是 X.509 证书。
有关 UseHttps
重载的完整列表,请参阅 UseHttps。
在代码中配置客户端证书
ClientCertificateMode 配置客户端证书要求。
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.ConfigureHttpsDefaults(listenOptions =>
{
listenOptions.ClientCertificateMode = ClientCertificateMode.AllowCertificate;
});
});
默认值为 NoCertificate,其中 Kestrel 不会从客户端请求或要求证书。
有关详细信息,请参阅在 ASP.NET Core 中配置证书身份验证。
在代码中配置 HTTPS 默认值
ConfigureHttpsDefaults(Action<HttpsConnectionAdapterOptions>) 指定要为每个 HTTPS 终结点运行的配置 Action
。 多次调用 ConfigureHttpsDefaults
,用最新指定的 Action
替换之前的 Action
实例。
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.ConfigureHttpsDefaults(listenOptions =>
{
// ...
});
});
注意
通过在调用 ConfigureHttpsDefaults 之前调用 Listen 创建的终结点将不会应用默认值。
在代码中配置 SSL/TLS 协议
SSL 协议是用于在两个对等机(传统上是客户端和服务器)之间加密和解密流量的协议。
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.ConfigureHttpsDefaults(listenOptions =>
{
listenOptions.SslProtocols = SslProtocols.Tls13;
});
});
在代码中配置 TLS 密码套件筛选器
在 Linux 上,CipherSuitesPolicy 可用于针对每个连接筛选 TLS 握手:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel((context, serverOptions) =>
{
serverOptions.ConfigureHttpsDefaults(listenOptions =>
{
listenOptions.OnAuthenticate = (context, sslOptions) =>
{
sslOptions.CipherSuitesPolicy = new CipherSuitesPolicy(
new[]
{
TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
// ...
});
};
});
});
配置服务器名称指示
服务器名称指示 (SNI) 可用于承载相同 IP 地址和端口上的多个域。 SNI 可用于通过从一台服务器为多个站点提供服务来节省资源。
为了运行 SNI,客户端在 TLS 握手过程中将进行安全会话的主机名发送至服务器,从而让服务器可以提供正确的证书。 在 TLS 握手后的安全会话期间,客户端将服务器提供的证书用于与服务器进行加密通信。
所有网站必须在相同的 Kestrel 实例上运行。 Kestrel 在无反向代理时不支持跨多个实例共享一个 IP 地址和端口。
可用两种方式配置 SNI:
- 在配置中配置主机名和 HTTPS 选项之间的映射。 例如,
appsettings.json
文件中的 JSON。 - 在代码中创建终结点,并通过 ServerCertificateSelector 回调使用主机名选择证书。
在 appsettings.json 中配置 SNI
Kestrel 支持配置中定义的 SNI。 可以使用包含主机名和 HTTPS 选项之间的映射的 Sni
对象来配置终结点。 连接主机名与选项匹配,并且这些选项用于该连接。
以下配置将添加一个名为 MySniEndpoint
的终结点,该终结点使用 SNI 基于主机名选择 HTTPS 选项:
{
"Kestrel": {
"Endpoints": {
"MySniEndpoint": {
"Url": "https://*",
"SslProtocols": ["Tls11", "Tls12"],
"Sni": {
"a.example.org": {
"Protocols": "Http1AndHttp2",
"SslProtocols": ["Tls11", "Tls12", "Tls13"],
"Certificate": {
"Subject": "<subject; required>",
"Store": "<certificate store; required>",
},
"ClientCertificateMode" : "NoCertificate"
},
"*.example.org": {
"Certificate": {
"Path": "<path to .pfx file>",
"Password": "$CREDENTIAL_PLACEHOLDER$"
}
},
"*": {
// At least one subproperty needs to exist per SNI section or it
// cannot be discovered via IConfiguration
"Protocols": "Http1",
}
}
}
},
"Certificates": {
"Default": {
"Path": "<path to .pfx file>",
"Password": "$CREDENTIAL_PLACEHOLDER$"
}
}
}
}
警告
在上一示例中,证书密码以纯文本形式存储在 appsettings.json
中。 $CREDENTIAL_PLACEHOLDER$
令牌用作证书密码的占位符。 若要在开发环境中安全地存储证书密码,请参阅在开发过程中保护机密。 若要在生产环境中安全地存储证书密码,请参阅 Azure Key Vault 配置提供程序。 不应将开发机密用于生产或测试。
可由 SNI 覆盖的 HTTPS 选项:
Certificate
配置证书源。Protocols
配置允许的 HTTP 协议。SslProtocols
配置允许的 SSL 协议。ClientCertificateMode
配置客户端证书要求。
主机名支持通配符匹配:
- 完全匹配。 例如,
a.example.org
匹配a.example.org
。 - 通配符前缀。 如果有多个通配符匹配项,则选择最长的模式。 例如,
*.example.org
匹配b.example.org
和c.example.org
。 - 完整通配符。
*
匹配其他所有内容,包括不使用 SNI 且不发送主机名的客户端。
匹配的 SNI 配置将应用于连接的终结点,并重写终结点上的值。 如果连接与已配置的 SNI 主机名不匹配,则连接将被拒绝。
使用代码配置 SNI
Kestrel 支持具有多个回调 API 的 SNI:
ServerCertificateSelector
ServerOptionsSelectionCallback
TlsHandshakeCallbackOptions
具有 ServerCertificateSelector
的 SNI
Kestrel 通过 ServerCertificateSelector
回调支持 SNI。 每次连接调用一次回调,从而允许应用检查主机名并选择合适的证书:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.ListenAnyIP(5005, listenOptions =>
{
listenOptions.UseHttps(httpsOptions =>
{
var localhostCert = CertificateLoader.LoadFromStoreCert(
"localhost", "My", StoreLocation.CurrentUser,
allowInvalid: true);
var exampleCert = CertificateLoader.LoadFromStoreCert(
"example.com", "My", StoreLocation.CurrentUser,
allowInvalid: true);
var subExampleCert = CertificateLoader.LoadFromStoreCert(
"sub.example.com", "My", StoreLocation.CurrentUser,
allowInvalid: true);
var certs = new Dictionary<string, X509Certificate2>(
StringComparer.OrdinalIgnoreCase)
{
["localhost"] = localhostCert,
["example.com"] = exampleCert,
["sub.example.com"] = subExampleCert
};
httpsOptions.ServerCertificateSelector = (connectionContext, name) =>
{
if (name is not null && certs.TryGetValue(name, out var cert))
{
return cert;
}
return exampleCert;
};
});
});
});
具有 ServerOptionsSelectionCallback
的 SNI
Kestrel 通过 ServerOptionsSelectionCallback
回调支持其他动态 TLS 配置。 每次连接调用一次回调,从而允许应用检查主机名并选择合适的证书和 TLS 配置。 默认证书和 ConfigureHttpsDefaults
不与此回调一起使用。
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.ListenAnyIP(5005, listenOptions =>
{
listenOptions.UseHttps(httpsOptions =>
{
var localhostCert = CertificateLoader.LoadFromStoreCert(
"localhost", "My", StoreLocation.CurrentUser,
allowInvalid: true);
var exampleCert = CertificateLoader.LoadFromStoreCert(
"example.com", "My", StoreLocation.CurrentUser,
allowInvalid: true);
listenOptions.UseHttps((stream, clientHelloInfo, state, cancellationToken) =>
{
if (string.Equals(clientHelloInfo.ServerName, "localhost",
StringComparison.OrdinalIgnoreCase))
{
return new ValueTask<SslServerAuthenticationOptions>(
new SslServerAuthenticationOptions
{
ServerCertificate = localhostCert,
// Different TLS requirements for this host
ClientCertificateRequired = true
});
}
return new ValueTask<SslServerAuthenticationOptions>(
new SslServerAuthenticationOptions
{
ServerCertificate = exampleCert
});
}, state: null!);
});
});
});
具有 TlsHandshakeCallbackOptions
的 SNI
Kestrel 通过 TlsHandshakeCallbackOptions.OnConnection
回调支持其他动态 TLS 配置。 每次连接调用一次回调,从而允许应用检查主机名并选择合适的证书、TLS 配置和其他服务器选项。 默认证书和 ConfigureHttpsDefaults
不与此回调一起使用。
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.ListenAnyIP(5005, listenOptions =>
{
listenOptions.UseHttps(httpsOptions =>
{
var localhostCert = CertificateLoader.LoadFromStoreCert(
"localhost", "My", StoreLocation.CurrentUser,
allowInvalid: true);
var exampleCert = CertificateLoader.LoadFromStoreCert(
"example.com", "My", StoreLocation.CurrentUser,
allowInvalid: true);
listenOptions.UseHttps(new TlsHandshakeCallbackOptions
{
OnConnection = context =>
{
if (string.Equals(context.ClientHelloInfo.ServerName, "localhost",
StringComparison.OrdinalIgnoreCase))
{
// Different TLS requirements for this host
context.AllowDelayedClientCertificateNegotation = true;
return new ValueTask<SslServerAuthenticationOptions>(
new SslServerAuthenticationOptions
{
ServerCertificate = localhostCert
});
}
return new ValueTask<SslServerAuthenticationOptions>(
new SslServerAuthenticationOptions
{
ServerCertificate = exampleCert
});
}
});
});
});
});
配置 HTTP 协议
Kestrel 支持所有常用的 HTTP 版本。 可以使用 HttpProtocols 枚举(指定可用的 HTTP 版本选项)将终结点配置为支持不同的 HTTP 版本。
需要 TLS 才能支持多个 HTTP 版本。 当终结点支持多个协议时,TLS 应用程序层协议协商 (ALPN) 握手可用于协商客户端与服务器之间的连接协议。
HttpProtocols 值 |
允许的连接协议 |
---|---|
Http1 |
仅 HTTP/1.1。 可以在具有 TLS 或没有 TLS 的情况下使用。 |
Http2 |
仅 HTTP/2。 仅当客户端支持先验知识模式时,才可以在没有 TLS 的情况下使用。 |
Http3 |
仅 HTTP/3。 需要 TLS。 可能需要将客户端配置为仅使用 HTTP/3。 |
Http1AndHttp2 |
HTTP/1.1 和 HTTP/2。 HTTP/2 要求客户端在 TLS 应用层协议协商 (ALPN) 握手过程中选择 HTTP/2;否则,连接默认为 HTTP/1.1。 |
Http1AndHttp2AndHttp3 |
HTTP/1.1、HTTP/2 和 HTTP/3。 第一个客户端请求通常使用 HTTP/1.1 或 HTTP/2,alt-svc 响应头会提示客户端升级到 HTTP/3。 HTTP/2 和 HTTP/3 需要 TLS;否则,连接默认为 HTTP/1.1。 |
终结点的默认协议值为 HttpProtocols.Http1AndHttp2
。
HTTP/2 的 TLS 限制:
- TLS 版本 1.2 或更高版本
- 重新协商已禁用
- 压缩已禁用
- 最小的临时密钥交换大小:
- 椭圆曲线 Diffie-Hellman (ECDHE) [RFC4492]:最小 224 位
- 有限字段 Diffie-Hellman (DHE) [
TLS12
]:最小 2048 位
- 不禁止密码套件。
默认情况下,支持具有 P-256 椭圆曲线 [FIPS186
] 的 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
[TLS-ECDHE
]。
在 appsettings.json 中配置 HTTP 协议
以下 appsettings.json
示例将为所有指定终结点建立 HTTP/1.1 连接协议:
{
"Kestrel": {
"Endpoints": {
"HttpsDefaultCert": {
"Url": "https://localhost:5001",
"Protocols": "Http1"
}
}
}
}
可以在 Kestrel:EndpointDefaults
节中配置默认协议。 以下 appsettings.json
示例将 HTTP/1.1 建立为所有终结点的默认连接协议:
{
"Kestrel": {
"EndpointDefaults": {
"Protocols": "Http1"
}
}
}
代码中指定的协议覆盖了由配置设置的值。
在代码中配置 HTTP 协议
ListenOptions.Protocols 用于指定具有 HttpProtocols 枚举的协议。
以下示例为端口 8000 上的 HTTP/1.1、HTTP/2 和 HTTP/3 连接配置终结点。 TLS 使用提供的证书来保护连接:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel((context, serverOptions) =>
{
serverOptions.Listen(IPAddress.Any, 8000, listenOptions =>
{
listenOptions.UseHttps("testCert.pfx", "testPassword");
listenOptions.Protocols = HttpProtocols.Http1AndHttp2AndHttp3;
});
});
请参阅
ASP.NET Core 项目被配置为绑定到 5000-5300 之间的随机 HTTP 端口和 7000-7300 之间的随机 HTTPS 端口。 这个默认配置是在生成的 Properties/launchSettings.json
文件中指定的,可以被重写。 如果没有指定端口,Kestrel 将绑定到 http://localhost:5000
。
使用以下内容指定 URL:
ASPNETCORE_URLS
环境变量。--urls
命令行参数。urls
主机配置键。- UseUrls 扩展方法。
采用这些方法提供的值可以是一个或多个 HTTP 和 HTTPS 终结点(如果默认证书可用,则为 HTTPS)。 将值配置为以分号分隔的列表(例如 "Urls": "http://localhost:8000;http://localhost:8001"
)。
关于开发证书的创建:
- 安装 .NET SDK 时。
- dev-certs tool 用于创建证书。
开发证书仅适用于生成证书的用户。 某些浏览器需要授予显式权限才能信任本地开发证书。
项目模板将应用配置为默认情况下在 HTTPS 上运行,并包括 HTTPS 重定向和 HSTS 支持。
调用 KestrelServerOptions 上的 Listen 或 ListenUnixSocket 方法以配置 URL 前缀和 Kestrel 的端口。
UseUrls
、--urls
命令行参数、urls
主机配置键以及 ASPNETCORE_URLS
环境变量也有用,但具有本节后面注明的限制(必须要有可用于 HTTPS 终结点配置的默认证书)。
KestrelServerOptions
配置:
ConfigureEndpointDefaults
ConfigureEndpointDefaults(Action<ListenOptions>) 指定一个为每个指定的终结点运行的配置 Action
。 多次调用 ConfigureEndpointDefaults
会将之前的 Action
替换为最后指定的 Action
:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.ConfigureEndpointDefaults(listenOptions =>
{
// ...
});
});
注意
通过在调用 ConfigureEndpointDefaults 之前调用 Listen 创建的终结点将不会应用默认值。
Configure(IConfiguration)
允许 Kestrel 从 IConfiguration 中加载终结点。 配置必须针对 Kestrel 的配置节。 Configure(IConfiguration, bool)
重载可用于在配置源更改时启用重载终结点。
默认情况下,从 Kestrel
部分加载 Kestrel 配置并启用重载更改:
{
"Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://localhost:5000"
},
"Https": {
"Url": "https://localhost:5001"
}
}
}
}
如果已启用重载配置并发出更改信号,则会执行以下步骤:
- 新配置与旧配置相比,不会修改任何没有配置更改的终结点。
- 已删除或已修改的终结点将在 5 秒内完成处理请求并关闭。
- 启动新的或已修改的终结点。
重启终结点时,连接到已修改的终结点的客户端可能会断开连接或被拒绝。
ConfigureHttpsDefaults
ConfigureHttpsDefaults(Action<HttpsConnectionAdapterOptions>) 指定一个为每个 HTTPS 终结点运行的配置 Action
。 多次调用 ConfigureHttpsDefaults
,用最新指定的 Action
替换之前的 Action
。
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.ConfigureHttpsDefaults(listenOptions =>
{
// ...
});
});
注意
通过在调用 ConfigureHttpsDefaults 之前调用 Listen 创建的终结点将不会应用默认值。
ListenOptions.UseHttps
将 Kestrel 配置为使用 HTTPS。
ListenOptions.UseHttps
扩展:
UseHttps
:将 Kestrel 配置为使用 HTTPS,采用默认证书。 如果没有配置默认证书,则会引发异常。UseHttps(string fileName)
UseHttps(string fileName, string password)
UseHttps(string fileName, string password, Action<HttpsConnectionAdapterOptions> configureOptions)
UseHttps(StoreName storeName, string subject)
UseHttps(StoreName storeName, string subject, bool allowInvalid)
UseHttps(StoreName storeName, string subject, bool allowInvalid, StoreLocation location)
UseHttps(StoreName storeName, string subject, bool allowInvalid, StoreLocation location, Action<HttpsConnectionAdapterOptions> configureOptions)
UseHttps(X509Certificate2 serverCertificate)
UseHttps(X509Certificate2 serverCertificate, Action<HttpsConnectionAdapterOptions> configureOptions)
UseHttps(Action<HttpsConnectionAdapterOptions> configureOptions)
ListenOptions.UseHttps
参数:
filename
是证书文件的路径和文件名,关联包含应用内容文件的目录。password
是访问 X.509 证书数据所需的密码。configureOptions
是配置HttpsConnectionAdapterOptions
的Action
。 返回ListenOptions
。storeName
是从中加载证书的证书存储。subject
是证书的主题名称。allowInvalid
指示是否存在需要留意的无效证书,例如自签名证书。location
是从中加载证书的存储位置。serverCertificate
是 X.509 证书。
在生产中,必须显式配置 HTTPS。 至少必须提供默认证书。
如果要从磁盘读取证书,而不是从 Windows 证书存储读取证书,则包含目录必须具有适当的权限,以防止未经授权的访问。
下面要描述的支持的配置:
- 无配置
- 从配置中替换默认证书
- 更改代码中的默认值
无配置
Kestrel 侦听 http://localhost:5000
。
从配置中替换默认证书
Kestrel 可以使用默认 HTTPS 应用设置配置架构。 从磁盘上的文件或从证书存储中配置多个终结点,包括要使用的 URL 和证书。
在以下 appsettings.json
示例中:
- 将
AllowInvalid
设置为true
,从而允许使用无效证书(例如自签名证书)。 - 任何未指定证书的 HTTPS 终结点(下例中的
HttpsDefaultCert
)会回退至在Certificates:Default
下定义的证书或开发证书。
{
"Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://localhost:5000"
},
"HttpsInlineCertFile": {
"Url": "https://localhost:5001",
"Certificate": {
"Path": "<path to .pfx file>",
"Password": "$CREDENTIAL_PLACEHOLDER$"
}
},
"HttpsInlineCertAndKeyFile": {
"Url": "https://localhost:5002",
"Certificate": {
"Path": "<path to .pem/.crt file>",
"KeyPath": "<path to .key file>",
"Password": "$CREDENTIAL_PLACEHOLDER$"
}
},
"HttpsInlineCertStore": {
"Url": "https://localhost:5003",
"Certificate": {
"Subject": "<subject; required>",
"Store": "<certificate store; required>",
"Location": "<location; defaults to CurrentUser>",
"AllowInvalid": "<true or false; defaults to false>"
}
},
"HttpsDefaultCert": {
"Url": "https://localhost:5004"
}
},
"Certificates": {
"Default": {
"Path": "<path to .pfx file>",
"Password": "$CREDENTIAL_PLACEHOLDER$"
}
}
}
}
警告
在上一示例中,证书密码以纯文本形式存储在 appsettings.json
中。 $CREDENTIAL_PLACEHOLDER$
令牌用作每个证书密码的占位符。 若要在开发环境中安全地存储证书密码,请参阅在开发过程中保护机密。 若要在生产环境中安全地存储证书密码,请参阅 Azure Key Vault 配置提供程序。 不应将开发机密用于生产或测试。
架构的注意事项:
- 终结点的名称不区分大小写。 例如,由于再也无法解析标识符“Families”,因此
HTTPS
andHttps
是等效的。 - 每个终结点都要具备
Url
参数。 此参数的格式和顶层Urls
配置参数一样,只不过它只能有单个值。 - 这些终结点不会添加进顶层
Urls
配置中定义的终结点,而是替换它们。 通过Listen
在代码中定义的终结点与在配置节中定义的终结点相累积。 Certificate
部分是可选的。 如果未指定Certificate
部分,则使用Certificates:Default
中定义的默认值。 如果没有可用的默认值,则使用开发证书。 如果没有默认值,且开发证书不存在,则服务器将引发异常,并且无法启动。Certificate
部分支持多个证书源。- 只要不会导致端口冲突,就能在配置中定义任何数量的终结点。
证书源
可以将证书节点配置为从多个源加载证书:
Path
和Password
用于加载 .pfx 文件。Path
、KeyPath
和Password
用于加载 .pem/.crt 和 .key 文件。Subject
和Store
用于从证书存储中加载。
例如,可将 Certificates:Default
证书指定为:
"Default": {
"Subject": "<subject; required>",
"Store": "<cert store; required>",
"Location": "<location; defaults to CurrentUser>",
"AllowInvalid": "<true or false; defaults to false>"
}
ConfigurationLoader
Configure(IConfiguration) 通过 Endpoint(String, Action<EndpointConfiguration>) 方法返回 KestrelConfigurationLoader,可以用于补充已配置的终结点设置:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel((context, serverOptions) =>
{
var kestrelSection = context.Configuration.GetSection("Kestrel");
serverOptions.Configure(kestrelSection)
.Endpoint("HTTPS", listenOptions =>
{
// ...
});
});
可以直接访问 KestrelServerOptions.ConfigurationLoader
以继续迭代现有加载程序,例如由 WebApplicationBuilder.WebHost 提供的加载程序。
- 每个终结点的配置节都可用于
Endpoint
方法中的选项,以便读取自定义设置。 - 通过另一节再次调用 Configure(IConfiguration) 可能加载多个配置。 只使用最新配置,除非之前的实例上显式调用了
Load
。 元包不会调用Load
,所以可能会替换它的默认配置节。 KestrelConfigurationLoader
从KestrelServerOptions
将 API 的Listen
簇反射为Endpoint
重载,因此可在同样的位置配置代码和配置终结点。 这些重载不使用名称,且只使用配置中的默认设置。
更改代码中的默认值
可以使用 ConfigureEndpointDefaults
和 ConfigureHttpsDefaults
更改 ListenOptions
和 HttpsConnectionAdapterOptions
的默认设置,包括重写之前的方案指定的默认证书。 需要在配置任何终结点之前调用 ConfigureEndpointDefaults
和 ConfigureHttpsDefaults
。
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel((context, serverOptions) =>
{
serverOptions.ConfigureEndpointDefaults(listenOptions =>
{
// ...
});
serverOptions.ConfigureHttpsDefaults(listenOptions =>
{
// ...
});
});
使用服务器名称指示配置终结点
服务器名称指示 (SNI) 可用于承载相同 IP 地址和端口上的多个域。 为了运行 SNI,客户端在 TLS 握手过程中将进行安全会话的主机名发送至服务器,从而让服务器可以提供正确的证书。 在 TLS 握手后的安全会话期间,客户端将服务器提供的证书用于与服务器进行加密通信。
可用两种方式配置 SNI:
- 在代码中创建终结点,并通过 ServerCertificateSelector 回调使用主机名选择证书。
- 在配置中配置主机名和 HTTPS 选项之间的映射。 例如,
appsettings.json
文件中的 JSON。
具有 ServerCertificateSelector
的 SNI
Kestrel 通过 ServerCertificateSelector
回调支持 SNI。 每次连接调用一次回调,从而允许应用检查主机名并选择合适的证书:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.ListenAnyIP(5005, listenOptions =>
{
listenOptions.UseHttps(httpsOptions =>
{
var localhostCert = CertificateLoader.LoadFromStoreCert(
"localhost", "My", StoreLocation.CurrentUser,
allowInvalid: true);
var exampleCert = CertificateLoader.LoadFromStoreCert(
"example.com", "My", StoreLocation.CurrentUser,
allowInvalid: true);
var subExampleCert = CertificateLoader.LoadFromStoreCert(
"sub.example.com", "My", StoreLocation.CurrentUser,
allowInvalid: true);
var certs = new Dictionary<string, X509Certificate2>(
StringComparer.OrdinalIgnoreCase)
{
["localhost"] = localhostCert,
["example.com"] = exampleCert,
["sub.example.com"] = subExampleCert
};
httpsOptions.ServerCertificateSelector = (connectionContext, name) =>
{
if (name is not null && certs.TryGetValue(name, out var cert))
{
return cert;
}
return exampleCert;
};
});
});
});
具有 ServerOptionsSelectionCallback
的 SNI
Kestrel 通过 ServerOptionsSelectionCallback
回调支持其他动态 TLS 配置。 每次连接调用一次回调,从而允许应用检查主机名并选择合适的证书和 TLS 配置。 默认证书和 ConfigureHttpsDefaults
不与此回调一起使用。
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.ListenAnyIP(5005, listenOptions =>
{
listenOptions.UseHttps(httpsOptions =>
{
var localhostCert = CertificateLoader.LoadFromStoreCert(
"localhost", "My", StoreLocation.CurrentUser,
allowInvalid: true);
var exampleCert = CertificateLoader.LoadFromStoreCert(
"example.com", "My", StoreLocation.CurrentUser,
allowInvalid: true);
listenOptions.UseHttps((stream, clientHelloInfo, state, cancellationToken) =>
{
if (string.Equals(clientHelloInfo.ServerName, "localhost",
StringComparison.OrdinalIgnoreCase))
{
return new ValueTask<SslServerAuthenticationOptions>(
new SslServerAuthenticationOptions
{
ServerCertificate = localhostCert,
// Different TLS requirements for this host
ClientCertificateRequired = true
});
}
return new ValueTask<SslServerAuthenticationOptions>(
new SslServerAuthenticationOptions
{
ServerCertificate = exampleCert
});
}, state: null!);
});
});
});
具有 TlsHandshakeCallbackOptions
的 SNI
Kestrel 通过 TlsHandshakeCallbackOptions.OnConnection
回调支持其他动态 TLS 配置。 每次连接调用一次回调,从而允许应用检查主机名并选择合适的证书、TLS 配置和其他服务器选项。 默认证书和 ConfigureHttpsDefaults
不与此回调一起使用。
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.ListenAnyIP(5005, listenOptions =>
{
listenOptions.UseHttps(httpsOptions =>
{
var localhostCert = CertificateLoader.LoadFromStoreCert(
"localhost", "My", StoreLocation.CurrentUser,
allowInvalid: true);
var exampleCert = CertificateLoader.LoadFromStoreCert(
"example.com", "My", StoreLocation.CurrentUser,
allowInvalid: true);
listenOptions.UseHttps(new TlsHandshakeCallbackOptions
{
OnConnection = context =>
{
if (string.Equals(context.ClientHelloInfo.ServerName, "localhost",
StringComparison.OrdinalIgnoreCase))
{
// Different TLS requirements for this host
context.AllowDelayedClientCertificateNegotation = true;
return new ValueTask<SslServerAuthenticationOptions>(
new SslServerAuthenticationOptions
{
ServerCertificate = localhostCert
});
}
return new ValueTask<SslServerAuthenticationOptions>(
new SslServerAuthenticationOptions
{
ServerCertificate = exampleCert
});
}
});
});
});
});
配置中的 SNI
Kestrel 支持配置中定义的 SNI。 可以使用包含主机名和 HTTPS 选项之间的映射的 Sni
对象来配置终结点。 连接主机名与选项匹配,并且这些选项用于该连接。
以下配置将添加一个名为 MySniEndpoint
的终结点,该终结点使用 SNI 基于主机名选择 HTTPS 选项:
{
"Kestrel": {
"Endpoints": {
"MySniEndpoint": {
"Url": "https://*",
"SslProtocols": ["Tls11", "Tls12"],
"Sni": {
"a.example.org": {
"Protocols": "Http1AndHttp2",
"SslProtocols": ["Tls11", "Tls12", "Tls13"],
"Certificate": {
"Subject": "<subject; required>",
"Store": "<certificate store; required>",
},
"ClientCertificateMode" : "NoCertificate"
},
"*.example.org": {
"Certificate": {
"Path": "<path to .pfx file>",
"Password": "$CREDENTIAL_PLACEHOLDER$"
}
},
"*": {
// At least one subproperty needs to exist per SNI section or it
// cannot be discovered via IConfiguration
"Protocols": "Http1",
}
}
}
},
"Certificates": {
"Default": {
"Path": "<path to .pfx file>",
"Password": "$CREDENTIAL_PLACEHOLDER$"
}
}
}
}
警告
在上一示例中,证书密码以纯文本形式存储在 appsettings.json
中。 $CREDENTIAL_PLACEHOLDER$
令牌用作每个证书密码的占位符。 若要在开发环境中安全地存储证书密码,请参阅在开发过程中保护机密。 若要在生产环境中安全地存储证书密码,请参阅 Azure Key Vault 配置提供程序。 不应将开发机密用于生产或测试。
可由 SNI 覆盖的 HTTPS 选项:
Certificate
配置证书源。Protocols
配置允许的 HTTP 协议。SslProtocols
配置允许的 SSL 协议。ClientCertificateMode
配置客户端证书要求。
主机名支持通配符匹配:
- 完全匹配。 例如,
a.example.org
匹配a.example.org
。 - 通配符前缀。 如果有多个通配符匹配项,则选择最长的模式。 例如,
*.example.org
匹配b.example.org
和c.example.org
。 - 完整通配符。
*
匹配其他所有内容,包括不使用 SNI 且不发送主机名的客户端。
匹配的 SNI 配置将应用于连接的终结点,并重写终结点上的值。 如果连接与已配置的 SNI 主机名不匹配,则连接将被拒绝。
SNI 要求
所有网站必须在相同的 Kestrel 实例上运行。 Kestrel 在无反向代理时不支持跨多个实例共享一个 IP 地址和端口。
SSL/TLS 协议
SSL 协议是用于在两个对等机(传统上是客户端和服务器)之间加密和解密流量的协议。
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.ConfigureHttpsDefaults(listenOptions =>
{
listenOptions.SslProtocols = SslProtocols.Tls13;
});
});
{
"Kestrel": {
"Endpoints": {
"MyHttpsEndpoint": {
"Url": "https://localhost:5001",
"SslProtocols": ["Tls12", "Tls13"],
"Certificate": {
"Path": "<path to .pfx file>",
"Password": "$CREDENTIAL_PLACEHOLDER$"
}
}
}
}
}
警告
在上一示例中,证书密码以纯文本形式存储在 appsettings.json
中。 $CREDENTIAL_PLACEHOLDER$
令牌用作证书密码的占位符。 若要在开发环境中安全地存储证书密码,请参阅在开发过程中保护机密。 若要在生产环境中安全地存储证书密码,请参阅 Azure Key Vault 配置提供程序。 不应将开发机密用于生产或测试。
默认值 SslProtocols.None
会导致 Kestrel 使用操作系统默认值来选择最佳协议。 除非你有特定原因要选择协议,否则请使用默认值。
客户端证书
ClientCertificateMode
配置客户端证书要求。
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.ConfigureHttpsDefaults(listenOptions =>
{
listenOptions.ClientCertificateMode = ClientCertificateMode.AllowCertificate;
});
});
{
"Kestrel": {
"Endpoints": {
"MyHttpsEndpoint": {
"Url": "https://localhost:5001",
"ClientCertificateMode": "AllowCertificate",
"Certificate": {
"Path": "<path to .pfx file>",
"Password": "$CREDENTIAL_PLACEHOLDER$"
}
}
}
}
}
警告
在上一示例中,证书密码以纯文本形式存储在 appsettings.json
中。 $CREDENTIAL_PLACEHOLDER$
令牌用作证书密码的占位符。 若要在开发环境中安全地存储证书密码,请参阅在开发过程中保护机密。 若要在生产环境中安全地存储证书密码,请参阅 Azure Key Vault 配置提供程序。
默认值为 ClientCertificateMode.NoCertificate
,其中 Kestrel 不会从客户端请求或要求证书。
有关详细信息,请参阅在 ASP.NET Core 中配置证书身份验证。
连接日志记录
调用 UseConnectionLogging 以发出用于进行连接上的字节级别通信的调试级别日志。 连接日志记录有助于排查低级通信中的问题,例如在 TLS 加密期间和代理后。 如果 UseConnectionLogging
放置在 UseHttps
之前,则会记录加密的流量。 如果 UseConnectionLogging
放置于 UseHttps
之后,则会记录解密的流量。 这是内置连接中间件。
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel((context, serverOptions) =>
{
serverOptions.Listen(IPAddress.Any, 8000, listenOptions =>
{
listenOptions.UseConnectionLogging();
});
});
绑定到 TCP 套接字
Listen 方法绑定至 TCP 套接字,且 options lambda 允许 X.509 证书配置:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel((context, serverOptions) =>
{
serverOptions.Listen(IPAddress.Loopback, 5000);
serverOptions.Listen(IPAddress.Loopback, 5001, listenOptions =>
{
listenOptions.UseHttps("testCert.pfx", "testPassword");
});
});
示例使用 ListenOptions 为终结点配置 HTTPS。 可使用相同 API 为特定终结点配置其他 Kestrel 设置。
在 Windows 上,可以使用 New-SelfSignedCertificate
PowerShell cmdlet 创建自签名证书。 有关不受支持的示例,请参阅 UpdateIISExpressSSLForChrome.ps1
。
在 macOS、Linux 和 Windows 上,可以使用 OpenSSL 创建证书。
绑定到 Unix 套接字
可通过 ListenUnixSocket 侦听 Unix 套接字以提高 Nginx 的性能,如以下示例所示:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel((context, serverOptions) =>
{
serverOptions.ListenUnixSocket("/tmp/kestrel-test.sock");
});
- 在 Nginx 配置文件中,将
server
>location
>proxy_pass
条目设置为http://unix:/tmp/{KESTREL SOCKET}:/;
。{KESTREL SOCKET}
是提供给 ListenUnixSocket 的套接字的名称(例如,上述示例中的kestrel-test.sock
)。 - 确保套接字可由 Nginx (例如
chmod go+w /tmp/kestrel-test.sock
)进行写入。
端口 0
如果指定端口号 0
,Kestrel 将动态绑定到可用端口。 以下示例演示如何确定 Kestrel 在运行时绑定到的端口:
app.Run(async (context) =>
{
var serverAddressFeature = context.Features.Get<IServerAddressesFeature>();
if (serverAddressFeature is not null)
{
var listenAddresses = string.Join(", ", serverAddressFeature.Addresses);
// ...
}
});
在某些情况下,动态绑定端口不可用:
ListenLocalhost
- 将基于 TCP 的 HTTP/1.1 或 HTTP/2 和基于 QUIC 的 HTTP/3 绑定在一起。
限制
使用以下方法配置终结点:
- UseUrls
--urls
命令行参数urls
主机配置键ASPNETCORE_URLS
环境变量
若要将代码用于 Kestrel 以外的服务器,这些方法非常有用。 不过,请注意以下限制:
- HTTPS 无法与这些方法结合使用,除非在 HTTPS 终结点配置中提供了默认证书(例如,使用
KestrelServerOptions
配置或配置文件,如本文前面的部分所示)。 - 如果同时使用
Listen
和UseUrls
方法,Listen
终结点将覆盖UseUrls
终结点。
IIS 终结点配置
使用 IIS 时,由 Listen
或 UseUrls
设置用于 IIS 覆盖绑定的 URL 绑定。 有关详细信息,请参阅 ASP.NET Core 模块。
ListenOptions.Protocols
Protocols
属性建立在连接终结点上或为服务器启用的 HTTP 协议(HttpProtocols
)。 从 HttpProtocols
枚举向 Protocols
属性赋值。
HttpProtocols 枚举值 |
允许的连接协议 |
---|---|
Http1 |
仅 HTTP/1.1。 可以在具有 TLS 或没有 TLS 的情况下使用。 |
Http2 |
仅 HTTP/2。 仅当客户端支持先验知识模式时,才可以在没有 TLS 的情况下使用。 |
Http3 |
仅 HTTP/3。 需要 TLS。 可能需要将客户端配置为仅使用 HTTP/3。 |
Http1AndHttp2 |
HTTP/1.1 和 HTTP/2。 HTTP/2 要求客户端在 TLS 应用层协议协商 (ALPN) 握手过程中选择 HTTP/2;否则,连接默认为 HTTP/1.1。 |
Http1AndHttp2AndHttp3 |
HTTP/1.1、HTTP/2 和 HTTP/3。 第一个客户端请求通常使用 HTTP/1.1 或 HTTP/2,alt-svc 响应头会提示客户端升级到 HTTP/3。 HTTP/2 和 HTTP/3 需要 TLS;否则,连接默认为 HTTP/1.1。 |
任何终结点的默认 ListenOptions.Protocols
值都为 HttpProtocols.Http1AndHttp2
。
HTTP/2 的 TLS 限制:
- TLS 版本 1.2 或更高版本
- 重新协商已禁用
- 压缩已禁用
- 最小的临时密钥交换大小:
- 椭圆曲线 Diffie-Hellman (ECDHE) [RFC4492]:最小 224 位
- 有限字段 Diffie-Hellman (DHE) [
TLS12
]:最小 2048 位
- 不禁止密码套件。
默认情况下,支持具有 P-256 椭圆曲线 [FIPS186
] 的 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
[TLS-ECDHE
]。
以下示例允许端口 8000 上的 HTTP/1.1 和 HTTP/2 连接。 TLS 使用提供的证书来保护连接:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel((context, serverOptions) =>
{
serverOptions.Listen(IPAddress.Any, 8000, listenOptions =>
{
listenOptions.UseHttps("testCert.pfx", "testPassword");
listenOptions.Protocols = HttpProtocols.Http1AndHttp2AndHttp3;
});
});
在 Linux 上,CipherSuitesPolicy 可用于针对每个连接筛选 TLS 握手:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel((context, serverOptions) =>
{
serverOptions.ConfigureHttpsDefaults(listenOptions =>
{
listenOptions.OnAuthenticate = (context, sslOptions) =>
{
sslOptions.CipherSuitesPolicy = new CipherSuitesPolicy(
new[]
{
TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
// ...
});
};
});
});
连接中间件
必要时,自定义连接中间件可以按连接为特定密码筛选 TLS 握手。
下面的示例针对应用不支持的任何密码算法引发 NotSupportedException。 或者,定义 ITlsHandshakeFeature.CipherAlgorithm 并将其与可接受的密码套件列表进行比较。
没有任何加密使用 CipherAlgorithmType.Null 密码算法。
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel((context, serverOptions) =>
{
serverOptions.Listen(IPAddress.Any, 8000, listenOptions =>
{
listenOptions.UseHttps("testCert.pfx", "testPassword");
listenOptions.Use((context, next) =>
{
var tlsFeature = context.Features.Get<ITlsHandshakeFeature>()!;
if (tlsFeature.CipherAlgorithm == CipherAlgorithmType.Null)
{
throw new NotSupportedException(
$"Prohibited cipher: {tlsFeature.CipherAlgorithm}");
}
return next();
});
});
});
从配置中设置 HTTP 协议
默认情况下,从 Kestrel
部分加载 Kestrel 配置。 以下 appsettings.json
示例将 HTTP/1.1 建立为所有终结点的默认连接协议:
{
"Kestrel": {
"EndpointDefaults": {
"Protocols": "Http1"
}
}
}
以下 appsettings.json
示例将为所有指定终结点建立 HTTP/1.1 连接协议:
{
"Kestrel": {
"Endpoints": {
"HttpsDefaultCert": {
"Url": "https://localhost:5001",
"Protocols": "Http1"
}
}
}
}
代码中指定的协议覆盖了由配置设置的值。
URL 前缀
如果使用 UseUrls
、--urls
命令行参数、urls
主机配置键或 ASPNETCORE_URLS
环境变量,URL 前缀可采用以下任意格式。
仅 HTTP URL 前缀是有效的。 使用 UseUrls
配置 URL 绑定时,Kestrel 不支持 HTTPS。
包含端口号的 IPv4 地址
http://65.55.39.10:80/
0.0.0.0
是一种绑定到所有 IPv4 地址的特殊情况。包含端口号的 IPv6 地址
http://[0:0:0:0:0:ffff:4137:270a]:80/
[::]
是 IPv40.0.0.0
的 IPv6 等效项。包含端口号的主机名
http://contoso.com:80/ http://*:80/
主机名、
*
和+
并不特殊。 没有识别为有效 IP 地址或localhost
的任何内容都将绑定到所有 IPv4 和 IPv6 IP。 若要将不同主机名绑定到相同端口上的不同 ASP.NET Core 应用,请使用 HTTP.sys 或反向代理服务器。 反向代理服务器示例包括 IIS、Nginx 或 Apache。警告
采用反向代理配置进行托管需要主机筛选。
包含端口号的主机
localhost
名称或包含端口号的环回 IPhttp://localhost:5000/ http://127.0.0.1:5000/ http://[::1]:5000/
指定
localhost
后,Kestrel 将尝试绑定到 IPv4 和 IPv6 环回接口。 如果其他服务正在任一环回接口上使用请求的端口,则 Kestrel 将无法启动。 如果任一环回接口出于任何其他原因(通常是因为 IPv6 不受支持)而不可用,则 Kestrel 将记录一个警告。
ASP.NET Core 项目被配置为绑定到 5000-5300 之间的随机 HTTP 端口和 7000-7300 之间的随机 HTTPS 端口。 这个默认配置是在生成的 Properties/launchSettings.json
文件中指定的,可以被重写。 如果没有指定端口,Kestrel 将绑定到:
http://localhost:5000
https://localhost:5001
(存在本地开发证书时)
使用以下内容指定 URL:
ASPNETCORE_URLS
环境变量。--urls
命令行参数。urls
主机配置键。- UseUrls 扩展方法。
采用这些方法提供的值可以是一个或多个 HTTP 和 HTTPS 终结点(如果默认证书可用,则为 HTTPS)。 将值配置为以分号分隔的列表(例如 "Urls": "http://localhost:8000;http://localhost:8001"
)。
关于开发证书的创建:
- 安装 .NET SDK 时。
- dev-certs tool 用于创建证书。
开发证书仅适用于生成证书的用户。 某些浏览器需要授予显式权限才能信任本地开发证书。
项目模板将应用配置为默认情况下在 HTTPS 上运行,并包括 HTTPS 重定向和 HSTS 支持。
调用 KestrelServerOptions 上的 Listen 或 ListenUnixSocket 方法以配置 URL 前缀和 Kestrel 的端口。
UseUrls
、--urls
命令行参数、urls
主机配置键以及 ASPNETCORE_URLS
环境变量也有用,但具有本节后面注明的限制(必须要有可用于 HTTPS 终结点配置的默认证书)。
KestrelServerOptions
配置:
ConfigureEndpointDefaults
ConfigureEndpointDefaults(Action<ListenOptions>) 指定一个为每个指定的终结点运行的配置 Action
。 多次调用 ConfigureEndpointDefaults
会将之前的 Action
替换为最后指定的 Action
:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.ConfigureEndpointDefaults(listenOptions =>
{
// ...
});
});
注意
通过在调用 ConfigureEndpointDefaults 之前调用 Listen 创建的终结点将不会应用默认值。
Configure(IConfiguration)
允许 Kestrel 从 IConfiguration 中加载终结点。 配置必须针对 Kestrel 的配置节。 Configure(IConfiguration, bool)
重载可用于在配置源更改时启用重载终结点。
默认情况下,从 Kestrel
部分加载 Kestrel 配置并启用重载更改:
{
"Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://localhost:5000"
},
"Https": {
"Url": "https://localhost:5001"
}
}
}
}
如果已启用重载配置并发出更改信号,则会执行以下步骤:
- 新配置与旧配置相比,不会修改任何没有配置更改的终结点。
- 已删除或已修改的终结点将在 5 秒内完成处理请求并关闭。
- 启动新的或已修改的终结点。
重启终结点时,连接到已修改的终结点的客户端可能会断开连接或被拒绝。
ConfigureHttpsDefaults
ConfigureHttpsDefaults(Action<HttpsConnectionAdapterOptions>) 指定一个为每个 HTTPS 终结点运行的配置 Action
。 多次调用 ConfigureHttpsDefaults
,用最新指定的 Action
替换之前的 Action
。
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.ConfigureHttpsDefaults(listenOptions =>
{
// ...
});
});
注意
通过在调用 ConfigureHttpsDefaults 之前调用 Listen 创建的终结点将不会应用默认值。
ListenOptions.UseHttps
将 Kestrel 配置为使用 HTTPS。
ListenOptions.UseHttps
扩展:
UseHttps
:将 Kestrel 配置为使用 HTTPS,采用默认证书。 如果没有配置默认证书,则会引发异常。UseHttps(string fileName)
UseHttps(string fileName, string password)
UseHttps(string fileName, string password, Action<HttpsConnectionAdapterOptions> configureOptions)
UseHttps(StoreName storeName, string subject)
UseHttps(StoreName storeName, string subject, bool allowInvalid)
UseHttps(StoreName storeName, string subject, bool allowInvalid, StoreLocation location)
UseHttps(StoreName storeName, string subject, bool allowInvalid, StoreLocation location, Action<HttpsConnectionAdapterOptions> configureOptions)
UseHttps(X509Certificate2 serverCertificate)
UseHttps(X509Certificate2 serverCertificate, Action<HttpsConnectionAdapterOptions> configureOptions)
UseHttps(Action<HttpsConnectionAdapterOptions> configureOptions)
ListenOptions.UseHttps
参数:
filename
是证书文件的路径和文件名,关联包含应用内容文件的目录。password
是访问 X.509 证书数据所需的密码。configureOptions
是配置HttpsConnectionAdapterOptions
的Action
。 返回ListenOptions
。storeName
是从中加载证书的证书存储。subject
是证书的主题名称。allowInvalid
指示是否存在需要留意的无效证书,例如自签名证书。location
是从中加载证书的存储位置。serverCertificate
是 X.509 证书。
在生产中,必须显式配置 HTTPS。 至少必须提供默认证书。
下面要描述的支持的配置:
- 无配置
- 从配置中替换默认证书
- 更改代码中的默认值
无配置
Kestrel 在 http://localhost:5000
和 https://localhost:5001
上进行侦听(如果默认证书可用)。
从配置中替换默认证书
Kestrel 可以使用默认 HTTPS 应用设置配置架构。 从磁盘上的文件或从证书存储中配置多个终结点,包括要使用的 URL 和证书。
在以下 appsettings.json
示例中:
- 将
AllowInvalid
设置为true
,从而允许使用无效证书(例如自签名证书)。 - 任何未指定证书的 HTTPS 终结点(下例中的
HttpsDefaultCert
)会回退至在Certificates:Default
下定义的证书或开发证书。
{
"Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://localhost:5000"
},
"HttpsInlineCertFile": {
"Url": "https://localhost:5001",
"Certificate": {
"Path": "<path to .pfx file>",
"Password": "$CREDENTIAL_PLACEHOLDER$"
}
},
"HttpsInlineCertAndKeyFile": {
"Url": "https://localhost:5002",
"Certificate": {
"Path": "<path to .pem/.crt file>",
"KeyPath": "<path to .key file>",
"Password": "$CREDENTIAL_PLACEHOLDER$"
}
},
"HttpsInlineCertStore": {
"Url": "https://localhost:5003",
"Certificate": {
"Subject": "<subject; required>",
"Store": "<certificate store; required>",
"Location": "<location; defaults to CurrentUser>",
"AllowInvalid": "<true or false; defaults to false>"
}
},
"HttpsDefaultCert": {
"Url": "https://localhost:5004"
}
},
"Certificates": {
"Default": {
"Path": "<path to .pfx file>",
"Password": "$CREDENTIAL_PLACEHOLDER$"
}
}
}
}
警告
在上一示例中,证书密码以纯文本形式存储在 appsettings.json
中。 $CREDENTIAL_PLACEHOLDER$
令牌用作每个证书密码的占位符。 若要在开发环境中安全地存储证书密码,请参阅在开发过程中保护机密。 若要在生产环境中安全地存储证书密码,请参阅 Azure Key Vault 配置提供程序。 不应将开发机密用于生产或测试。
架构的注意事项:
- 终结点的名称不区分大小写。 例如,由于再也无法解析标识符“Families”,因此
HTTPS
andHttps
是等效的。 - 每个终结点都要具备
Url
参数。 此参数的格式和顶层Urls
配置参数一样,只不过它只能有单个值。 - 这些终结点不会添加进顶层
Urls
配置中定义的终结点,而是替换它们。 通过Listen
在代码中定义的终结点与在配置节中定义的终结点相累积。 Certificate
部分是可选的。 如果未指定Certificate
部分,则使用Certificates:Default
中定义的默认值。 如果没有可用的默认值,则使用开发证书。 如果没有默认值,且开发证书不存在,则服务器将引发异常,并且无法启动。Certificate
部分支持多个证书源。- 只要不会导致端口冲突,就能在配置中定义任何数量的终结点。
证书源
可以将证书节点配置为从多个源加载证书:
Path
和Password
用于加载 .pfx 文件。Path
、KeyPath
和Password
用于加载 .pem/.crt 和 .key 文件。Subject
和Store
用于从证书存储中加载。
例如,可将 Certificates:Default
证书指定为:
"Default": {
"Subject": "<subject; required>",
"Store": "<cert store; required>",
"Location": "<location; defaults to CurrentUser>",
"AllowInvalid": "<true or false; defaults to false>"
}
ConfigurationLoader
Configure(IConfiguration) 通过 Endpoint(String, Action<EndpointConfiguration>) 方法返回 KestrelConfigurationLoader,可以用于补充已配置的终结点设置:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel((context, serverOptions) =>
{
var kestrelSection = context.Configuration.GetSection("Kestrel");
serverOptions.Configure(kestrelSection)
.Endpoint("HTTPS", listenOptions =>
{
// ...
});
});
可以直接访问 KestrelServerOptions.ConfigurationLoader
以继续迭代现有加载程序,例如由 WebApplicationBuilder.WebHost 提供的加载程序。
- 每个终结点的配置节都可用于
Endpoint
方法中的选项,以便读取自定义设置。 - 通过另一节再次调用 Configure(IConfiguration) 可能加载多个配置。 只使用最新配置,除非之前的实例上显式调用了
Load
。 元包不会调用Load
,所以可能会替换它的默认配置节。 KestrelConfigurationLoader
从KestrelServerOptions
将 API 的Listen
簇反射为Endpoint
重载,因此可在同样的位置配置代码和配置终结点。 这些重载不使用名称,且只使用配置中的默认设置。
更改代码中的默认值
可以使用 ConfigureEndpointDefaults
和 ConfigureHttpsDefaults
更改 ListenOptions
和 HttpsConnectionAdapterOptions
的默认设置,包括重写之前的方案指定的默认证书。 需要在配置任何终结点之前调用 ConfigureEndpointDefaults
和 ConfigureHttpsDefaults
。
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel((context, serverOptions) =>
{
serverOptions.ConfigureEndpointDefaults(listenOptions =>
{
// ...
});
serverOptions.ConfigureHttpsDefaults(listenOptions =>
{
// ...
});
});
使用服务器名称指示配置终结点
服务器名称指示 (SNI) 可用于承载相同 IP 地址和端口上的多个域。 为了运行 SNI,客户端在 TLS 握手过程中将进行安全会话的主机名发送至服务器,从而让服务器可以提供正确的证书。 在 TLS 握手后的安全会话期间,客户端将服务器提供的证书用于与服务器进行加密通信。
可用两种方式配置 SNI:
- 在代码中创建终结点,并通过 ServerCertificateSelector 回调使用主机名选择证书。
- 在配置中配置主机名和 HTTPS 选项之间的映射。 例如,
appsettings.json
文件中的 JSON。
具有 ServerCertificateSelector
的 SNI
Kestrel 通过 ServerCertificateSelector
回调支持 SNI。 每次连接调用一次回调,从而允许应用检查主机名并选择合适的证书:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.ListenAnyIP(5005, listenOptions =>
{
listenOptions.UseHttps(httpsOptions =>
{
var localhostCert = CertificateLoader.LoadFromStoreCert(
"localhost", "My", StoreLocation.CurrentUser,
allowInvalid: true);
var exampleCert = CertificateLoader.LoadFromStoreCert(
"example.com", "My", StoreLocation.CurrentUser,
allowInvalid: true);
var subExampleCert = CertificateLoader.LoadFromStoreCert(
"sub.example.com", "My", StoreLocation.CurrentUser,
allowInvalid: true);
var certs = new Dictionary<string, X509Certificate2>(
StringComparer.OrdinalIgnoreCase)
{
["localhost"] = localhostCert,
["example.com"] = exampleCert,
["sub.example.com"] = subExampleCert
};
httpsOptions.ServerCertificateSelector = (connectionContext, name) =>
{
if (name is not null && certs.TryGetValue(name, out var cert))
{
return cert;
}
return exampleCert;
};
});
});
});
具有 ServerOptionsSelectionCallback
的 SNI
Kestrel 通过 ServerOptionsSelectionCallback
回调支持其他动态 TLS 配置。 每次连接调用一次回调,从而允许应用检查主机名并选择合适的证书和 TLS 配置。 默认证书和 ConfigureHttpsDefaults
不与此回调一起使用。
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.ListenAnyIP(5005, listenOptions =>
{
listenOptions.UseHttps(httpsOptions =>
{
var localhostCert = CertificateLoader.LoadFromStoreCert(
"localhost", "My", StoreLocation.CurrentUser,
allowInvalid: true);
var exampleCert = CertificateLoader.LoadFromStoreCert(
"example.com", "My", StoreLocation.CurrentUser,
allowInvalid: true);
listenOptions.UseHttps((stream, clientHelloInfo, state, cancellationToken) =>
{
if (string.Equals(clientHelloInfo.ServerName, "localhost",
StringComparison.OrdinalIgnoreCase))
{
return new ValueTask<SslServerAuthenticationOptions>(
new SslServerAuthenticationOptions
{
ServerCertificate = localhostCert,
// Different TLS requirements for this host
ClientCertificateRequired = true
});
}
return new ValueTask<SslServerAuthenticationOptions>(
new SslServerAuthenticationOptions
{
ServerCertificate = exampleCert
});
}, state: null!);
});
});
});
具有 TlsHandshakeCallbackOptions
的 SNI
Kestrel 通过 TlsHandshakeCallbackOptions.OnConnection
回调支持其他动态 TLS 配置。 每次连接调用一次回调,从而允许应用检查主机名并选择合适的证书、TLS 配置和其他服务器选项。 默认证书和 ConfigureHttpsDefaults
不与此回调一起使用。
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.ListenAnyIP(5005, listenOptions =>
{
listenOptions.UseHttps(httpsOptions =>
{
var localhostCert = CertificateLoader.LoadFromStoreCert(
"localhost", "My", StoreLocation.CurrentUser,
allowInvalid: true);
var exampleCert = CertificateLoader.LoadFromStoreCert(
"example.com", "My", StoreLocation.CurrentUser,
allowInvalid: true);
listenOptions.UseHttps(new TlsHandshakeCallbackOptions
{
OnConnection = context =>
{
if (string.Equals(context.ClientHelloInfo.ServerName, "localhost",
StringComparison.OrdinalIgnoreCase))
{
// Different TLS requirements for this host
context.AllowDelayedClientCertificateNegotation = true;
return new ValueTask<SslServerAuthenticationOptions>(
new SslServerAuthenticationOptions
{
ServerCertificate = localhostCert
});
}
return new ValueTask<SslServerAuthenticationOptions>(
new SslServerAuthenticationOptions
{
ServerCertificate = exampleCert
});
}
});
});
});
});
配置中的 SNI
Kestrel 支持配置中定义的 SNI。 可以使用包含主机名和 HTTPS 选项之间的映射的 Sni
对象来配置终结点。 连接主机名与选项匹配,并且这些选项用于该连接。
以下配置将添加一个名为 MySniEndpoint
的终结点,该终结点使用 SNI 基于主机名选择 HTTPS 选项:
{
"Kestrel": {
"Endpoints": {
"MySniEndpoint": {
"Url": "https://*",
"SslProtocols": ["Tls11", "Tls12"],
"Sni": {
"a.example.org": {
"Protocols": "Http1AndHttp2",
"SslProtocols": ["Tls11", "Tls12", "Tls13"],
"Certificate": {
"Subject": "<subject; required>",
"Store": "<certificate store; required>",
},
"ClientCertificateMode" : "NoCertificate"
},
"*.example.org": {
"Certificate": {
"Path": "<path to .pfx file>",
"Password": "$CREDENTIAL_PLACEHOLDER$"
}
},
"*": {
// At least one subproperty needs to exist per SNI section or it
// cannot be discovered via IConfiguration
"Protocols": "Http1",
}
}
}
},
"Certificates": {
"Default": {
"Path": "<path to .pfx file>",
"Password": "$CREDENTIAL_PLACEHOLDER$"
}
}
}
}
警告
在上一示例中,证书密码以纯文本形式存储在 appsettings.json
中。 $CREDENTIAL_PLACEHOLDER$
令牌用作每个证书密码的占位符。 若要在开发环境中安全地存储证书密码,请参阅在开发过程中保护机密。 若要在生产环境中安全地存储证书密码,请参阅 Azure Key Vault 配置提供程序。 不应将开发机密用于生产或测试。
可由 SNI 覆盖的 HTTPS 选项:
Certificate
配置证书源。Protocols
配置允许的 HTTP 协议。SslProtocols
配置允许的 SSL 协议。ClientCertificateMode
配置客户端证书要求。
主机名支持通配符匹配:
- 完全匹配。 例如,
a.example.org
匹配a.example.org
。 - 通配符前缀。 如果有多个通配符匹配项,则选择最长的模式。 例如,
*.example.org
匹配b.example.org
和c.example.org
。 - 完整通配符。
*
匹配其他所有内容,包括不使用 SNI 且不发送主机名的客户端。
匹配的 SNI 配置将应用于连接的终结点,并重写终结点上的值。 如果连接与已配置的 SNI 主机名不匹配,则连接将被拒绝。
SNI 要求
所有网站必须在相同的 Kestrel 实例上运行。 Kestrel 在无反向代理时不支持跨多个实例共享一个 IP 地址和端口。
SSL/TLS 协议
SSL 协议是用于在两个对等机(传统上是客户端和服务器)之间加密和解密流量的协议。
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.ConfigureHttpsDefaults(listenOptions =>
{
listenOptions.SslProtocols = SslProtocols.Tls13;
});
});
{
"Kestrel": {
"Endpoints": {
"MyHttpsEndpoint": {
"Url": "https://localhost:5001",
"SslProtocols": ["Tls12", "Tls13"],
"Certificate": {
"Path": "<path to .pfx file>",
"Password": "$CREDENTIAL_PLACEHOLDER$"
}
}
}
}
}
警告
在上一示例中,证书密码以纯文本形式存储在 appsettings.json
中。 $CREDENTIAL_PLACEHOLDER$
令牌用作证书密码的占位符。 若要在开发环境中安全地存储证书密码,请参阅在开发过程中保护机密。 若要在生产环境中安全地存储证书密码,请参阅 Azure Key Vault 配置提供程序。 不应将开发机密用于生产或测试。
默认值 SslProtocols.None
会导致 Kestrel 使用操作系统默认值来选择最佳协议。 除非你有特定原因要选择协议,否则请使用默认值。
客户端证书
ClientCertificateMode
配置客户端证书要求。
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.ConfigureHttpsDefaults(listenOptions =>
{
listenOptions.ClientCertificateMode = ClientCertificateMode.AllowCertificate;
});
});
{
"Kestrel": {
"Endpoints": {
"MyHttpsEndpoint": {
"Url": "https://localhost:5001",
"ClientCertificateMode": "AllowCertificate",
"Certificate": {
"Path": "<path to .pfx file>",
"Password": "$CREDENTIAL_PLACEHOLDER$"
}
}
}
}
}
警告
在上一示例中,证书密码以纯文本形式存储在 appsettings.json
中。 $CREDENTIAL_PLACEHOLDER$
令牌用作证书密码的占位符。 若要在开发环境中安全地存储证书密码,请参阅在开发过程中保护机密。 若要在生产环境中安全地存储证书密码,请参阅 Azure Key Vault 配置提供程序。
默认值为 ClientCertificateMode.NoCertificate
,其中 Kestrel 不会从客户端请求或要求证书。
有关详细信息,请参阅在 ASP.NET Core 中配置证书身份验证。
连接日志记录
调用 UseConnectionLogging 以发出用于进行连接上的字节级别通信的调试级别日志。 连接日志记录有助于排查低级通信中的问题,例如在 TLS 加密期间和代理后。 如果 UseConnectionLogging
放置在 UseHttps
之前,则会记录加密的流量。 如果 UseConnectionLogging
放置于 UseHttps
之后,则会记录解密的流量。 这是内置连接中间件。
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel((context, serverOptions) =>
{
serverOptions.Listen(IPAddress.Any, 8000, listenOptions =>
{
listenOptions.UseConnectionLogging();
});
});
绑定到 TCP 套接字
Listen 方法绑定至 TCP 套接字,且 options lambda 允许 X.509 证书配置:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel((context, serverOptions) =>
{
serverOptions.Listen(IPAddress.Loopback, 5000);
serverOptions.Listen(IPAddress.Loopback, 5001, listenOptions =>
{
listenOptions.UseHttps("testCert.pfx", "testPassword");
});
});
示例使用 ListenOptions 为终结点配置 HTTPS。 可使用相同 API 为特定终结点配置其他 Kestrel 设置。
在 Windows 上,可以使用 New-SelfSignedCertificate
PowerShell cmdlet 创建自签名证书。 有关不受支持的示例,请参阅 UpdateIISExpressSSLForChrome.ps1
。
在 macOS、Linux 和 Windows 上,可以使用 OpenSSL 创建证书。
绑定到 Unix 套接字
可通过 ListenUnixSocket 侦听 Unix 套接字以提高 Nginx 的性能,如以下示例所示:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel((context, serverOptions) =>
{
serverOptions.ListenUnixSocket("/tmp/kestrel-test.sock");
});
- 在 Nginx 配置文件中,将
server
>location
>proxy_pass
条目设置为http://unix:/tmp/{KESTREL SOCKET}:/;
。{KESTREL SOCKET}
是提供给 ListenUnixSocket 的套接字的名称(例如,上述示例中的kestrel-test.sock
)。 - 确保套接字可由 Nginx (例如
chmod go+w /tmp/kestrel-test.sock
)进行写入。
端口 0
如果指定端口号 0
,Kestrel 将动态绑定到可用端口。 以下示例演示如何确定 Kestrel 在运行时绑定到的端口:
app.Run(async (context) =>
{
var serverAddressFeature = context.Features.Get<IServerAddressesFeature>();
if (serverAddressFeature is not null)
{
var listenAddresses = string.Join(", ", serverAddressFeature.Addresses);
// ...
}
});
限制
使用以下方法配置终结点:
- UseUrls
--urls
命令行参数urls
主机配置键ASPNETCORE_URLS
环境变量
若要将代码用于 Kestrel 以外的服务器,这些方法非常有用。 不过,请注意以下限制:
- HTTPS 无法与这些方法结合使用,除非在 HTTPS 终结点配置中提供了默认证书(例如,使用
KestrelServerOptions
配置或配置文件,如本文前面的部分所示)。 - 如果同时使用
Listen
和UseUrls
方法,Listen
终结点将覆盖UseUrls
终结点。
IIS 终结点配置
使用 IIS 时,由 Listen
或 UseUrls
设置用于 IIS 覆盖绑定的 URL 绑定。 有关详细信息,请参阅 ASP.NET Core 模块。
ListenOptions.Protocols
Protocols
属性建立在连接终结点上或为服务器启用的 HTTP 协议(HttpProtocols
)。 从 HttpProtocols
枚举向 Protocols
属性赋值。
HttpProtocols 枚举值 |
允许的连接协议 |
---|---|
Http1 |
仅 HTTP/1.1。 可以在具有 TLS 或没有 TLS 的情况下使用。 |
Http2 |
仅 HTTP/2。 仅当客户端支持先验知识模式时,才可以在没有 TLS 的情况下使用。 |
Http1AndHttp2 |
HTTP/1.1 和 HTTP/2。 HTTP/2 要求客户端在 TLS 应用层协议协商 (ALPN) 握手过程中选择 HTTP/2;否则,连接默认为 HTTP/1.1。 |
任何终结点的默认 ListenOptions.Protocols
值都为 HttpProtocols.Http1AndHttp2
。
HTTP/2 的 TLS 限制:
- TLS 版本 1.2 或更高版本
- 重新协商已禁用
- 压缩已禁用
- 最小的临时密钥交换大小:
- 椭圆曲线 Diffie-Hellman (ECDHE) [RFC4492]:最小 224 位
- 有限字段 Diffie-Hellman (DHE) [
TLS12
]:最小 2048 位
- 不禁止密码套件。
默认情况下,支持具有 P-256 椭圆曲线 [FIPS186
] 的 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
[TLS-ECDHE
]。
以下示例允许端口 8000 上的 HTTP/1.1 和 HTTP/2 连接。 TLS 使用提供的证书来保护连接:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel((context, serverOptions) =>
{
serverOptions.Listen(IPAddress.Any, 8000, listenOptions =>
{
listenOptions.UseHttps("testCert.pfx", "testPassword");
listenOptions.Protocols = HttpProtocols.Http1AndHttp2AndHttp3;
});
});
在 Linux 上,CipherSuitesPolicy 可用于针对每个连接筛选 TLS 握手:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel((context, serverOptions) =>
{
serverOptions.ConfigureHttpsDefaults(listenOptions =>
{
listenOptions.OnAuthenticate = (context, sslOptions) =>
{
sslOptions.CipherSuitesPolicy = new CipherSuitesPolicy(
new[]
{
TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
// ...
});
};
});
});
连接中间件
必要时,自定义连接中间件可以按连接为特定密码筛选 TLS 握手。
下面的示例针对应用不支持的任何密码算法引发 NotSupportedException。 或者,定义 ITlsHandshakeFeature.CipherAlgorithm 并将其与可接受的密码套件列表进行比较。
没有任何加密使用 CipherAlgorithmType.Null 密码算法。
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel((context, serverOptions) =>
{
serverOptions.Listen(IPAddress.Any, 8000, listenOptions =>
{
listenOptions.UseHttps("testCert.pfx", "testPassword");
listenOptions.Use((context, next) =>
{
var tlsFeature = context.Features.Get<ITlsHandshakeFeature>()!;
if (tlsFeature.CipherAlgorithm == CipherAlgorithmType.Null)
{
throw new NotSupportedException(
$"Prohibited cipher: {tlsFeature.CipherAlgorithm}");
}
return next();
});
});
});
从配置中设置 HTTP 协议
默认情况下,从 Kestrel
部分加载 Kestrel 配置。 以下 appsettings.json
示例将 HTTP/1.1 建立为所有终结点的默认连接协议:
{
"Kestrel": {
"EndpointDefaults": {
"Protocols": "Http1"
}
}
}
以下 appsettings.json
示例将为所有指定终结点建立 HTTP/1.1 连接协议:
{
"Kestrel": {
"Endpoints": {
"HttpsDefaultCert": {
"Url": "https://localhost:5001",
"Protocols": "Http1"
}
}
}
}
代码中指定的协议覆盖了由配置设置的值。
URL 前缀
如果使用 UseUrls
、--urls
命令行参数、urls
主机配置键或 ASPNETCORE_URLS
环境变量,URL 前缀可采用以下任意格式。
仅 HTTP URL 前缀是有效的。 使用 UseUrls
配置 URL 绑定时,Kestrel 不支持 HTTPS。
包含端口号的 IPv4 地址
http://65.55.39.10:80/
0.0.0.0
是一种绑定到所有 IPv4 地址的特殊情况。包含端口号的 IPv6 地址
http://[0:0:0:0:0:ffff:4137:270a]:80/
[::]
是 IPv40.0.0.0
的 IPv6 等效项。包含端口号的主机名
http://contoso.com:80/ http://*:80/
主机名、
*
和+
并不特殊。 没有识别为有效 IP 地址或localhost
的任何内容都将绑定到所有 IPv4 和 IPv6 IP。 若要将不同主机名绑定到相同端口上的不同 ASP.NET Core 应用,请使用 HTTP.sys 或反向代理服务器。 反向代理服务器示例包括 IIS、Nginx 或 Apache。警告
采用反向代理配置进行托管需要主机筛选。
包含端口号的主机
localhost
名称或包含端口号的环回 IPhttp://localhost:5000/ http://127.0.0.1:5000/ http://[::1]:5000/
指定
localhost
后,Kestrel 将尝试绑定到 IPv4 和 IPv6 环回接口。 如果其他服务正在任一环回接口上使用请求的端口,则 Kestrel 将无法启动。 如果任一环回接口出于任何其他原因(通常是因为 IPv6 不受支持)而不可用,则 Kestrel 将记录一个警告。
默认情况下,ASP.NET Core 绑定到:
http://localhost:5000
https://localhost:5001
(存在本地开发证书时)
使用以下内容指定 URL:
ASPNETCORE_URLS
环境变量。--urls
命令行参数。urls
主机配置键。- UseUrls 扩展方法。
采用这些方法提供的值可以是一个或多个 HTTP 和 HTTPS 终结点(如果默认证书可用,则为 HTTPS)。 将值配置为以分号分隔的列表(例如 "Urls": "http://localhost:8000;http://localhost:8001"
)。
关于开发证书的创建:
- 安装 .NET SDK 时。
- dev-certs tool 用于创建证书。
某些浏览器需要授予显式权限才能信任本地开发证书。
项目模板将应用配置为默认情况下在 HTTPS 上运行,并包括 HTTPS 重定向和 HSTS 支持。
调用 KestrelServerOptions 上的 Listen 或 ListenUnixSocket 方法以配置 URL 前缀和 Kestrel 的端口。
UseUrls
、--urls
命令行参数、urls
主机配置键以及 ASPNETCORE_URLS
环境变量也有用,但具有本节后面注明的限制(必须要有可用于 HTTPS 终结点配置的默认证书)。
KestrelServerOptions
配置:
ConfigureEndpointDefaults
ConfigureEndpointDefaults(Action<ListenOptions>) 指定一个为每个指定的终结点运行的配置 Action
。 多次调用 ConfigureEndpointDefaults
,用最新指定的 Action
替换之前的 Action
。
webBuilder.ConfigureKestrel(serverOptions =>
{
serverOptions.ConfigureEndpointDefaults(listenOptions =>
{
// Configure endpoint defaults
});
});
注意
通过在调用 ConfigureEndpointDefaults 之前调用 Listen 创建的终结点将不会应用默认值。
Configure(IConfiguration)
允许 Kestrel 从 IConfiguration 中加载终结点。 配置必须针对 Kestrel 的配置节。
Configure(IConfiguration, bool)
重载可用于在配置源更改时启用重载终结点。
IHostBuilder.ConfigureWebHostDefaults
在默认情况下调用 Configure(context.Configuration.GetSection("Kestrel"), reloadOnChange: true)
来加载 Kestrel 配置并启用重载。
{
"Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://localhost:5000"
},
"Https": {
"Url": "https://localhost:5001"
}
}
}
}
如果已启用重载配置并发出更改信号,则会执行以下步骤:
- 新配置与旧配置相比,不会修改任何没有配置更改的终结点。
- 已删除或已修改的终结点将在 5 秒内完成处理请求并关闭。
- 启动新的或已修改的终结点。
重启终结点时,连接到已修改的终结点的客户端可能会断开连接或被拒绝。
ConfigureHttpsDefaults
ConfigureHttpsDefaults(Action<HttpsConnectionAdapterOptions>) 指定一个为每个 HTTPS 终结点运行的配置 Action
。 多次调用 ConfigureHttpsDefaults
,用最新指定的 Action
替换之前的 Action
。
webBuilder.ConfigureKestrel(serverOptions =>
{
serverOptions.ConfigureHttpsDefaults(listenOptions =>
{
// certificate is an X509Certificate2
listenOptions.ServerCertificate = certificate;
});
});
注意
通过在调用 ConfigureHttpsDefaults 之前调用 Listen 创建的终结点将不会应用默认值。
ListenOptions.UseHttps
将 Kestrel 配置为使用 HTTPS。
ListenOptions.UseHttps
扩展:
UseHttps
:将 Kestrel 配置为使用 HTTPS,采用默认证书。 如果没有配置默认证书,则会引发异常。UseHttps(string fileName)
UseHttps(string fileName, string password)
UseHttps(string fileName, string password, Action<HttpsConnectionAdapterOptions> configureOptions)
UseHttps(StoreName storeName, string subject)
UseHttps(StoreName storeName, string subject, bool allowInvalid)
UseHttps(StoreName storeName, string subject, bool allowInvalid, StoreLocation location)
UseHttps(StoreName storeName, string subject, bool allowInvalid, StoreLocation location, Action<HttpsConnectionAdapterOptions> configureOptions)
UseHttps(X509Certificate2 serverCertificate)
UseHttps(X509Certificate2 serverCertificate, Action<HttpsConnectionAdapterOptions> configureOptions)
UseHttps(Action<HttpsConnectionAdapterOptions> configureOptions)
ListenOptions.UseHttps
参数:
filename
是证书文件的路径和文件名,关联包含应用内容文件的目录。password
是访问 X.509 证书数据所需的密码。configureOptions
是配置HttpsConnectionAdapterOptions
的Action
。 返回ListenOptions
。storeName
是从中加载证书的证书存储。subject
是证书的主题名称。allowInvalid
指示是否存在需要留意的无效证书,例如自签名证书。location
是从中加载证书的存储位置。serverCertificate
是 X.509 证书。
在生产中,必须显式配置 HTTPS。 至少必须提供默认证书。
下面要描述的支持的配置:
- 无配置
- 从配置中替换默认证书
- 更改代码中的默认值
无配置
Kestrel 在 http://localhost:5000
和 https://localhost:5001
上进行侦听(如果默认证书可用)。
从配置中替换默认证书
Kestrel 可以使用默认 HTTPS 应用设置配置架构。 从磁盘上的文件或从证书存储中配置多个终结点,包括要使用的 URL 和证书。
在以下 appsettings.json
示例中:
- 将
AllowInvalid
设置为true
,从而允许使用无效证书(例如自签名证书)。 - 任何未指定证书的 HTTPS 终结点(下例中的
HttpsDefaultCert
)会回退至在Certificates:Default
下定义的证书或开发证书。
{
"Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://localhost:5000"
},
"HttpsInlineCertFile": {
"Url": "https://localhost:5001",
"Certificate": {
"Path": "<path to .pfx file>",
"Password": "$CREDENTIAL_PLACEHOLDER$"
}
},
"HttpsInlineCertAndKeyFile": {
"Url": "https://localhost:5002",
"Certificate": {
"Path": "<path to .pem/.crt file>",
"KeyPath": "<path to .key file>",
"Password": "$CREDENTIAL_PLACEHOLDER$"
}
},
"HttpsInlineCertStore": {
"Url": "https://localhost:5003",
"Certificate": {
"Subject": "<subject; required>",
"Store": "<certificate store; required>",
"Location": "<location; defaults to CurrentUser>",
"AllowInvalid": "<true or false; defaults to false>"
}
},
"HttpsDefaultCert": {
"Url": "https://localhost:5004"
}
},
"Certificates": {
"Default": {
"Path": "<path to .pfx file>",
"Password": "$CREDENTIAL_PLACEHOLDER$"
}
}
}
}
警告
在上一示例中,证书密码以纯文本形式存储在 appsettings.json
中。 $CREDENTIAL_PLACEHOLDER$
令牌用作每个证书密码的占位符。 若要在开发环境中安全地存储证书密码,请参阅在开发过程中保护机密。 若要在生产环境中安全地存储证书密码,请参阅 Azure Key Vault 配置提供程序。 不应将开发机密用于生产或测试。
架构的注意事项:
- 终结点的名称不区分大小写。 例如,由于再也无法解析标识符“Families”,因此
HTTPS
andHttps
是等效的。 - 每个终结点都要具备
Url
参数。 此参数的格式和顶层Urls
配置参数一样,只不过它只能有单个值。 - 这些终结点不会添加进顶层
Urls
配置中定义的终结点,而是替换它们。 通过Listen
在代码中定义的终结点与在配置节中定义的终结点相累积。 Certificate
部分是可选的。 如果未指定Certificate
部分,则使用Certificates:Default
中定义的默认值。 如果没有可用的默认值,则使用开发证书。 如果没有默认值,且开发证书不存在,则服务器将引发异常,并且无法启动。Certificate
部分支持多个证书源。- 只要不会导致端口冲突,就能在配置中定义任何数量的终结点。
证书源
可以将证书节点配置为从多个源加载证书:
Path
和Password
用于加载 .pfx 文件。Path
、KeyPath
和Password
用于加载 .pem/.crt 和 .key 文件。Subject
和Store
用于从证书存储中加载。
例如,可将 Certificates:Default
证书指定为:
"Default": {
"Subject": "<subject; required>",
"Store": "<cert store; required>",
"Location": "<location; defaults to CurrentUser>",
"AllowInvalid": "<true or false; defaults to false>"
}
ConfigurationLoader
options.Configure(context.Configuration.GetSection("{SECTION}"))
通过 .Endpoint(string name, listenOptions => { })
方法返回 KestrelConfigurationLoader,可以用于补充已配置的终结点设置:
webBuilder.UseKestrel((context, serverOptions) =>
{
serverOptions.Configure(context.Configuration.GetSection("Kestrel"))
.Endpoint("HTTPS", listenOptions =>
{
listenOptions.HttpsOptions.SslProtocols = SslProtocols.Tls12;
});
});
可以直接访问 KestrelServerOptions.ConfigurationLoader
以继续迭代现有加载程序,例如由 CreateDefaultBuilder 提供的加载程序。
- 每个终结点的配置节都可用于
Endpoint
方法中的选项,以便读取自定义设置。 - 通过另一节再次调用
options.Configure(context.Configuration.GetSection("{SECTION}"))
可能加载多个配置。 只使用最新配置,除非之前的实例上显式调用了Load
。 元包不会调用Load
,所以可能会替换它的默认配置节。 KestrelConfigurationLoader
从KestrelServerOptions
将 API 的Listen
簇反射为Endpoint
重载,因此可在同样的位置配置代码和配置终结点。 这些重载不使用名称,且只使用配置中的默认设置。
更改代码中的默认值
可以使用 ConfigureEndpointDefaults
和 ConfigureHttpsDefaults
更改 ListenOptions
和 HttpsConnectionAdapterOptions
的默认设置,包括重写之前的方案指定的默认证书。 需要在配置任何终结点之前调用 ConfigureEndpointDefaults
和 ConfigureHttpsDefaults
。
webBuilder.ConfigureKestrel(serverOptions =>
{
serverOptions.ConfigureEndpointDefaults(listenOptions =>
{
// Configure endpoint defaults
});
serverOptions.ConfigureHttpsDefaults(listenOptions =>
{
listenOptions.SslProtocols = SslProtocols.Tls12;
});
});
使用服务器名称指示配置终结点
服务器名称指示 (SNI) 可用于承载相同 IP 地址和端口上的多个域。 为了运行 SNI,客户端在 TLS 握手过程中将进行安全会话的主机名发送至服务器,从而让服务器可以提供正确的证书。 在 TLS 握手后的安全会话期间,客户端将服务器提供的证书用于与服务器进行加密通信。
可用两种方式配置 SNI:
- 在代码中创建终结点,并通过 ServerCertificateSelector 回调使用主机名选择证书。
- 在配置中配置主机名和 HTTPS 选项之间的映射。 例如,
appsettings.json
文件中的 JSON。
具有 ServerCertificateSelector
的 SNI
Kestrel 通过 ServerCertificateSelector
回调支持 SNI。 每次连接调用一次回调,从而允许应用检查主机名并选择合适的证书。 可以在项目的 Program.cs
文件的 ConfigureWebHostDefaults
方法调用中使用以下回调代码:
// using System.Security.Cryptography.X509Certificates;
// using Microsoft.AspNetCore.Server.Kestrel.Https;
webBuilder.ConfigureKestrel(serverOptions =>
{
serverOptions.ListenAnyIP(5005, listenOptions =>
{
listenOptions.UseHttps(httpsOptions =>
{
var localhostCert = CertificateLoader.LoadFromStoreCert(
"localhost", "My", StoreLocation.CurrentUser,
allowInvalid: true);
var exampleCert = CertificateLoader.LoadFromStoreCert(
"example.com", "My", StoreLocation.CurrentUser,
allowInvalid: true);
var subExampleCert = CertificateLoader.LoadFromStoreCert(
"sub.example.com", "My", StoreLocation.CurrentUser,
allowInvalid: true);
var certs = new Dictionary<string, X509Certificate2>(StringComparer.OrdinalIgnoreCase)
{
{ "localhost", localhostCert },
{ "example.com", exampleCert },
{ "sub.example.com", subExampleCert },
};
httpsOptions.ServerCertificateSelector = (connectionContext, name) =>
{
if (name != null && certs.TryGetValue(name, out var cert))
{
return cert;
}
return exampleCert;
};
});
});
});
具有 ServerOptionsSelectionCallback
的 SNI
Kestrel 通过 ServerOptionsSelectionCallback
回调支持其他动态 TLS 配置。 每次连接调用一次回调,从而允许应用检查主机名并选择合适的证书和 TLS 配置。 默认证书和 ConfigureHttpsDefaults
不与此回调一起使用。
// using System.Security.Cryptography.X509Certificates;
// using Microsoft.AspNetCore.Server.Kestrel.Https;
webBuilder.ConfigureKestrel(serverOptions =>
{
serverOptions.ListenAnyIP(5005, listenOptions =>
{
listenOptions.UseHttps(httpsOptions =>
{
var localhostCert = CertificateLoader.LoadFromStoreCert(
"localhost", "My", StoreLocation.CurrentUser,
allowInvalid: true);
var exampleCert = CertificateLoader.LoadFromStoreCert(
"example.com", "My", StoreLocation.CurrentUser,
allowInvalid: true);
listenOptions.UseHttps((stream, clientHelloInfo, state, cancellationToken) =>
{
if (string.Equals(clientHelloInfo.ServerName, "localhost", StringComparison.OrdinalIgnoreCase))
{
return new ValueTask<SslServerAuthenticationOptions>(new SslServerAuthenticationOptions
{
ServerCertificate = localhostCert,
// Different TLS requirements for this host
ClientCertificateRequired = true,
});
}
return new ValueTask<SslServerAuthenticationOptions>(new SslServerAuthenticationOptions
{
ServerCertificate = exampleCert,
});
}, state: null);
});
});
});
配置中的 SNI
Kestrel 支持配置中定义的 SNI。 可以使用包含主机名和 HTTPS 选项之间的映射的 Sni
对象来配置终结点。 连接主机名与选项匹配,并且这些选项用于该连接。
以下配置将添加一个名为 MySniEndpoint
的终结点,该终结点使用 SNI 基于主机名选择 HTTPS 选项:
{
"Kestrel": {
"Endpoints": {
"MySniEndpoint": {
"Url": "https://*",
"SslProtocols": ["Tls11", "Tls12"],
"Sni": {
"a.example.org": {
"Protocols": "Http1AndHttp2",
"SslProtocols": ["Tls11", "Tls12", "Tls13"],
"Certificate": {
"Subject": "<subject; required>",
"Store": "<certificate store; required>",
},
"ClientCertificateMode" : "NoCertificate"
},
"*.example.org": {
"Certificate": {
"Path": "<path to .pfx file>",
"Password": "$CREDENTIAL_PLACEHOLDER$"
}
},
"*": {
// At least one subproperty needs to exist per SNI section or it
// cannot be discovered via IConfiguration
"Protocols": "Http1",
}
}
}
},
"Certificates": {
"Default": {
"Path": "<path to .pfx file>",
"Password": "$CREDENTIAL_PLACEHOLDER$"
}
}
}
}
警告
在上一示例中,证书密码以纯文本形式存储在 appsettings.json
中。 $CREDENTIAL_PLACEHOLDER$
令牌用作每个证书密码的占位符。 若要在开发环境中安全地存储证书密码,请参阅在开发过程中保护机密。 若要在生产环境中安全地存储证书密码,请参阅 Azure Key Vault 配置提供程序。 不应将开发机密用于生产或测试。
可由 SNI 覆盖的 HTTPS 选项:
Certificate
配置证书源。Protocols
配置允许的 HTTP 协议。SslProtocols
配置允许的 SSL 协议。ClientCertificateMode
配置客户端证书要求。
主机名支持通配符匹配:
- 完全匹配。 例如,
a.example.org
匹配a.example.org
。 - 通配符前缀。 如果有多个通配符匹配项,则选择最长的模式。 例如,
*.example.org
匹配b.example.org
和c.example.org
。 - 完整通配符。
*
匹配其他所有内容,包括不使用 SNI 且不发送主机名的客户端。
匹配的 SNI 配置将应用于连接的终结点,并重写终结点上的值。 如果连接与已配置的 SNI 主机名不匹配,则连接将被拒绝。
SNI 要求
- 在目标框架
netcoreapp2.1
或更高版本上运行。 在net461
或最高版本上,将调用回调,但是name
始终为null
。 如果客户端未在 TLS 握手过程中提供主机名参数,则name
也为null
。 - 所有网站在相同的 Kestrel 实例上运行。 Kestrel 在无反向代理时不支持跨多个实例共享一个 IP 地址和端口。
SSL/TLS 协议
SSL 协议是用于在两个对等机(传统上是客户端和服务器)之间加密和解密流量的协议。
webBuilder.ConfigureKestrel(serverOptions =>
{
serverOptions.ConfigureHttpsDefaults(listenOptions =>
{
listenOptions.SslProtocols = SslProtocols.Tls13;
});
});
{
"Kestrel": {
"Endpoints": {
"MyHttpsEndpoint": {
"Url": "https://localhost:5001",
"SslProtocols": ["Tls12", "Tls13"],
"Certificate": {
"Path": "<path to .pfx file>",
"Password": "$CREDENTIAL_PLACEHOLDER$"
}
}
}
}
}
警告
在上一示例中,证书密码以纯文本形式存储在 appsettings.json
中。 $CREDENTIAL_PLACEHOLDER$
令牌用作证书密码的占位符。 若要在开发环境中安全地存储证书密码,请参阅在开发过程中保护机密。 若要在生产环境中安全地存储证书密码,请参阅 Azure Key Vault 配置提供程序。 不应将开发机密用于生产或测试。
默认值 SslProtocols.None
会导致 Kestrel 使用操作系统默认值来选择最佳协议。 除非你有特定原因要选择协议,否则请使用默认值。
客户端证书
ClientCertificateMode
配置客户端证书要求。
webBuilder.ConfigureKestrel(serverOptions =>
{
serverOptions.ConfigureHttpsDefaults(listenOptions =>
{
listenOptions.ClientCertificateMode = ClientCertificateMode.AllowCertificate;
});
});
{
"Kestrel": {
"Endpoints": {
"MyHttpsEndpoint": {
"Url": "https://localhost:5001",
"ClientCertificateMode": "AllowCertificate",
"Certificate": {
"Path": "<path to .pfx file>",
"Password": "$CREDENTIAL_PLACEHOLDER$"
}
}
}
}
}
警告
在上一示例中,证书密码以纯文本形式存储在 appsettings.json
中。 $CREDENTIAL_PLACEHOLDER$
令牌用作证书密码的占位符。 若要在开发环境中安全地存储证书密码,请参阅在开发过程中保护机密。 若要在生产环境中安全地存储证书密码,请参阅 Azure Key Vault 配置提供程序。 不应将开发机密用于生产或测试。
默认值为 ClientCertificateMode.NoCertificate
,其中 Kestrel 不会从客户端请求或要求证书。
有关详细信息,请参阅在 ASP.NET Core 中配置证书身份验证。
连接日志记录
调用 UseConnectionLogging 以发出用于进行连接上的字节级别通信的调试级别日志。 连接日志记录有助于排查低级通信中的问题,例如在 TLS 加密期间和代理后。 如果 UseConnectionLogging
放置在 UseHttps
之前,则会记录加密的流量。 如果 UseConnectionLogging
放置于 UseHttps
之后,则会记录解密的流量。 这是内置连接中间件。
webBuilder.ConfigureKestrel(serverOptions =>
{
serverOptions.Listen(IPAddress.Any, 8000, listenOptions =>
{
listenOptions.UseConnectionLogging();
});
});
绑定到 TCP 套接字
Listen 方法绑定至 TCP 套接字,且 options lambda 允许 X.509 证书配置:
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.ConfigureKestrel(serverOptions =>
{
serverOptions.Listen(IPAddress.Loopback, 5000);
serverOptions.Listen(IPAddress.Loopback, 5001,
listenOptions =>
{
listenOptions.UseHttps("testCert.pfx",
"testPassword");
});
})
.UseStartup<Startup>();
});
示例使用 ListenOptions 为终结点配置 HTTPS。 可使用相同 API 为特定终结点配置其他 Kestrel 设置。
在 Windows 上,可以使用 New-SelfSignedCertificate
PowerShell cmdlet 创建自签名证书。 有关不受支持的示例,请参阅 UpdateIISExpressSSLForChrome.ps1
。
在 macOS、Linux 和 Windows 上,可以使用 OpenSSL 创建证书。
绑定到 Unix 套接字
可通过 ListenUnixSocket 侦听 Unix 套接字以提高 Nginx 的性能,如以下示例所示:
webBuilder.ConfigureKestrel(serverOptions =>
{
serverOptions.ListenUnixSocket("/tmp/kestrel-test.sock");
serverOptions.ListenUnixSocket("/tmp/kestrel-test.sock",
listenOptions =>
{
listenOptions.UseHttps("testCert.pfx",
"testpassword");
});
})
- 在 Nginx 配置文件中,将
server
>location
>proxy_pass
条目设置为http://unix:/tmp/{KESTREL SOCKET}:/;
。{KESTREL SOCKET}
是提供给 ListenUnixSocket 的套接字的名称(例如,上述示例中的kestrel-test.sock
)。 - 确保套接字可由 Nginx (例如
chmod go+w /tmp/kestrel-test.sock
)进行写入。
端口 0
如果指定端口号 0
,Kestrel 将动态绑定到可用端口。 以下示例演示如何确定 Kestrel 在运行时绑定到的端口:
public void Configure(IApplicationBuilder app)
{
var serverAddressesFeature =
app.ServerFeatures.Get<IServerAddressesFeature>();
app.UseStaticFiles();
app.Run(async (context) =>
{
context.Response.ContentType = "text/html";
await context.Response
.WriteAsync("<!DOCTYPE html><html lang=\"en\"><head>" +
"<title></title></head><body><p>Hosted by Kestrel</p>");
if (serverAddressesFeature != null)
{
await context.Response
.WriteAsync("<p>Listening on the following addresses: " +
string.Join(", ", serverAddressesFeature.Addresses) +
"</p>");
}
await context.Response.WriteAsync("<p>Request URL: " +
$"{context.Request.GetDisplayUrl()}<p>");
});
}
在应用运行时,控制台窗口输出指示可用于访问应用的动态端口:
Listening on the following addresses: http://127.0.0.1:48508
限制
使用以下方法配置终结点:
- UseUrls
--urls
命令行参数urls
主机配置键ASPNETCORE_URLS
环境变量
若要将代码用于 Kestrel 以外的服务器,这些方法非常有用。 不过,请注意以下限制:
- HTTPS 无法与这些方法结合使用,除非在 HTTPS 终结点配置中提供了默认证书(例如,使用
KestrelServerOptions
配置或配置文件,如本文前面的部分所示)。 - 如果同时使用
Listen
和UseUrls
方法,Listen
终结点将覆盖UseUrls
终结点。
IIS 终结点配置
使用 IIS 时,由 Listen
或 UseUrls
设置用于 IIS 覆盖绑定的 URL 绑定。 有关详细信息,请参阅 ASP.NET Core 模块。
ListenOptions.Protocols
Protocols
属性建立在连接终结点上或为服务器启用的 HTTP 协议(HttpProtocols
)。 从 HttpProtocols
枚举向 Protocols
属性赋值。
HttpProtocols 枚举值 |
允许的连接协议 |
---|---|
Http1 |
仅 HTTP/1.1。 可以在具有 TLS 或没有 TLS 的情况下使用。 |
Http2 |
仅 HTTP/2。 仅当客户端支持先验知识模式时,才可以在没有 TLS 的情况下使用。 |
Http1AndHttp2 |
HTTP/1.1 和 HTTP/2。 HTTP/2 要求客户端在 TLS 应用层协议协商 (ALPN) 握手过程中选择 HTTP/2;否则,连接默认为 HTTP/1.1。 |
任何终结点的默认 ListenOptions.Protocols
值都为 HttpProtocols.Http1AndHttp2
。
HTTP/2 的 TLS 限制:
- TLS 版本 1.2 或更高版本
- 重新协商已禁用
- 压缩已禁用
- 最小的临时密钥交换大小:
- 椭圆曲线 Diffie-Hellman (ECDHE) [RFC4492]:最小 224 位
- 有限字段 Diffie-Hellman (DHE) [
TLS12
]:最小 2048 位
- 不禁止密码套件。
默认情况下,支持具有 P-256 椭圆曲线 [FIPS186
] 的 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
[TLS-ECDHE
]。
以下示例允许端口 8000 上的 HTTP/1.1 和 HTTP/2 连接。 TLS 使用提供的证书来保护连接:
webBuilder.ConfigureKestrel(serverOptions =>
{
serverOptions.Listen(IPAddress.Any, 8000, listenOptions =>
{
listenOptions.UseHttps("testCert.pfx", "testPassword");
});
});
在 Linux 上,CipherSuitesPolicy 可用于针对每个连接筛选 TLS 握手:
// using System.Net.Security;
// using Microsoft.AspNetCore.Hosting;
// using Microsoft.AspNetCore.Server.Kestrel.Core;
// using Microsoft.Extensions.DependencyInjection;
// using Microsoft.Extensions.Hosting;
webBuilder.ConfigureKestrel(serverOptions =>
{
serverOptions.ConfigureHttpsDefaults(listenOptions =>
{
listenOptions.OnAuthenticate = (context, sslOptions) =>
{
sslOptions.CipherSuitesPolicy = new CipherSuitesPolicy(
new[]
{
TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
TlsCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
// ...
});
};
});
});
连接中间件
必要时,自定义连接中间件可以按连接为特定密码筛选 TLS 握手。
下面的示例针对应用不支持的任何密码算法引发 NotSupportedException。 或者,定义 ITlsHandshakeFeature.CipherAlgorithm 并将其与可接受的密码套件列表进行比较。
没有哪种加密是使用 CipherAlgorithmType.Null 密码算法。
// using System.Net;
// using Microsoft.AspNetCore.Connections;
webBuilder.ConfigureKestrel(serverOptions =>
{
serverOptions.Listen(IPAddress.Any, 8000, listenOptions =>
{
listenOptions.UseHttps("testCert.pfx", "testPassword");
listenOptions.UseTlsFilter();
});
});
using System;
using System.Security.Authentication;
using Microsoft.AspNetCore.Connections.Features;
namespace Microsoft.AspNetCore.Connections
{
public static class TlsFilterConnectionMiddlewareExtensions
{
public static IConnectionBuilder UseTlsFilter(
this IConnectionBuilder builder)
{
return builder.Use((connection, next) =>
{
var tlsFeature = connection.Features.Get<ITlsHandshakeFeature>();
if (tlsFeature.CipherAlgorithm == CipherAlgorithmType.Null)
{
throw new NotSupportedException("Prohibited cipher: " +
tlsFeature.CipherAlgorithm);
}
return next();
});
}
}
}
连接筛选也可以通过 IConnectionBuilder lambda 进行配置:
// using System;
// using System.Net;
// using System.Security.Authentication;
// using Microsoft.AspNetCore.Connections;
// using Microsoft.AspNetCore.Connections.Features;
webBuilder.ConfigureKestrel(serverOptions =>
{
serverOptions.Listen(IPAddress.Any, 8000, listenOptions =>
{
listenOptions.UseHttps("testCert.pfx", "testPassword");
listenOptions.Use((context, next) =>
{
var tlsFeature = context.Features.Get<ITlsHandshakeFeature>();
if (tlsFeature.CipherAlgorithm == CipherAlgorithmType.Null)
{
throw new NotSupportedException(
$"Prohibited cipher: {tlsFeature.CipherAlgorithm}");
}
return next();
});
});
});
从配置中设置 HTTP 协议
CreateDefaultBuilder
在默认情况下调用 serverOptions.Configure(context.Configuration.GetSection("Kestrel"))
来加载 Kestrel 配置。
以下 appsettings.json
示例将 HTTP/1.1 建立为所有终结点的默认连接协议:
{
"Kestrel": {
"EndpointDefaults": {
"Protocols": "Http1"
}
}
}
以下 appsettings.json
示例将为所有指定终结点建立 HTTP/1.1 连接协议:
{
"Kestrel": {
"Endpoints": {
"HttpsDefaultCert": {
"Url": "https://localhost:5001",
"Protocols": "Http1"
}
}
}
}
代码中指定的协议覆盖了由配置设置的值。
URL 前缀
如果使用 UseUrls
、--urls
命令行参数、urls
主机配置键或 ASPNETCORE_URLS
环境变量,URL 前缀可采用以下任意格式。
仅 HTTP URL 前缀是有效的。 使用 UseUrls
配置 URL 绑定时,Kestrel 不支持 HTTPS。
包含端口号的 IPv4 地址
http://65.55.39.10:80/
0.0.0.0
是一种绑定到所有 IPv4 地址的特殊情况。包含端口号的 IPv6 地址
http://[0:0:0:0:0:ffff:4137:270a]:80/
[::]
是 IPv40.0.0.0
的 IPv6 等效项。包含端口号的主机名
http://contoso.com:80/ http://*:80/
主机名、
*
和+
并不特殊。 没有识别为有效 IP 地址或localhost
的任何内容都将绑定到所有 IPv4 和 IPv6 IP。 若要将不同主机名绑定到相同端口上的不同 ASP.NET Core 应用,请使用 HTTP.sys 或反向代理服务器。 反向代理服务器示例包括 IIS、Nginx 或 Apache。警告
采用反向代理配置进行托管需要主机筛选。
包含端口号的主机
localhost
名称或包含端口号的环回 IPhttp://localhost:5000/ http://127.0.0.1:5000/ http://[::1]:5000/
指定
localhost
后,Kestrel 将尝试绑定到 IPv4 和 IPv6 环回接口。 如果其他服务正在任一环回接口上使用请求的端口,则 Kestrel 将无法启动。 如果任一环回接口出于任何其他原因(通常是因为 IPv6 不受支持)而不可用,则 Kestrel 将记录一个警告。