-
Notifications
You must be signed in to change notification settings - Fork 84
Adds Https Redirection and Hsts Middlewares #264
Changes from 4 commits
d9f364d
18d6c96
9d3c8b2
4d27202
4a9495e
e9a1f5a
82401ac
e38ac6e
8c11086
a588a98
3aa120c
f72cb24
a704d29
23412eb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<Project Sdk="Microsoft.NET.Sdk.Web"> | ||
|
||
<PropertyGroup> | ||
<TargetFrameworks>net461;netcoreapp2.0</TargetFrameworks> | ||
<TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">netcoreapp2.0</TargetFrameworks> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" /> | ||
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Https" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.HttpsPolicy\Microsoft.AspNetCore.HttpsPolicy.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
{ | ||
"iisSettings": { | ||
"windowsAuthentication": false, | ||
"anonymousAuthentication": true, | ||
"iisExpress": { | ||
"applicationUrl": "http://localhost:31894/", | ||
"sslPort": 0 | ||
} | ||
}, | ||
"profiles": { | ||
"IIS Express": { | ||
"commandName": "IISExpress", | ||
"launchBrowser": true, | ||
"environmentVariables": { | ||
"ASPNETCORE_ENVIRONMENT": "Development" | ||
} | ||
}, | ||
"HttpsSample": { | ||
"commandName": "Project", | ||
"launchBrowser": true, | ||
"environmentVariables": { | ||
"ASPNETCORE_ENVIRONMENT": "Development" | ||
}, | ||
"applicationUrl": "http://localhost:31895/" | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Net; | ||
using System.Threading.Tasks; | ||
using Microsoft.AspNetCore.Builder; | ||
using Microsoft.AspNetCore.Hosting; | ||
using Microsoft.AspNetCore.Http; | ||
using Microsoft.AspNetCore.HttpsPolicy; | ||
using Microsoft.Extensions.DependencyInjection; | ||
|
||
namespace HttpsSample | ||
{ | ||
public class Startup | ||
{ | ||
// This method gets called by the runtime. Use this method to add services to the container. | ||
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 | ||
public void ConfigureServices(IServiceCollection services) | ||
{ | ||
services.Configure<HttpsPolicyOptions>(options => { | ||
options.SetHsts = true; | ||
options.StatusCode = 302; | ||
options.TlsPort = 5001; | ||
}); | ||
} | ||
|
||
|
||
public void Configure(IApplicationBuilder app) | ||
{ | ||
app.UseHttpsPolicy(); | ||
|
||
app.Run(async context => | ||
{ | ||
await context.Response.WriteAsync("Hello world!"); | ||
}); | ||
} | ||
|
||
// Entry point for the application. | ||
public static void Main(string[] args) | ||
{ | ||
var host = new WebHostBuilder() | ||
.UseKestrel( | ||
options => | ||
{ | ||
options.Listen(new IPEndPoint(IPAddress.Loopback, 5001), listenOptions => | ||
{ | ||
listenOptions.UseHttps("testCert.pfx", "testPassword"); | ||
}); | ||
options.Listen(new IPEndPoint(IPAddress.Loopback, 5000), listenOptions => | ||
{ | ||
}); | ||
}) | ||
.UseContentRoot(Directory.GetCurrentDirectory()) // for the cert file | ||
.UseStartup<Startup>() | ||
.Build(); | ||
|
||
host.Run(); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// Copyright (c) .NET Foundation. All rights reserved. | ||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
||
using System; | ||
using Microsoft.AspNetCore.Builder; | ||
using Microsoft.Extensions.Options; | ||
|
||
namespace Microsoft.AspNetCore.HttpsPolicy | ||
{ | ||
/// <summary> | ||
/// Extension methods for the HSTS middleware. | ||
/// </summary> | ||
public static class HstsExtensions | ||
{ | ||
/// <summary> | ||
/// Adds middleware for using HSTS, which adds the Strict-Transport-Security header. | ||
/// </summary> | ||
/// <param name="app">The <see cref="IApplicationBuilder"/> instance this method extends.</param> | ||
public static IApplicationBuilder UseHsts(this IApplicationBuilder app) | ||
{ | ||
if (app == null) | ||
{ | ||
throw new ArgumentNullException(nameof(app)); | ||
} | ||
|
||
return app.UseMiddleware<HstsMiddleware>(); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
// Copyright (c) .NET Foundation. All rights reserved. | ||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
||
using System; | ||
using System.Threading.Tasks; | ||
using Microsoft.AspNetCore.Http; | ||
using Microsoft.Extensions.Options; | ||
using Microsoft.Extensions.Primitives; | ||
using Microsoft.Net.Http.Headers; | ||
|
||
namespace Microsoft.AspNetCore.HttpsPolicy | ||
{ | ||
/// <summary> | ||
/// Enables HTTP Strict Transport Security (HSTS) | ||
/// See https://tools.ietf.org/html/rfc6797. | ||
/// </summary> | ||
public class HstsMiddleware | ||
{ | ||
private const string IncludeSubDomains = "; includeSubDomains"; | ||
private const string Preload = "; preload"; | ||
|
||
private readonly RequestDelegate _next; | ||
private readonly StringValues _nameValueHeaderValue; | ||
|
||
/// <summary> | ||
/// Initialize the HSTS middleware. | ||
/// </summary> | ||
/// <param name="next"></param> | ||
/// <param name="options"></param> | ||
public HstsMiddleware(RequestDelegate next, IOptions<HstsOptions> options) | ||
{ | ||
if (next == null) | ||
{ | ||
throw new ArgumentNullException(nameof(next)); | ||
} | ||
|
||
if (options == null) | ||
{ | ||
throw new ArgumentNullException(nameof(options)); | ||
} | ||
|
||
_next = next; | ||
|
||
var hstsOptions = options.Value; | ||
var includeSubdomains = hstsOptions.IncludeSubDomains ? IncludeSubDomains : StringSegment.Empty; | ||
var preload = hstsOptions.Preload ? Preload : StringSegment.Empty; | ||
|
||
_nameValueHeaderValue = new StringValues($"max-age={hstsOptions.MaxAge}{includeSubdomains}{preload}"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. _stsValue |
||
} | ||
|
||
/// <summary> | ||
/// Invoke the middleware. | ||
/// </summary> | ||
/// <param name="context">The <see cref="HttpContext"/>.</param> | ||
/// <returns></returns> | ||
public async Task Invoke(HttpContext context) | ||
{ | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We've got a blank line here. |
||
if (context.Request.IsHttps) | ||
{ | ||
context.Response.Headers[HeaderNames.StrictTransportSecurity] = _nameValueHeaderValue; | ||
} | ||
await _next(context); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no async/await required |
||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// Copyright (c) .NET Foundation. All rights reserved. | ||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
||
namespace Microsoft.AspNetCore.HttpsPolicy | ||
{ | ||
/// <summary> | ||
/// Options for the Hsts Middleware | ||
/// </summary> | ||
public class HstsOptions | ||
{ | ||
/// <summary> | ||
/// Sets the max-age parameter of the Strict-Transport-Security header. | ||
/// </summary> | ||
/// <remarks> | ||
/// Max-age is required; defaults to 0. | ||
/// See: https://tools.ietf.org/html/rfc6797#section-6.1.1 | ||
/// </remarks> | ||
public int MaxAge { get; set; } | ||
|
||
/// <summary> | ||
/// Sets the includeSubDomain parameter of the Strict-Transport-Security header. | ||
/// </summary> | ||
/// <remarks> | ||
/// See: https://tools.ietf.org/html/rfc6797#section-6.1.2 | ||
/// </remarks> | ||
public bool IncludeSubDomains { get; set; } | ||
|
||
/// <summary> | ||
/// Sets the preload parameter of the Strict-Transport-Security header. | ||
/// </summary> | ||
/// <remarks> | ||
/// Preload is not part of the RFC specification, but is supported by web browsers | ||
/// to preload HSTS sites on fresh install. See https://hstspreload.org/. | ||
/// </remarks> | ||
public bool Preload { get; set; } | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// Copyright (c) .NET Foundation. All rights reserved. | ||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
||
using System; | ||
using Microsoft.AspNetCore.Builder; | ||
using Microsoft.AspNetCore.HttpsPolicy; | ||
using Microsoft.AspNetCore.Rewrite; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Options; | ||
|
||
namespace Microsoft.AspNetCore.Builder | ||
{ | ||
/// <summary> | ||
/// Extension methods for the HttpsPolicy middleware. | ||
/// </summary> | ||
public static class HttpsPolicyBuilderExtensions | ||
{ | ||
/// <summary> | ||
/// Adds middleware for enforcing HTTPS for all HTTP Requests, including redirecting HTTP to HTTPS | ||
/// and adding the HTTP Strict-Transport-Header. | ||
/// </summary> | ||
/// <param name="app">The <see cref="IApplicationBuilder"/> instance this method extends.</param> | ||
/// <returns>The <see cref="IApplicationBuilder"/> with HttpsPolicy.</returns> | ||
/// <remarks> | ||
/// HTTPS Enforcement interanlly uses the UrlRewrite middleware to redirect HTTP requests to HTTPS | ||
/// </remarks> | ||
public static IApplicationBuilder UseHttpsPolicy(this IApplicationBuilder app) | ||
{ | ||
if (app == null) | ||
{ | ||
throw new ArgumentNullException(nameof(app)); | ||
} | ||
var options = app.ApplicationServices.GetRequiredService<IOptions<HttpsPolicyOptions>>().Value; | ||
|
||
if (options.SetHsts) | ||
{ | ||
app.UseHsts(); | ||
} | ||
|
||
var rewriteOptions = new RewriteOptions(); | ||
rewriteOptions.AddRedirectToHttps( | ||
options.StatusCode, | ||
options.TlsPort); | ||
|
||
app.UseRewriter(rewriteOptions); | ||
|
||
return app; | ||
} | ||
|
||
public static IApplicationBuilder UseHttpsPolicy(this IApplicationBuilder app, bool enableHsts) | ||
{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why empty? Do we need a comment explaining it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry redesign for this. I need to do a bit of work still! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, OK, sorry didn't notice the [WIP] in the title. |
||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// Copyright (c) .NET Foundation. All rights reserved. | ||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
||
using Microsoft.AspNetCore.Http; | ||
|
||
namespace Microsoft.AspNetCore.HttpsPolicy | ||
{ | ||
/// <summary> | ||
/// Options for the HttpsPolicyMiddleware middleware | ||
/// </summary> | ||
public class HttpsPolicyOptions | ||
{ | ||
/// <summary> | ||
/// Whether to use HTTP Strict-Transport-Security (HSTS) on all HTTPS requests. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. responses |
||
/// </summary> | ||
public bool SetHsts { get; set; } | ||
|
||
/// <summary> | ||
/// The status code to be used for Url Redirection | ||
/// </summary> | ||
public int StatusCode { get; set; } = StatusCodes.Status301MovedPermanently; // TODO throw ArgumentOutOfRangeException from UrlRewrite redirect rule? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's ok as it is. I don't think we need to over protect against a non redirect status code. I would change the property name and the doc comment to reflect that is a redirect status code. Property would be RedirectStatusCode. What do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes RedirectStatusCode. |
||
|
||
/// <summary> | ||
/// The TLS port to be added to the redirected URL. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The default port (443) will be used if not provided. |
||
/// </summary> | ||
public int? TlsPort { get; set; } | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// Copyright (c) .NET Foundation. All rights reserved. | ||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
||
using System; | ||
using Microsoft.AspNetCore.HttpsPolicy; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.DependencyInjection.Extensions; | ||
|
||
namespace Microsoft.AspNetCore.Builder | ||
{ | ||
/// <summary> | ||
/// Extension methods for the HttpsPolicy middleware. | ||
/// </summary> | ||
public static class HttpsPolicyServiceCollectionExtensions | ||
{ | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Builder namespace