ASP.net 和 C# 中是否需要中间件重定向到 HTTPS?
Is middleware neeeded to redirect to HTTPS in ASP.net and C#?
将所有不安全的传入请求重定向到 HTTPS 的推荐方法是什么。我需要写一个中间件组件吗?如果是这样,我不知道如何获取服务器名称。
public class RedirectHttpMiddleware
{
RequestDelegate _next;
public RedirectHttpMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
if (context.Request.IsSecure)
await _next(context);
else
{
var server = ""; // How do I get the server name?
context.Response.Redirect("https://" + server + context.Request.Path);
}
}
}
您可以使用自己的中间件 class,但通常我只是在我的启动配置中做这样的事情:
app.Use(async (context, next) =>
{
if (context.Request.IsHttps)
{
await next();
}
else
{
var withHttps = Uri.UriSchemeHttps + Uri.SchemeDelimiter + context.Request.Uri.GetComponents(UriComponents.AbsoluteUri & ~UriComponents.Scheme, UriFormat.SafeUnescaped);
context.Response.Redirect(withHttps);
}
});
它所做的只是抓取整个 URL、查询字符串和所有内容,然后使用 GetComponents
获取所有 除了 [中的方案=25=]。然后 HTTPS 方案被添加到组件 URL.
之前
这将适用于完整的 .NET Framework,对于 ASP.NET Core,您可以这样做:
app.Use(async (context, next) =>
{
if (context.Request.IsHttps)
{
await next();
}
else
{
var withHttps = "https://" + context.Request.Host + context.Request.Path;
context.Response.Redirect(withHttps);
}
});
这会将主机和路径附加到 HTTPS 方案。您可能还想添加其他组件,例如查询和哈希。
对于 .NET Core 2.0 及更低版本 (official docs for 2.0):
使用[RequireHttps]
attribute/filter。
您可以对您的控制器执行此操作:
[RequireHttps]
public class AccountController {
}
或者在 ConfigureServices
方法的 Startup.cs
中添加:
services.Configure<MvcOptions>(options =>
{
options.Filters.Add(new RequireHttpsAttribute());
}
此外,我只是想补充一点,vcsjones 的回答也是正确的,但是您需要确保在您的配置中尽早添加此代码,然后再 Middleware/code导致重定向。就我而言,我在添加身份框架中间件之前添加了它。
如果您想在 .NET Core 的 DEV 环境中获取端口,请查看 env.IsDevelopment()
并有条件地从 launchSettings.json
.
获取 SSL 端口
if (env.IsDevelopment())
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile(@"Properties/launchSettings.json", optional: false, reloadOnChange: true);
var launchConfig = builder.Build();
sslPort = launchConfig.GetValue<int>("iisSettings:iisExpress:sslPort");
}
`
获取SSL端口后,就可以将端口合并到@vcsjones发布的解决方案中。
完整答案在第 1 条中,但不要就此停止设置 HTTPS,执行额外的步骤:
1 - 然后我们使用 RequireHttpsAttribute
重定向到 HTTPS 并在 MVC 选项中设置 SSL 端口。我们也在从 launchSettings.json 读取 SSL 端口,但我们只在开发模式下需要它。
2 - 使用 AddAntiforgery
要求在您的防伪令牌上使用 HTTPS。
3 - 使用 NWebsec.AspNetCore.Middleware
NuGet 包和 UseHsts
方法在整个站点启用严格传输安全 (HSTS)。不要忘记在下面添加 Preload 并将您的站点提交到 HSTS Preload site. More information here and here.
4 - 使用 NWebsec.AspNetCore.Middleware
NuGet 包和 UseHpkp
方法在整个站点启用 Public 键固定 (HPKP)。请注意,如果您在这个问题上犯了一个错误,那么您实际上是在对您的网站进行 DoS 攻击。更多信息 here and here.
5 - 在使用的任何 URL 中包含 https 方案。 Content Security Policy (CSP) HTTP header and Subresource Integrity (SRI)在某些浏览器中模仿该方案时不要玩得很好。最好明确说明 HTTPS。例如
<script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.4/bootstrap.min.js"></script>
6- 使用 ASP.NET MVC Boilerplate Visual Studio project template to generate a project with all of this and much more built in. You can also view the code on GitHub.
完成上述所有操作后,您的 Startup
class 应该如下所示:
public class Startup
{
private readonly int? sslPort;
public Startup(IHostingEnvironment hostingEnvironment)
{
if (hostingEnvironment.IsDevelopment())
{
var launchConfiguration = new ConfigurationBuilder()
.SetBasePath(hostingEnvironment.ContentRootPath)
.AddJsonFile(@"Properties\launchSettings.json")
.Build();
// During development we won't be using port 443.
this.sslPort = launchConfiguration.GetValue<int>("iisSettings:iisExpress:sslPort");
}
}
public void ConfigureServices(IServiceCollection services)
{
services
.AddAntiforgery(options =>
{
options.RequireSsl = true;
});
.AddMvc(options =>
{
options.Filters.Add(new RequireHttpsAttribute());
options.SslPort = sslPort;
});
}
public void Configure(IApplicationBuilder application)
{
application
.UseHsts(options => options.MaxAge(days: 18 * 7).IncludeSubdomains().Preload())
.UseHpkp(options => options
.Sha256Pins(
"Base64 encoded SHA-256 hash of your first certificate e.g. cUPcTAZWKaASuYWhhneDttWpY3oBAkE3h2+soZS7sWs=",
"Base64 encoded SHA-256 hash of your second backup certificate e.g. M8HztCzM3elUxkcjR2S5P4hhyBNf6lHkmjAHKhpGPWE=")
.MaxAge(days: 18 * 7)
.IncludeSubdomains())
.UseCsp(options => options
.UpgradeInsecureRequests(this.sslPort.HasValue ? this.sslPort.Value : 443))
.UseMvc();
}
}
我修改了一些@vcsjones 的回答以在开发环境中使用自定义端口。也归功于@long2know。
app.Use(async (context, next) =>
{
var request = context.Request;
if (request.IsHttps)
{
await next();
}
else
{
var devPort = Configuration.GetValue<int>("iisSettings:iisExpress:sslPort");
var host = env.IsDevelopment() && devPort > 0
? new HostString(request.Host.Host, devPort)
: new HostString(request.Host.Host);
string newUrl = $"https://{host}{request.PathBase}{request.Path}{request.QueryString}";
context.Response.Redirect(newUrl, true);
}
});
这必须出现在app.UseStaticFiles或app.UseMvc之前,否则将被忽略。
请注意,端口应取自 launchSettings.json
文件,因此您还应将此文件添加到 Startup.cs
:
中的 ConfigurationBuilder
.AddJsonFile(@"Properties/launchSettings.json", optional: false, reloadOnChange: true)
AlwaysHttpsMiddleware.cs, inspired by RequiresHttpsAttribute.
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
public class AlwaysHttpsMiddleware
{
private readonly RequestDelegate _next;
public AlwaysHttpsMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
if (context.Request.IsHttps)
{
await _next.Invoke(context);
}
else
{
var request = context.Request;
// only redirect for GET requests, otherwise the browser might
// not propagate the verb and request body correctly.
if (!string.Equals(request.Method, "GET", StringComparison.OrdinalIgnoreCase))
{
context.Response.StatusCode = StatusCodes.Status403Forbidden;
await context.Response.WriteAsync("This site requires HTTPS.");
}
else
{
var newUrl = string.Concat(
"https://",
request.Host.ToUriComponent(),
request.PathBase.ToUriComponent(),
request.Path.ToUriComponent(),
request.QueryString.ToUriComponent());
context.Response.Redirect(newUrl);
}
}
}
}
Startup.cs
public void Configure(IApplicationBuilder app)
{
if (_env.IsProduction())
{
app.UseMiddleware<AlwaysHttpsMiddleware>();
}
}
这里有一些很好的答案,但我需要一个可以使用或不使用 IIS 并且在本地调试期间不更改协议的解决方案。我在 Startup.Configure 方法中将 AD 身份验证添加到管道后添加了它。这是针对完整框架的。此处的其他解决方案概述了如何为 Core 重建 URL。
app.Use(async (context, next) =>
{
if (context.Request.IsHttps || // Handles https straight to the server
context.Request.Headers["X-Forwarded-Proto"] == Uri.UriSchemeHttps || // Handles an IIS or Azure passthrough
context.Request.Host.ToString().StartsWith("localhost",true, System.Globalization.CultureInfo.InvariantCulture) || // Ignore for localhost
context.Request.Headers["X-Forwarded-Proto"].Contains( Uri.UriSchemeHttps )) // X-Forwarded-Proto can have multiple values if there are multiple proxies
{
await next();
}
else
{
var withHttps = Uri.UriSchemeHttps + Uri.SchemeDelimiter + context.Request.Host + context.Request.Path + context.Request.QueryString;
context.Response.Redirect(withHttps);
}
});
为了让您的 DOTNet Core 应用程序在 HTTPS 下 运行,需要遵循三个步骤:
- 导航到您的应用程序的 launchSettings.json 文件并输入所需的 https 端口 44390-44399
编辑您的 Startup.cs 文件。输入以下代码:
services.Configure<MvcOptions>(options =>
{
options.SslPort = 44390;
options.Filters.Add(new RequireHttpsAttribute());
});
Right-Click 在您的项目根目录中,来自解决方案资源管理器和 Select 属性。选中启用 SSL,复制 SSL link 并将其添加到 App URL 区域。
- 启动应用程序。在 HTTPS 上下文下它将始终 运行。
https://github.com/aspnet/KestrelHttpServer/issues/916 中讨论的一项技术是将其添加到您的 web.config:
<rewrite>
<rules>
<rule name="HTTP/S to HTTPS Redirect" enabled="true" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAny">
<add input="{SERVER_PORT_SECURE}" pattern="^0$" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" />
</rule>
</rules>
</rewrite>
我喜欢带有编译器指令的属性
#if !DEBUG
[RequireHttps]
#endif
public class HomeController : Controller
{
}
在 ASP.NET Core 2.1 中只使用这个:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts(); // <-- Add this !!!!!
}
app.UseHttpsRedirection(); // <-- Add this !!!!!
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc();
}
如果您需要在 .net 核心项目中从 http:// 永久重定向到 https://,只需将此代码添加到 Startup.cs
app.UseHttpsRedirection();
将所有不安全的传入请求重定向到 HTTPS 的推荐方法是什么。我需要写一个中间件组件吗?如果是这样,我不知道如何获取服务器名称。
public class RedirectHttpMiddleware
{
RequestDelegate _next;
public RedirectHttpMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
if (context.Request.IsSecure)
await _next(context);
else
{
var server = ""; // How do I get the server name?
context.Response.Redirect("https://" + server + context.Request.Path);
}
}
}
您可以使用自己的中间件 class,但通常我只是在我的启动配置中做这样的事情:
app.Use(async (context, next) =>
{
if (context.Request.IsHttps)
{
await next();
}
else
{
var withHttps = Uri.UriSchemeHttps + Uri.SchemeDelimiter + context.Request.Uri.GetComponents(UriComponents.AbsoluteUri & ~UriComponents.Scheme, UriFormat.SafeUnescaped);
context.Response.Redirect(withHttps);
}
});
它所做的只是抓取整个 URL、查询字符串和所有内容,然后使用 GetComponents
获取所有 除了 [中的方案=25=]。然后 HTTPS 方案被添加到组件 URL.
这将适用于完整的 .NET Framework,对于 ASP.NET Core,您可以这样做:
app.Use(async (context, next) =>
{
if (context.Request.IsHttps)
{
await next();
}
else
{
var withHttps = "https://" + context.Request.Host + context.Request.Path;
context.Response.Redirect(withHttps);
}
});
这会将主机和路径附加到 HTTPS 方案。您可能还想添加其他组件,例如查询和哈希。
对于 .NET Core 2.0 及更低版本 (official docs for 2.0):
使用[RequireHttps]
attribute/filter。
您可以对您的控制器执行此操作:
[RequireHttps]
public class AccountController {
}
或者在 ConfigureServices
方法的 Startup.cs
中添加:
services.Configure<MvcOptions>(options =>
{
options.Filters.Add(new RequireHttpsAttribute());
}
此外,我只是想补充一点,vcsjones 的回答也是正确的,但是您需要确保在您的配置中尽早添加此代码,然后再 Middleware/code导致重定向。就我而言,我在添加身份框架中间件之前添加了它。
如果您想在 .NET Core 的 DEV 环境中获取端口,请查看 env.IsDevelopment()
并有条件地从 launchSettings.json
.
if (env.IsDevelopment())
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile(@"Properties/launchSettings.json", optional: false, reloadOnChange: true);
var launchConfig = builder.Build();
sslPort = launchConfig.GetValue<int>("iisSettings:iisExpress:sslPort");
}
`
获取SSL端口后,就可以将端口合并到@vcsjones发布的解决方案中。
完整答案在第 1 条中,但不要就此停止设置 HTTPS,执行额外的步骤:
1 - 然后我们使用 RequireHttpsAttribute
重定向到 HTTPS 并在 MVC 选项中设置 SSL 端口。我们也在从 launchSettings.json 读取 SSL 端口,但我们只在开发模式下需要它。
2 - 使用 AddAntiforgery
要求在您的防伪令牌上使用 HTTPS。
3 - 使用 NWebsec.AspNetCore.Middleware
NuGet 包和 UseHsts
方法在整个站点启用严格传输安全 (HSTS)。不要忘记在下面添加 Preload 并将您的站点提交到 HSTS Preload site. More information here and here.
4 - 使用 NWebsec.AspNetCore.Middleware
NuGet 包和 UseHpkp
方法在整个站点启用 Public 键固定 (HPKP)。请注意,如果您在这个问题上犯了一个错误,那么您实际上是在对您的网站进行 DoS 攻击。更多信息 here and here.
5 - 在使用的任何 URL 中包含 https 方案。 Content Security Policy (CSP) HTTP header and Subresource Integrity (SRI)在某些浏览器中模仿该方案时不要玩得很好。最好明确说明 HTTPS。例如
<script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.4/bootstrap.min.js"></script>
6- 使用 ASP.NET MVC Boilerplate Visual Studio project template to generate a project with all of this and much more built in. You can also view the code on GitHub.
完成上述所有操作后,您的 Startup
class 应该如下所示:
public class Startup
{
private readonly int? sslPort;
public Startup(IHostingEnvironment hostingEnvironment)
{
if (hostingEnvironment.IsDevelopment())
{
var launchConfiguration = new ConfigurationBuilder()
.SetBasePath(hostingEnvironment.ContentRootPath)
.AddJsonFile(@"Properties\launchSettings.json")
.Build();
// During development we won't be using port 443.
this.sslPort = launchConfiguration.GetValue<int>("iisSettings:iisExpress:sslPort");
}
}
public void ConfigureServices(IServiceCollection services)
{
services
.AddAntiforgery(options =>
{
options.RequireSsl = true;
});
.AddMvc(options =>
{
options.Filters.Add(new RequireHttpsAttribute());
options.SslPort = sslPort;
});
}
public void Configure(IApplicationBuilder application)
{
application
.UseHsts(options => options.MaxAge(days: 18 * 7).IncludeSubdomains().Preload())
.UseHpkp(options => options
.Sha256Pins(
"Base64 encoded SHA-256 hash of your first certificate e.g. cUPcTAZWKaASuYWhhneDttWpY3oBAkE3h2+soZS7sWs=",
"Base64 encoded SHA-256 hash of your second backup certificate e.g. M8HztCzM3elUxkcjR2S5P4hhyBNf6lHkmjAHKhpGPWE=")
.MaxAge(days: 18 * 7)
.IncludeSubdomains())
.UseCsp(options => options
.UpgradeInsecureRequests(this.sslPort.HasValue ? this.sslPort.Value : 443))
.UseMvc();
}
}
我修改了一些@vcsjones 的回答以在开发环境中使用自定义端口。也归功于@long2know。
app.Use(async (context, next) =>
{
var request = context.Request;
if (request.IsHttps)
{
await next();
}
else
{
var devPort = Configuration.GetValue<int>("iisSettings:iisExpress:sslPort");
var host = env.IsDevelopment() && devPort > 0
? new HostString(request.Host.Host, devPort)
: new HostString(request.Host.Host);
string newUrl = $"https://{host}{request.PathBase}{request.Path}{request.QueryString}";
context.Response.Redirect(newUrl, true);
}
});
这必须出现在app.UseStaticFiles或app.UseMvc之前,否则将被忽略。
请注意,端口应取自 launchSettings.json
文件,因此您还应将此文件添加到 Startup.cs
:
ConfigurationBuilder
.AddJsonFile(@"Properties/launchSettings.json", optional: false, reloadOnChange: true)
AlwaysHttpsMiddleware.cs, inspired by RequiresHttpsAttribute.
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
public class AlwaysHttpsMiddleware
{
private readonly RequestDelegate _next;
public AlwaysHttpsMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
if (context.Request.IsHttps)
{
await _next.Invoke(context);
}
else
{
var request = context.Request;
// only redirect for GET requests, otherwise the browser might
// not propagate the verb and request body correctly.
if (!string.Equals(request.Method, "GET", StringComparison.OrdinalIgnoreCase))
{
context.Response.StatusCode = StatusCodes.Status403Forbidden;
await context.Response.WriteAsync("This site requires HTTPS.");
}
else
{
var newUrl = string.Concat(
"https://",
request.Host.ToUriComponent(),
request.PathBase.ToUriComponent(),
request.Path.ToUriComponent(),
request.QueryString.ToUriComponent());
context.Response.Redirect(newUrl);
}
}
}
}
Startup.cs
public void Configure(IApplicationBuilder app)
{
if (_env.IsProduction())
{
app.UseMiddleware<AlwaysHttpsMiddleware>();
}
}
这里有一些很好的答案,但我需要一个可以使用或不使用 IIS 并且在本地调试期间不更改协议的解决方案。我在 Startup.Configure 方法中将 AD 身份验证添加到管道后添加了它。这是针对完整框架的。此处的其他解决方案概述了如何为 Core 重建 URL。
app.Use(async (context, next) =>
{
if (context.Request.IsHttps || // Handles https straight to the server
context.Request.Headers["X-Forwarded-Proto"] == Uri.UriSchemeHttps || // Handles an IIS or Azure passthrough
context.Request.Host.ToString().StartsWith("localhost",true, System.Globalization.CultureInfo.InvariantCulture) || // Ignore for localhost
context.Request.Headers["X-Forwarded-Proto"].Contains( Uri.UriSchemeHttps )) // X-Forwarded-Proto can have multiple values if there are multiple proxies
{
await next();
}
else
{
var withHttps = Uri.UriSchemeHttps + Uri.SchemeDelimiter + context.Request.Host + context.Request.Path + context.Request.QueryString;
context.Response.Redirect(withHttps);
}
});
为了让您的 DOTNet Core 应用程序在 HTTPS 下 运行,需要遵循三个步骤:
- 导航到您的应用程序的 launchSettings.json 文件并输入所需的 https 端口 44390-44399
编辑您的 Startup.cs 文件。输入以下代码:
services.Configure<MvcOptions>(options => { options.SslPort = 44390; options.Filters.Add(new RequireHttpsAttribute()); });
Right-Click 在您的项目根目录中,来自解决方案资源管理器和 Select 属性。选中启用 SSL,复制 SSL link 并将其添加到 App URL 区域。
- 启动应用程序。在 HTTPS 上下文下它将始终 运行。
https://github.com/aspnet/KestrelHttpServer/issues/916 中讨论的一项技术是将其添加到您的 web.config:
<rewrite>
<rules>
<rule name="HTTP/S to HTTPS Redirect" enabled="true" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAny">
<add input="{SERVER_PORT_SECURE}" pattern="^0$" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" />
</rule>
</rules>
</rewrite>
我喜欢带有编译器指令的属性
#if !DEBUG
[RequireHttps]
#endif
public class HomeController : Controller
{
}
在 ASP.NET Core 2.1 中只使用这个:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts(); // <-- Add this !!!!!
}
app.UseHttpsRedirection(); // <-- Add this !!!!!
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc();
}
如果您需要在 .net 核心项目中从 http:// 永久重定向到 https://,只需将此代码添加到 Startup.cs
app.UseHttpsRedirection();