Enforce HTTPS in ASP.NET Core

By Rick Anderson

This document shows how to:

  • Require HTTPS for all requests.
  • Redirect all HTTP requests to HTTPS.

No API can prevent a client from sending sensitive data on the first request.

Warning

Do not use RequireHttpsAttribute on Web APIs that receive sensitive information. RequireHttpsAttribute uses HTTP status codes to redirect browsers from HTTP to HTTPS. API clients may not understand or obey redirects from HTTP to HTTPS. Such clients may send information over HTTP. Web APIs should either:

  • Not listen on HTTP.
  • Close the connection with status code 400 (Bad Request) and not serve the request.

Require HTTPS

We recommend all production ASP.NET Core web apps call:

  • The HTTPS Redirection Middleware (UseHttpsRedirection) to redirect all HTTP requests to HTTPS.
  • UseHsts, HTTP Strict Transport Security Protocol (HSTS).

UseHttpsRedirection

The following code calls UseHttpsRedirection in the Startup class:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseCookiePolicy();

    app.UseMvc();
}

The preceding highlighted code:

We recommend using temporary redirects rather than permanent redirects, as link caching can cause unstable behavior in development environments. We recommend using HSTS to signal to clients that only secure resource requests should be sent to the app (only in production).

Warning

A port must be available for the middleware to redirect to HTTPS. If no port is available, redirection to HTTPS doesn't occur. The HTTPS port can be specified using any of the following approaches:

  • Set HttpsRedirectionOptions.HttpsPort.
  • Set the ASPNETCORE_HTTPS_PORT environment variable.
  • In development, set an HTTPS URL in launchsettings.json.
  • Configure an HTTPS URL endpoint for Kestrel or HTTP.sys.

When Kestrel or HTTP.sys is used as a public-facing edge server, Kestrel or HTTP.sys must be configured to listen on both:

  • The secure port where the client is redirected (typically, 443 in production and 5001 in development).
  • The insecure port (typically, 80 in production and 5000 in development).

The insecure port must be accessible by the client in order for the app to receive an insecure request and redirect it to the secure port.

Any firewall between the client and server must also have the ports open for traffic.

For more information, see Kestrel endpoint configuration or HTTP.sys web server implementation in ASP.NET Core.

The following highlighted code calls AddHttpsRedirection to configure middleware options:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    services.AddHsts(options =>
    {
        options.Preload = true;
        options.IncludeSubDomains = true;
        options.MaxAge = TimeSpan.FromDays(60);
        options.ExcludedHosts.Add("example.com");
        options.ExcludedHosts.Add("www.example.com");
    });

    services.AddHttpsRedirection(options =>
    {
        options.RedirectStatusCode = StatusCodes.Status307TemporaryRedirect;
        options.HttpsPort = 5001;
    });            
}

Calling AddHttpsRedirection is only necessary to change the values of HttpsPort or RedirectStatusCode.

The preceding highlighted code:

