asp.net c# redirecting from http to https

asp.netHttpHttps

asp.net Problem Overview


So in my code I want to detect if my login page is being called http, and redirect it to https.

I know there are non code ways to skin this cat, but for frustrating technical reasosn I'm backed into doing it in code.

            if (!Request.IsSecureConnection)
            {
                string redirectUrl = Request.Url.ToString().Replace("http:", "https:");
                Response.Redirect(redirectUrl);
            }

So I drop this in my Page_Load(...), make sure my debugger uses real IIS, not VS2008s IIS, and hit debug.

Inthe debugger, waltz along, hit Response.Redirect("https://localhost/StudentPortal3G/AccessControl/AdLogin.aspx";), hit f5.

Get "Internet Explorere Cannot Display the webpage, url is HTTP, not HTTPS. Not getting an informative error... same thing happens not running in the debugger.

So what am I missing? it does not appear to be rocket science, I've seen similar code on lots of blogs...

What am I doing wrong? I figure it has to be a totally obvious Rookie mistake, but I'm not seeing it.

asp.net Solutions


Solution 1 - asp.net

I'd do a !Request.IsLocal as well to make sure that I'm not debugging, though if you're using a real instance of IIS with a cert applied when debugging that shouldn't be an issue.

if (!Request.IsLocal && !Request.IsSecureConnection)
{
    string redirectUrl = Request.Url.ToString().Replace("http:", "https:");
    Response.Redirect(redirectUrl, false);
    HttpContext.ApplicationInstance.CompleteRequest();
}

Note: This answer assumes an MVC context within a Controller where HttpContext is a property holding the current context. If you're unlucky enough to still be using WebForms or are referencing the context in a degenerate way you will need to use HttpContext.Current.ApplicationInstance.CompleteRequest().

Note: I've updated this to be consistent with the recommended pattern to terminate the request according to the framework documentation.

> When you use this method in a page handler to terminate a request for > one page and start a new request for another page, set endResponse to > false and then call the CompleteRequest method. If you specify true > for the endResponse parameter, this method calls the End method for > the original request, which throws a ThreadAbortException exception > when it completes. This exception has a detrimental effect on Web > application performance, which is why passing false for the > endResponse parameter is recommended. For more information, see the > End method.

Solution 2 - asp.net

I usually call the following from the OnPreInit in a base class that all my pages inherit from. Of course, you could just do this in every page...but you wouldn't want to do that now would you?

Note that I've got two properties for each page so that I can specify the SSL requirement for each page (RequiresSSL) while I can also override and redirect check if I want (with IgnoreRequiresSSL, which is helpful for pages like error pages that you rewrite to and don't know whether they'll be encrypted or not), but of course, you can remove these for simple setups.

    protected override void OnPreInit(EventArgs e)
    {
        base.OnPreInit(e);

        if (!IsPostBack)
            RedirectAccordingToRequiresSSL();

        ...
    }

    /// <summary>
    /// Redirect if necessary to ssl or non-ssl enabled URL dependant on RequiresSSL property setting.
    /// </summary>
    private void RedirectAccordingToRequiresSSL()
    {
        if (IgnoreRequiresSSL) return;

        if (RequiresSSL)
        {
            if (!Request.IsSecureConnection) // Need to redirect to https
                RedirectAccordingToRequiresSSL(Uri.UriSchemeHttps);
        }
        else if (Request.IsSecureConnection)
        {
            RedirectAccordingToRequiresSSL(Uri.UriSchemeHttp);
        }

        // Otherwise don't need to do any redirecting as already using the correct scheme
    }

    /// <summary>
    /// Redirect as requested to specified scheme
    /// </summary>
    /// <param name="scheme"></param>
    private void RedirectAccordingToRequiresSSL(string scheme)
    {
        var url = scheme + Uri.SchemeDelimiter + Request.Url.Authority + Request.Url.PathAndQuery;
        Response.Redirect(url, false);
    }

Solution 3 - asp.net

In my opinion the following is the best all-round approach.

Three reasons

  1. It works for both MVC and Web API as it is done at IIS level.
  2. It does not effect local / debug settings. (permanent redirect can mess you around when debugging non https sites on your pc).
  3. Uses a permanent redirect, so all future requests will automatically go to https

Simply add the following to your <system.webServer> section in your 'Web.config' for your project.

 <system.webServer>
 ....

 <rewrite>
  <rules>
    <rule name="HTTP to HTTPS redirect" stopProcessing="true">
      <match url="(.*)" />
      <conditions>
        <add input="{HTTP_HOST}" pattern="localhost" negate="true" />
        <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>

