Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is middleware neeeded to redirect to HTTPS in ASP.net and C#?

What is the recommend way to redirect to HTTPS all incoming requests that are not secure. Do I need to write a middleware component? If so, I couldn't figure out how to get the server name.

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);
        }
    }
}
like image 280
William Avatar asked Apr 06 '15 18:04

William


People also ask

What middleware can be specified to redirect all HTTP requests to HTTPS?

HTTPS Redirection Middleware (UseHttpsRedirection) to redirect HTTP requests to HTTPS.

What is the use of middleware in asp net?

Middleware is software that's assembled into an app pipeline to handle requests and responses. Each component: Chooses whether to pass the request to the next component in the pipeline. Can perform work before and after the next component in the pipeline.

How do I redirect in middleware NET Core?

Use AddRedirectToHttps to redirect HTTP requests to the same host and path using the HTTPS protocol. If the status code isn't supplied, the middleware defaults to 302 - Found. If the port isn't supplied: The middleware defaults to null .

Does ASP NET have middleware?

Middleware in ASP.NET Core controls how our application responds to HTTP requests. It can also control how our application looks when there is an error, and it is a key piece in how we authenticate and authorize a user to perform specific actions.


4 Answers

You can use your own middleware class, but typically I just do something like this in my Startup configuration:

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);
    }
});

What this does is just grab the entire URL, query string and all, and use GetComponents to get everything except the scheme in the URL. Then the HTTPS scheme gets prepended to the components URL.

This will work with the full .NET Framework, for ASP.NET Core, you can do something like this:

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);
    }
});

This appends the host and the path to the HTTPS scheme. You may want to add other components such as the query and hash, too.

like image 104
vcsjones Avatar answered Oct 18 '22 18:10

vcsjones


For .NET Core 2.0 and lower (official docs for 2.0):

Use the [RequireHttps] attribute/filter. You can either do this to your controllers:

[RequireHttps]
public class AccountController {
}

Or else add this in your Startup.cs in the ConfigureServices method:

services.Configure<MvcOptions>(options =>
{
    options.Filters.Add(new RequireHttpsAttribute());
}

Also, I just wanted to add that vcsjones' answer is also correct, but you need to be sure to add this code early on in your config, before any other Middleware/code that causes redirects. In my case, I added it just before I added the Identity Framework middleware.

like image 33
Josh Mouch Avatar answered Oct 18 '22 18:10

Josh Mouch


The full answer is in number 1 but don't stop there setting up HTTPS, go the extra step:

1 - We then use the RequireHttpsAttribute to redirect to HTTPS and set the SSL port in the MVC options. We are also reading the SSL port from launchSettings.json but we only need this in Development mode.

2 - Use AddAntiforgery to require HTTPS on your anti-forgery tokens.

3 - Use the NWebsec.AspNetCore.Middleware NuGet package and UseHsts method to enable Strict Transport Security (HSTS) across the site. Don't forget to add the Preload below and submit your site to the HSTS Preload site. More information here and here.

4 - Use NWebsec.AspNetCore.Middleware NuGet package and the UseHpkp method to enable Public Key Pinning (HPKP) across the site. Note that if you make a mistake with this one you are essentially DoS'ing your site. More information here and here.

5 - Include the https scheme in any URL's used. Content Security Policy (CSP) HTTP header and Subresource Integrity (SRI) do not play nice when you imit the scheme in some browsers. It is better to be explicit about HTTPS. e.g.

<script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.4/bootstrap.min.js"></script>

6- Use the 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.

After all of the above, your Startup class should look something like this:

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();
    }
}
like image 12
Muhammad Rehan Saeed Avatar answered Oct 18 '22 20:10

Muhammad Rehan Saeed


If you want to grab the port when in a DEV enviroment in .NET Core, look at env.IsDevelopment() and conditionally grab the SSL port from 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");
}

`

After grabing the SSL port, then you can incorporate the port into the solution posted by @vcsjones.

like image 3
long2know Avatar answered Oct 18 '22 19:10

long2know