Best way in asp.net to force https for an entire site?

189,050

Solution 1

Please use HSTS (HTTP Strict Transport Security)

from http://www.hanselman.com/blog/HowToEnableHTTPStrictTransportSecurityHSTSInIIS7.aspx

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="HTTP to HTTPS redirect" stopProcessing="true">
                    <match url="(.*)" />
                    <conditions>
                        <add input="{HTTPS}" pattern="off" ignoreCase="true" />
                    </conditions>
                    <action type="Redirect" url="https://{HTTP_HOST}/{R:1}"
                        redirectType="Permanent" />
                </rule>
            </rules>
            <outboundRules>
                <rule name="Add Strict-Transport-Security when HTTPS" enabled="true">
                    <match serverVariable="RESPONSE_Strict_Transport_Security"
                        pattern=".*" />
                    <conditions>
                        <add input="{HTTPS}" pattern="on" ignoreCase="true" />
                    </conditions>
                    <action type="Rewrite" value="max-age=31536000" />
                </rule>
            </outboundRules>
        </rewrite>
    </system.webServer>
</configuration>

Original Answer (replaced with the above on 4 December 2015)

basically

protected void Application_BeginRequest(Object sender, EventArgs e)
{
   if (HttpContext.Current.Request.IsSecureConnection.Equals(false) && HttpContext.Current.Request.IsLocal.Equals(false))
   {
    Response.Redirect("https://" + Request.ServerVariables["HTTP_HOST"]
+   HttpContext.Current.Request.RawUrl);
   }
}

that would go in the global.asax.cs (or global.asax.vb)

i dont know of a way to specify it in the web.config

Solution 2

The other thing you can do is use HSTS by returning the "Strict-Transport-Security" header to the browser. The browser has to support this (and at present, it's primarily Chrome and Firefox that do), but it means that once set, the browser won't make requests to the site over HTTP and will instead translate them to HTTPS requests before issuing them. Try this in combination with a redirect from HTTP:

protected void Application_BeginRequest(Object sender, EventArgs e)
{
  switch (Request.Url.Scheme)
  {
    case "https":
      Response.AddHeader("Strict-Transport-Security", "max-age=300");
      break;
    case "http":
      var path = "https://" + Request.Url.Host + Request.Url.PathAndQuery;
      Response.Status = "301 Moved Permanently";
      Response.AddHeader("Location", path);
      break;
  }
}

Browsers that aren't HSTS aware will just ignore the header but will still get caught by the switch statement and sent over to HTTPS.

Solution 3

The IIS7 module will let you redirect.

    <rewrite>
        <rules>
            <rule name="Redirect HTTP to HTTPS" stopProcessing="true">
                <match url="(.*)"/>
                <conditions>
                    <add input="{HTTPS}" pattern="^OFF$"/>
                </conditions>
                <action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="SeeOther"/>
            </rule>
        </rules>
    </rewrite>

Solution 4

For those using ASP.NET MVC. You can use the following to force SSL/TLS over HTTPS over the whole site in two ways:

The Hard Way

1 - Add the RequireHttpsAttribute to the global filters:

GlobalFilters.Filters.Add(new RequireHttpsAttribute());

2 - Force Anti-Forgery tokens to use SSL/TLS:

AntiForgeryConfig.RequireSsl = true;

3 - Require Cookies to require HTTPS by default by changing the Web.config file:

<system.web>
    <httpCookies httpOnlyCookies="true" requireSSL="true" />
</system.web>

4 - Use the NWebSec.Owin NuGet package and add the following line of code to enable Strict Transport Security accross the site. Don't forget to add the Preload directive below and submit your site to the HSTS Preload site. More information here and here. Note that if you are not using OWIN, there is a Web.config method you can read up on on the NWebSec site.

// app is your OWIN IAppBuilder app in Startup.cs
app.UseHsts(options => options.MaxAge(days: 30).Preload());

5 - Use the NWebSec.Owin NuGet package and add the following line of code to enable Public Key Pinning (HPKP) across the site. More information here and here.

// app is your OWIN IAppBuilder app in Startup.cs
app.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: 30));

6 - 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>

The Easy Way

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.

Solution 5

If you are unable to set this up in IIS for whatever reason, I'd make an HTTP module that does the redirect for you:

using System;
using System.Web;

namespace HttpsOnly
{
    /// <summary>
    /// Redirects the Request to HTTPS if it comes in on an insecure channel.
    /// </summary>
    public class HttpsOnlyModule : IHttpModule
    {
        public void Init(HttpApplication app)
        {
            // Note we cannot trust IsSecureConnection when 
            // in a webfarm, because usually only the load balancer 
            // will come in on a secure port the request will be then 
            // internally redirected to local machine on a specified port.

            // Move this to a config file, if your behind a farm, 
            // set this to the local port used internally.
            int specialPort = 443;

            if (!app.Context.Request.IsSecureConnection 
               || app.Context.Request.Url.Port != specialPort)
            {
               app.Context.Response.Redirect("https://" 
                  + app.Context.Request.ServerVariables["HTTP_HOST"] 
                  + app.Context.Request.RawUrl);    
            }
        }

