Requiring SSL For ASP.NET MVC Controllers

There are quite a few posts out there about switching to SSL when a user visits specific areas of a website but I figure the more the merrier so here’s yet another one.

My company is in the process of rolling out an ASP.NET MVC site for a client and specific actions and controllers need to have SSL running to ensure that no sensitive information gets out such as passwords and credit cards.  If a user visits the site using http:// I need to switch them to https:// in certain parts of the website.  Fortunately, ASP.NET MVC is quite extensible so it only took about 4-5 minutes to get a simple solution in place. 

The easiest way I know of to switch to SSL for specific controllers or actions is to create an ActionFilterAttribute that handles redirecting them to an https:// address.  Classes that derive from ActionFilterAttribute can be placed immediately above actions or even controllers in cases where the filter needs to apply to all actions in the controller.  For my situation I needed entire controllers to be SSL-enabled so I placed the attribute above the controller class name.

Here’s an example of the simple RequiresSSL attribute class:

using System;
using System.Web;
using System.Web.Mvc;

namespace Helpers
{
    public class RequiresSSL : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            HttpRequestBase req = filterContext.HttpContext.Request;
            HttpResponseBase res = filterContext.HttpContext.Response;

            //Check if we're secure or not and if we're on the local box
            if (!req.IsSecureConnection && !req.IsLocal)
            {
                string url = req.Url.ToString().ToLower().Replace("http:", "https:");
                res.Redirect(url);
            }
            base.OnActionExecuting(filterContext);
        }
    }
}


A couple of people (thanks Jon and Phil) commented that the ToLower() call I had above could cause consequences with QueryString data.  I could take ToString() out but some people may type “HTTP” instead of “http” which would mess up the replace call.  For the current application I’m working on I only have integers being passed around on the QueryString so it didn’t affect me at all but it definitely could affect string data being passed.  The suggestion was to use the UriBuilder class and after thinking it through more I agree.  Here’s a different version of the RequiresSSL class that uses the UriBuilder class.

 

using System;
using System.Web;
using System.Web.Mvc;

namespace Helpers
{
    public class RequiresSSL : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            HttpRequestBase req = filterContext.HttpContext.Request;
            HttpResponseBase res = filterContext.HttpContext.Response;

            //Check if we're secure or not and if we're on the local box
            if (!req.IsSecureConnection && !req.IsLocal)
            {
                var builder = new UriBuilder(req.Url)
                {
                    Scheme = Uri.UriSchemeHttps,
                    Port = 443
                };
                res.Redirect(builder.Uri.ToString());
            }
            base.OnActionExecuting(filterContext);
        }
    }
}


The RequiresSSL attribute can then be placed above the appropriate action or controller:

[HandleError]
[RequiresSSL]
public class AccountController : Controller
{
    ...
}


If you’re running IIS7 and want to get a test SSL certificate setup for testing purposes check out my good friend Rob Bagby’s excellent post on the subject.

Published Tuesday, August 25, 2009 10:53 AM by dwahlin
Filed under: , ,

Comments

# re: Requiring SSL For ASP.NET MVC Controllers

Wednesday, August 26, 2009 10:27 AM by RichardD

Nice - but wouldn't it be better to use the UriBuilder class?

Eg: myserver/.../action

var builder = new UriBuilder(req.Url)

{

   Scheme = Uri.UriSchemeHttps,

   Port = 443

};

string url = builder.Uri.ToString();

res.Redirect(url);

# re: Requiring SSL For ASP.NET MVC Controllers

Wednesday, August 26, 2009 10:31 AM by Elane Mikels

Nice tutor. Thanks fellas

# re: Requiring SSL For ASP.NET MVC Controllers

Wednesday, August 26, 2009 3:11 PM by dwahlin

Richard,

Great suggestion...thanks.  I'm OK with going the simple route here but I haven't compared performance of String.Replace to UriBuilder.  Since this would typically be hit once to get the browser switched to https initially I don't know that it matters much though.

# re: Requiring SSL For ASP.NET MVC Controllers

Thursday, August 27, 2009 7:35 AM by Jon

Converting the url to lower case could mess up some query string parameters. For example, if you had a hashed, base-64 encoded value as a parameter. It may not happen much but something to be aware of. Using the UriBuilder would be a safer approach.

# re: Requiring SSL For ASP.NET MVC Controllers

Thursday, August 27, 2009 10:55 AM by Phil Bolduc

The main issue I have with the string.Replace() over UriBuilder, is that you are also using string.ToLower() which will modify any query string parameters. Modifying the query string parameters could have negative side effects.

# re: Requiring SSL For ASP.NET MVC Controllers

Thursday, August 27, 2009 11:39 AM by dwahlin

Jon, Phil:  That's a great point.  It's not something I've run into with my current application but definitely one of those things that could bite you without realizing it.  You've sold me on UriBuilder. :-)

# re: Requiring SSL For ASP.NET MVC Controllers

Friday, August 28, 2009 8:58 AM by aspfree.com

Nice recommend!

Continue with the nice work!