RequireHttps and routing to https URL
Asked Answered
P

3

0

I am using the RequireHttps attribute on most of the actions in my User controller which handles the login and my secure https pages.

On my Home Page which is http I have a link to my login page as follows (MVC 4 Razor View):-

<a href="@Url.Action("Login", "User")">Login</a>

The link correctly goes to the login page with an https address. However, when I look in the IIS log I see there are two entries for the login URL, one on port 80 and one on port 443.

Is this an issue I should be concerned about?

I know on my @Url.Action I could force https mode, but not sure if this is the best way. Plus this removes the port, which is annoying when using IIS Express in VS 2012. I'd then have to further extend the @Url.Action to include the hostname:port.

So I am just checking if (a) this should be a concern and (b) if it is a concern whether there are any other ways to forcing the URL to https.

Promissory answered 27/2, 2013 at 17:35 Comment(0)
W
4

Most tutorials will agree that by having a mixed mode site (both HTTP and HTTPS) you're defeating the purpose of SSL (having certain paths require SSL then switching back to a non SSL connection). Once you switch to HTTPS it's recommended that you force the user to stay using HTTPS for everything, at the very least until they logout. I have one site that uses HTTPS and once you hit the site, I just use a URL Rewrite rule to switch the user to HTTPS, and only HTTPS is allowed.

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

Once you do this it's also recommended to set the authentication cookie to require HTTPS as well. For Forms authentication this is as simple as setting the following in your web.config.

<authentication>
    <forms requireSSL="true" />
</authentication>

I would also recommend looking at some of the Headers that can be set to help browsers treat the site correctly, like using Strict-Transport-Security to signify that the site requires SSL. Keep in mind that while Headers are a great supplemental measure you can take, ultimately they are left for the browser to enforce and should not be relied on exclusively.

I recommend these steps because I don't suffer from the symptom you're describing and am hoping they'll help resolve the issue you're noticing in the logs.

AMMENDMENT: Oh and I also forgot to mention, HTTPS is a little more intensive to establish a connection with than plain old HTTP. Not much in the grand scheme of things but still it's something. I'd recommend you utilize HTTP Keep Alive so as to reduce some of that overhead.

UPDATE: Communicating over SSL doesn't imply that you are authenticated. It just means you're talking over a secure/encrypted connection.

Take your Amazon example lets say. If you visit the site, you'll like get just a normal connection over HTTP. You're aren't logged in you're just browsing the site. If you wanted you could switch to HTTPS and you'd still get the same site but you're not logged in yet. Now if you try to login you'll get redirected so that you talk over SSL (if you're not already) as noted by the HTTPS moniker. Even after you actually login you will still be communicating over SSL. Even if you try to manually switch to not using SSL while you are logged in by removing the S from the protocol part of the URL, it'll still send you back to using HTTPS. This is the correct way of doing it. It's generally suggested that you not return to a non encrypted session after authenticating. This is typically to avoid session hijacking since your authentication cookie would never be sent over plain HTTP. Make sure the resources you have on external sources, are on sites that you trust. External resources access while in a HTTP connection should also be over an SSL connection. Again just because you communicate over SSL doesn't mean you're logged into those sources. For my app is 100% access over SSL, but I also have Google analytics and Google maps integration on the site (obviously both are external to my domain). I just make sure that I talk to Google over SSL. I don't have to actually be logged into Google to use any of those things. The same goes for your external images. Just make sure your URL's used to reference those external images are defined using the HTTPS moniker so that it uses SSL.

UPDATE: The reason you're getting two hits in the log like that is because you're login link is being requested over HTTP, the Require HTTPS attribute hits first realizes you're not using SSL and redirects you back to itself with the HTTPS protocol. If you update your ActionLink URL you can get around this, but as you know it gets ugly.

