12

Recently I had a bit of a problem with a site on AppHarbor which I wrote about on their support forums: Request.IsSecureConnection always returns false

In short, because the load balancer is decrypting the HTTPS traffic before it hits the web app, attributes such as Request.IsSecureConnection and configuration like requireSSL on forms auth is not behaving as expected. In fact in the latter case, you can't even authenticate as the app thinks the request isn't coming over HTTPS.

It's the forms auth which is especially problematic because without it, cookies aren't set to "secure" and are sent back over HTTP if the site is accessed by domain name only and implicitly serves up the insecure URL scheme.

What would be the best workaround for this? I'd prefer to leverage the native security configuration, can anyone see a way to override the implementation which checks if the connection is secure? It's easy enough to detect whether the request was served over HTTPS (either based on Request.Url.Scheme or the X_FORWARDED_FOR header), it's just a question of neatly tying this in.

Mike Mertsock
  • 11,825
  • 7
  • 42
  • 75
Troy Hunt
  • 20,345
  • 13
  • 96
  • 151
  • The IsSecureConnection is only check if the url starts with https:// (and not with http://) – Aristos Nov 29 '11 at 08:02
  • Are you confident of that? There seems to be more too it based on the response on App Harbor and other people experiencing similar problems under the same circumstances in other load balanced scenarios. My understanding is that it checks if the connection uses secure sockets but that's not dependent on if the URL scheme is HTTPS, hence the problem. – Troy Hunt Nov 29 '11 at 09:16
  • last time I have check this with NetReflector, and see the code of "IsSecureConnection" that check only if url starts with https:// If you can run NetReflector you find the function and check it by your self. – Aristos Nov 29 '11 at 09:45
  • Just a thought Troy, don't know if it's any help, what about flagging it when you originate (Maybe is a session of some-kind) then looking for that when it comes back? I've not used the particular set-up your describing, but generally it seems as though it may provide an avenue to explore. – shawty Nov 29 '11 at 09:56

2 Answers2

5

Alternatively, you can use the URL rewrite module to trick ASP.NET into thinking that it is running under a HTTPS context, and leave the requireSSL flags in place (which means the cookies will be set as secure - and only available if you really are running under HTTPS)

You can set the following in your web.config:

    <rewrite>
        <rules>
            <rule name="HTTPS_AlwaysOn" patternSyntax="Wildcard">
                <match url="*" />
                <serverVariables>
                    <set name="HTTPS" value="on" />
                </serverVariables>
                <action type="None" />
            </rule>
        </rules>
    </rewrite>

You'll also need to add HTTPS to the list of allowedServerVariables in the applicationHost.config (or through the URL REwrite config)

        <rewrite>
            <allowedServerVariables>
                <add name="HTTPS" />
            </allowedServerVariables>
        </rewrite>

With thanks to Levi Broderick on the ASP.NET team who sent me in the right direction to this solution!

James Crowley
  • 3,911
  • 5
  • 36
  • 65
4

Turn off the RequireSSL setting and add the following code to your app. This should secure your authentication/session cookies.

void Application_EndRequest(object sender, EventArgs e)
{
    if (Response.Cookies.Count > 0)
    {
        foreach (string s in Response.Cookies.AllKeys)
        {
            if (s == FormsAuthentication.FormsCookieName || s.ToLower() == "asp.net_sessionid")
            {
                Response.Cookies[s].Secure = true;
            }
        }
    }
}
Chris
  • 459
  • 2
  • 3
  • Allowing the cookie to go over HTTP at all would keep it insecure. Since the `Response.Cookies.Count > 0` isn't necessary with the `foreach`, I ended up swapping it for `!Request.IsLocal` and putting in `Response.Cookies[s].HttpOnly = false;` to prevent sending it over the wire in plaintext (but leave it open for local dev testing). – patridge Feb 11 '12 at 04:22
  • 1
    HttpOnly = false IS THE WRONG FLAG (it controls whether the cookie is available to Javascript, and has nothing to do with the type of connection). – John Wu Nov 12 '13 at 08:10