        public void Dispose()
        {
            // Needed for IHttpModule
        }
    }
}

Then just compile it to a DLL, add it as a reference to your project and place this in web.config:

 <httpModules>
      <add name="HttpsOnlyModule" type="HttpsOnly.HttpsOnlyModule, HttpsOnly" />
 </httpModules>
Share:
189,050

Related videos on Youtube

Felipe
Author by

Felipe

Updated on May 16, 2020

Comments

  • Felipe
    Felipe almost 4 years

    About 6 months ago I rolled out a site where every request needed to be over https. The only way at the time I could find to ensure that every request to a page was over https was to check it in the page load event. If the request was not over http I would response.redirect("https://example.com")

    Is there a better way -- ideally some setting in the web.config?

  • Brian MacKay
    Brian MacKay over 14 years
    This seems more involved than just sticking it in the global.asax -- just curious, is there an advantage?
  • Bob Yexley
    Bob Yexley over 14 years
    The advantage would be, when you don't want to use it, just comment out the module in your web.config. This solution is configurable, whereas the other is not.
  • Jakub Šturc
    Jakub Šturc over 13 years
    I am little confused. I'd expected something like app.BeginRequest += new OnBeginRequest; in the Init method and in the OnBeginRequest would contains what current Init method contains. Are you sure that this module works as expected?
  • SnAzBaZ
    SnAzBaZ over 13 years
    It does not work. You do need to add the OnBeginRequest event etc, then it works.
  • mg1075
    mg1075 over 12 years
    This works, but it was dangerous for me: when I attempted to run locally in VS 2010 with this code running, my start page never loaded; instead, I just received a "This webpage is not available" message. To fix, I added a second condition to test if the url contains the string "localhost": if it does not, then force https.
  • Joe
    Joe over 12 years
    This is giving me a redirect loop. Before I added the code it worked fine. Any suggestions?
  • Chris
    Chris about 12 years
    Also, for IIS 7.0, you need to install Url Rewrite Module 2.0
  • Pankaj
    Pankaj about 12 years
    +1, It is doing the redirect to server twice? First one, When you are explicitly redirecting and second one, when you are doing redirect in the Global.asax ?
  • dana
    dana about 11 years
    Never heard about the HSTS header before, but looks pretty cool. Is there any reason for using such a small max-age value (5 minutes)? The Wikipedia article you link to suggests setting it to a large value (6-12 months).
  • Oran Dennison
    Oran Dennison about 11 years
    +1. check out this very extensive article on Troy's blog which includes details on why only using redirects can reduce security. Hint: it can leave you vulnerable to the SSL Strip tool, among other things. troyhunt.com/2011/11/…
  • tne
    tne almost 10 years
    Please note that this does not provide any useful security whatsoever. Actually, it will only secure connections from users that are already safe, and will fail to secure those that are being attacked (this is because a MITM can simply omit the redirection altogether and forward everything to your "secure" site). IMHO, redirecting user agents is just feel-good voodoo security, and provides a sometimes dangerous illusion of safety. The only way to go is to instruct the user agents to only request secure resources, not redirect them if they don't. This is what HSTS does -- see answers below.
  • Tieson T.
    Tieson T. over 9 years
    Also worth checking out NWebsec, which makes this (and more) very easy.
  • Justin J Stark
    Justin J Stark over 9 years
    You'll want to wrap the switch in if(!Request.IsLocal) so it doesn't break debugging.
  • Ognyan Dimitrov
    Ognyan Dimitrov over 9 years
    Good answer. One subtlety - For the Http headers ("Strict-Transport-Security") it is better to use library like NWebSec because there are multiple options which are concentrated in one place of configuration rather then spread out here and there.
  • Manik Arora
    Manik Arora over 9 years
    I found this link simple and helpful in making any particular page to accept only https requests - support.microsoft.com/kb/239875
  • Manik Arora
    Manik Arora about 9 years
    You can also add - "GlobalFilters.Filters.Add(new RequireHttpsAttribute());" to "Application_Start()" method in "global.asax.cs"
  • Rosdi Kasim
    Rosdi Kasim about 9 years
    This answer should be considered 'harmful' and should not be used. As per comment by @tne above.
  • Pluto
    Pluto almost 9 years
    Also if using <authentication mode="Forms">, inside you must have <forms requireSSL="true">
  • Diin
    Diin over 8 years
    @muhammad-rehan-saeed I am using mvc5 boilerplate but the site does not redirect http to https automatically on production server it does so only on localhost is there something I am missing?
  • Muhammad Rehan Saeed
    Muhammad Rehan Saeed over 8 years
    This is not the right forum to ask this question. Post an issue on the GitHub site. The RequireHttpsAttribute does the redirect. As long as you have that it should be fine.
  • Marc L.
    Marc L. over 7 years
    I don't believe this will work for any pages served using WebForms or any APIs built with WebAPI. It will only cover MVC controllers.
  • Marc L.
    Marc L. over 7 years
    @RosdiKasim, the accepted answer was updated for HSTS as well, but completely obviated the "old answer" that showed the redirect-only in code. This is a good one for doing it in code. Can also be written into an IHttpModule.
  • Marc L.
    Marc L. over 7 years
    I would edit this faulty code, but to make it secure you'd also need to use HSTS. Just go with Troy Hunt's answer and make it a module; see support.microsoft.com/en-us/kb/307996 (an oldie, but goodie).
  • Bryan Lewis
    Bryan Lewis about 7 years
    A quick conversion to VB.net and this solution worked great.
  • GJKH
    GJKH almost 7 years
    If you're getting a reported error about your web.config being malformed make sure you have the url rewrite module installed - that had me stuck for 10 minutes or so. iis.net/downloads/microsoft/url-rewrite
  • Andrew Morton
    Andrew Morton almost 7 years
    @RosdiKasim Should this answer still be considered harmful since the Dec 4 '15 edit?
  • Rosdi Kasim
    Rosdi Kasim almost 7 years
    @AndrewMorton The updated answer (using HSTS) is the proper way to do it. It also redirects the browser to https in case the browser is using http.
  • Diana
    Diana almost 7 years
    @MuhammadRehanSaeed, love your answer. But... how do I get the SHA256 hash of a certificate created with MakeCert? All I have is a SHA-1 thumbprint... Do you happen to know?
  • Muhammad Rehan Saeed
    Muhammad Rehan Saeed almost 7 years
    @Diana this link can show you how.
  • monty
    monty about 6 years
    Due to a couple of non-tech issues, this is the method I used... except I'm returning "308 Permanent Redirect" which ensures that POSTs stay POSTs for the http redirect.
  • M-Peror
    M-Peror about 6 years
    I first used montys suggestion to use a 308 instead of 301 because of the POST support, only to find out that a 308 is not supported by IE11. If a significant portion of your visitors is still on IE, this could be a concern.
  • Jason James
    Jason James about 6 years
    This doesn't work for me. The site never get redirected to. I edited my web.config as above. The site works fine without the web.config edit and the https site works just fine if I navigate straight there (assuming no web.config changes). Has anyone else had issues with this code?
  • Adam R. Grey
    Adam R. Grey about 6 years
    I get a different problem. No redirect, but I can't get to the https site whether I have the web.config updated or not. firefox says SSL_ERROR_RX_RECORD_TOO_LONG and IE says to turn on TLS 1, 1.1, and 1.2 and try again.
  • Adam R. Grey
    Adam R. Grey about 6 years
    Does this handle all traffic to that website? or just the pages you've coded? That is, what about my images and javascript files?
  • ahwm
    ahwm over 5 years
    I've always had to use <add input="{HTTPS}" pattern="on" negate="true" /> because off never worked. Maybe it does now, I don't even try it these days.
  • Jánosi Zoltán János
    Jánosi Zoltán János over 3 years
    I copied these line to my web.config and now https is not working. I deleted these lines from web.config but my site still doesn't work. It seems to me, that these few lines modified something in my system that is connected to this project.
  • gabac
    gabac over 3 years
    After hsts is enabled for a domain the browser will not allow a non secure connection. You either need to make https works or clear the hsts for the domain on your browser.
  • David Klempfner
    David Klempfner almost 3 years
    @tne don't you first have to write code to redirect a user from http to https, in order to be able to respond with the HSTS? HSTS is only read by the browser if it's using HTTPS.
  • tne
    tne almost 3 years
    @DavidKlempfner In an ideal world this is not the best solution. The best would be to encourage end-users to only use HTTPS (it's now built-in to browsers, see "HTTPS-Only Mode" in Firefox for example, but there has always been extensions). HSTS helps if one needs to build lists of sites that can be secured (like HTTPS Everywhere), by declaring "this whole domain supports HTTPS, do use it. An insecure redirection + HSTS can be seen as a form of TOFU and as such is definitely better than plain HTTP, but will not be better than closing port 80.
  • Tim
    Tim over 2 years
    When I paste the revised answer's <rewrite> ... </rewrite> block into the <system.webServer> section of my web.config file, there is a 500 error.