Url.Action("Login", "User", null, "https", Request.Url.Host)
Wheelhouse answered 27/2, 2013 at 18:0 Comment(6)
Thanks for the advice. This was kind of going to be a follow up separate question, but I guess 2 sites gets rid of my initial problem. However:- (1) What happens with sites like Amazon? When you are logged in but on the front page it knows who you are - I like this functionality especially as our site allows you select an item you'd like to book, log in to add it to your basket, browse the site for another item to book, add that one etc. (2) Our site has images hosted at different places. Having to stay logged into https would leave the user with insecure messages - any solution to this?Promissory
I updated my answer with some more info for your questions (not enough room to do it in a comment)Wheelhouse
Thanks. 2 questions (1) You say "Even after you actually login you will still be communicating over SSL". With the Amazon example, I log in (URL says https), I search for Books and the URL changes back to http but it also says "Hello cw_dev" in the top. Unless I am misunderstanding the issue isn't that the the opposite of what you are saying? (2) Let's says my website is hosted a domain A, my images as Domain B. Domain B does not have an SSL certificate. Are you saying if I try and access the images simply by using an HTTPS url it should just work? I am sure I tried this earlier and it didn't.Promissory
You're right I stand corrected (I hadn't tries to search after logging in before posting my update). Though I find it interesting that they let you back into an insecure session after being authenticated... Typically this is frowned upon because of session hijacking. I'm not saying they are susceptible to this, it's just that's typically the reason behind not going back to HTTP after logging in over SSL. No you're correct, a valid SSL cert is required to use SSL. In my case Google provides their services over SSL as well as plain old HTTP.Wheelhouse
Our issue is typically this... We sell our website to customers who host it on their own IIS. Their line speeds are not typically mega fast. So to reduce server load, images are hosted on general FTP elsewhere. This works really well. This leaves us with the issue of forcing the whole site into Https as the main part of the site accesses these images. Not sure of the best way forwards as here. Would it be possible to store just their name in a separate cookie using encryption for the welcome message and would that be considered wrong?Promissory
Actually hosting images on an FTP would generally result in worse overall experience (for the user of the site, the web server would still be offloading the images of course so less load there) as you wouldn't benefit from caching preferences like you could from a static folder in IIS. Just their name in a cookie? Yes you can do that, so long as you don't turn around and use that to verify their identity on subsequent page loads. If it's their login name (versus a display name/alias), then you should make sure the cookie is secure/encrypted.Wheelhouse
E
3

Add this to your global.ascx

protected void Application_BeginRequest()
        {
            if (!Context.Request.IsSecureConnection)
                Response.Redirect(Context.Request.Url.ToString().Replace

("http:", "https:"));
        }

This will cause all the requestes to be converted to https instead of http

Emden answered 24/3, 2014 at 10:34 Comment(0)
H
0

I write an extension for Url.Action that generate the right protocol depending on the Attribute decooration. I let you check

public static class Extensions
{
    public static string SecuredAction(this UrlHelper helper, string action, string controller)
    {
        bool requireSSL = false;
        var route = System.Web.Routing.RouteTable.Routes.Select(r => r as System.Web.Routing.Route) .Where(r =>
            r != null && r.Defaults != null && r.Defaults["controller"] != null && r.Defaults["controller"].ToString().Equals(controller, StringComparison.InvariantCultureIgnoreCase)
            && r.Defaults["action"] != null && r.Defaults["action"].ToString().Equals(action, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault();

        if(route == null)
            return helper.Action(action, controller);

        //Get the method and check if requiere ssl
        MemberInfo method = route.DataTokens["TargetActionMethod"] as MemberInfo;
        requireSSL = method.CustomAttributes.Any(a => a.AttributeType == typeof(RequireHttps)) || method.DeclaringType.CustomAttributes.Any(a => a.AttributeType == typeof(RequireHttps));

        //Return the correct protocol
        if(helper.RequestContext.HttpContext.Request.IsSecureConnection && !requireSSL)
            return helper.Action(action, controller, null, "http");

        if (!helper.RequestContext.HttpContext.Request.IsSecureConnection && requireSSL)
            return helper.Action(action, controller, null, "https");

        return helper.Action(action, controller);
    }
}
Haemachrome answered 14/10, 2014 at 5:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.