Solution 4 - asp.net

You can also use the new UriBuilder:

Dim context As HttpContext = HttpContext.Current
If Not context.Request.IsSecureConnection Then
    Dim secureUrl As New UriBuilder(context.Request.Url)
    secureUrl.Scheme = "https"
    secureUrl.Port = 443
    context.Response.Redirect(secureUrl.ToString, False)
    Return
End If

C#

HttpContext context = HttpContext.Current;
if (!context.Request.IsSecureConnection)
{
    UriBuilder secureUrl = new UriBuilder(context.Request.Url);
    secureUrl.Scheme = "https";
    secureUrl.Port = 443;
    context.Response.Redirect(secureUrl.ToString(), false);
}

Solution 5 - asp.net

One of the ways that I was able to enforce an https redirect is to the following:

In the app pool I have my application running on just port 443 so that there is no possiblity for an unencrypted session to occur (unless encryption scheme is broken through a vulnerability..). I created another application on port 80 with the same IP address which contains just a web.config file with the following code

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
    <httpRedirect enabled="true" destination="https://yourWebsiteURL.com" />
</system.webServer>

Solution 6 - asp.net

Here's my solution:

// Force HTTPS connection
if (!Request.IsSecureConnection)
{
    var uri = new Uri(Request.Url.ToString());
    var redirectUrl = Settings.CanonicalDomain + uri.PathAndQuery;
    Response.Status = "301 Moved Permanently";
    Response.AddHeader("Location", redirectUrl);
    Response.End();
}

Where Settings.CanonicalDomain is your HTTPS hostname. It 301 redirects which may be the proper response in some cases.

Solution 7 - asp.net

I would also suggest tvalfonsso's solution, but with a small modification in case you have some url rewriting (RawUrl differs from Url)

    if (SPPage == SPPages.StartAutotrading && !Request.IsLocal && !Request.IsSecureConnection)
		{
			string redirectUrl = (Request.Url.ToString().Replace(Request.Url.PathAndQuery.ToString(), "") + Request.RawUrl).Replace("http:", "https:");
			Response.Redirect(redirectUrl);
		}

Solution 8 - asp.net

disclaimer - I was involved in the development of this project

I would recommend using http://nuget.org/packages/SecurePages/ It gives you the ability to secure specific pages or use Regex to define matches. It will also force all pages not matching the Regex or directly specified back to HTTP.

You can install it via NuGet: Install-Package SecurePages

Docs are here: https://github.com/webadvanced/Secure-Page-manager-for-asp.net#secure-pages

Simple Usage:

SecurePagesConfiguration.Urls.AddUrl("/cart");

or

SecurePagesConfiguration.Urls.AddRegex(@"(.*)account", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline);

Solution 9 - asp.net

On my development environment, I like to have a separate publish directory with IIS installed with a self signed cert, which is different form my code directory without a cert that I debug directly inside of Visual Studio. In this scenario !Request.IsLocal isn't ideal because it doesn't work anywhere on your development environment, even in the IIS directory with the cert. I prefer this:

if (!IsPostBack && !HttpContext.Current.IsDebuggingEnabled) 
{
    // do http->https and https->http redirection here
}

HttpContext.Current.IsDebuggingEnabled is based on the value of compilation debug="true/false" in your web.config. I have it set to true in my code directory, and false in my publish directory when I need to test http and https redirection locally.

I add in the IsPostBack simply to make it (slightly) more efficient by skipping the extra ssl checking when not needed.

Solution 10 - asp.net

A simple way to get IIS to do it without using Rewrite:

  1. IIS SSL Settings: Set SSL Required.
  2. IIS Error Pages: Change the IIS 403 Error code to redirect to the https url.

You can also add from the web.config in the HttpErrors section.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionEric Brown - CalView Question on Stackoverflow
Solution 1 - asp.nettvanfossonView Answer on Stackoverflow
Solution 2 - asp.netTedView Answer on Stackoverflow
Solution 3 - asp.netZapnologicaView Answer on Stackoverflow
Solution 4 - asp.netGeorge FilippakosView Answer on Stackoverflow
Solution 5 - asp.netErkin DjindjievView Answer on Stackoverflow
Solution 6 - asp.netTom GullenView Answer on Stackoverflow
Solution 7 - asp.netRobert BenyiView Answer on Stackoverflow
Solution 8 - asp.netPaulView Answer on Stackoverflow
Solution 9 - asp.netTTTView Answer on Stackoverflow
Solution 10 - asp.netNomad77View Answer on Stackoverflow