The following mechanisms set the port automatically:

  • The middleware can discover the ports via IServerAddressesFeature when the following conditions apply:

    • Kestrel or HTTP.sys is used directly with HTTPS endpoints (also applies to running the app with Visual Studio Code's debugger).
    • Only one HTTPS port is used by the app.
  • Visual Studio is used:

    • IIS Express has HTTPS enabled.
    • launchSettings.json sets the sslPort for IIS Express.

Note

When an app is run behind a reverse proxy (for example, IIS, IIS Express), IServerAddressesFeature isn't available. The port must be manually configured. When the port isn't set, requests aren't redirected.

The port can be configured by setting the https_port Web Host configuration setting:

Key: https_port
Type: string
Default: A default value isn't set.
Set using: UseSetting
Environment variable: <PREFIX_>HTTPS_PORT (The prefix is ASPNETCORE_ when using the Web Host.)

WebHost.CreateDefaultBuilder(args)
    .UseSetting("https_port", "8080")

Note

The port can be configured indirectly by setting the URL with the ASPNETCORE_URLS environment variable. The environment variable configures the server, and then the middleware indirectly discovers the HTTPS port via IServerAddressesFeature.

If no port is set:

  • Requests aren't redirected.
  • The middleware logs the warning "Failed to determine the https port for redirect."

Note

An alternative to using HTTPS Redirection Middleware (UseHttpsRedirection) is to use URL Rewriting Middleware (AddRedirectToHttps). AddRedirectToHttps can also set the status code and port when the redirect is executed. For more information, see URL Rewriting Middleware.

When redirecting to HTTPS without the requirement for additional redirect rules, we recommend using HTTPS Redirection Middleware (UseHttpsRedirection) described in this topic.

The RequireHttpsAttribute is used to require HTTPS. [RequireHttpsAttribute] can decorate controllers or methods, or can be applied globally. To apply the attribute globally, add the following code to ConfigureServices in Startup:

// Requires using Microsoft.AspNetCore.Mvc;
public void ConfigureServices(IServiceCollection services)
{
    services.Configure<MvcOptions>(options =>
    {
        options.Filters.Add(new RequireHttpsAttribute());
    });

The preceding highlighted code requires all requests use HTTPS; therefore, HTTP requests are ignored. The following highlighted code redirects all HTTP requests to HTTPS:

// Requires using Microsoft.AspNetCore.Rewrite;
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();

    var options = new RewriteOptions()
       .AddRedirectToHttps();

    app.UseRewriter(options);

For more information, see URL Rewriting Middleware. The middleware also permits the app to set the status code or the status code and the port when the redirect is executed.

Requiring HTTPS globally (options.Filters.Add(new RequireHttpsAttribute());) is a security best practice. Applying the [RequireHttps] attribute to all controllers/Razor Pages isn't considered as secure as requiring HTTPS globally. You can't guarantee the [RequireHttps] attribute is applied when new controllers and Razor Pages are added.

HTTP Strict Transport Security Protocol (HSTS)

Per OWASP, HTTP Strict Transport Security (HSTS) is an opt-in security enhancement that's specified by a web app through the use of a response header. When a browser that supports HSTS receives this header:

  • The browser stores configuration for the domain that prevents sending any communication over HTTP. The browser forces all communication over HTTPS.
  • The browser prevents the user from using untrusted or invalid certificates. The browser disables prompts that allow a user to temporarily trust such a certificate.

Because HSTS is enforced by the client it has some limitations:

  • The client must support HSTS.
  • HSTS requires at least one successful HTTPS request to establish the HSTS policy.
  • The application must check every HTTP request and redirect or reject the HTTP request.

ASP.NET Core 2.1 or later implements HSTS with the UseHsts extension method. The following code calls UseHsts when the app isn't in development mode:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseCookiePolicy();

    app.UseMvc();
}

UseHsts isn't recommended in development because the HSTS settings are highly cacheable by browsers. By default, UseHsts excludes the local loopback address.

For production environments implementing HTTPS for the first time, set the initial HSTS value to a small value. Set the value from hours to no more than a single day in case you need to revert the HTTPS infrastructure to HTTP. After you're confident in the sustainability of the HTTPS configuration, increase the HSTS max-age value; a commonly used value is one year.

The following code:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    services.AddHsts(options =>
    {
        options.Preload = true;
        options.IncludeSubDomains = true;
        options.MaxAge = TimeSpan.FromDays(60);
        options.ExcludedHosts.Add("example.com");
        options.ExcludedHosts.Add("www.example.com");
    });

    services.AddHttpsRedirection(options =>
    {
        options.RedirectStatusCode = StatusCodes.Status307TemporaryRedirect;
        options.HttpsPort = 5001;
    });            
}
  • Sets the preload parameter of the Strict-Transport-Security header. Preload isn't part of the RFC HSTS specification, but is supported by web browsers to preload HSTS sites on fresh install. See https://hstspreload.org/ for more information.
  • Enables includeSubDomain, which applies the HSTS policy to Host subdomains.
  • Explicitly sets the max-age parameter of the Strict-Transport-Security header to 60 days. If not set, defaults to 30 days. See the max-age directive for more information.
  • Adds example.com to the list of hosts to exclude.

UseHsts excludes the following loopback hosts:

  • localhost : The IPv4 loopback address.
  • 127.0.0.1 : The IPv4 loopback address.
  • [::1] : The IPv6 loopback address.

The preceding example shows how to add additional hosts.

Opt-out of HTTPS/HSTS on project creation

In some backend service scenarios where connection security is handled at the public-facing edge of the network, configuring connection security at each node isn't required. Web apps generated from the templates in Visual Studio or from the dotnet new command enable HTTPS redirection and HSTS. For deployments that don't require these scenarios, you can opt-out of HTTPS/HSTS when the app is created from the template.

To opt-out of HTTPS/HSTS:

Uncheck the Configure for HTTPS checkbox.

Entity diagram

How to set up a developer certificate for Docker

See this GitHub issue.

Additional information