ASP.Net MVC: Partially Secured Sites / Switching from HTTPS back to HTTP

Most sites out there have some portions that should be only served via HTTPS, while the remainder can be HTTP, such as account pages and content pages respectively.  This is sometimes called a “partially secured site.”

Starting with MVC 2, you could decorate controllers and actions with the RequireHttps attribute, which would redirect non-secure GET requests to HTTPS.  Unfortunately, once you are in HTTPS, you won’t automatically switch back to HTTP for those actions that do not require it.

To do that, you can override OnActionExecuting in your base controller (to save you from having to reimplement the call in each of your actual controllers) and redirect the user.

Here’s the code

 
[RequireHttps]
public ActionResult MySslAction()
{
// HTTPS
}
 
public ActionResult MyNonSslAction()
{
// HTTP
}
 
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext.Request.IsSecureConnection && !filterContext.ActionDescriptor.IsDefined(typeof(RequireHttpsAttribute), true))
{
// redirect to un-secured page
string url = "http://" + filterContext.HttpContext.Request.Url.Host + filterContext.HttpContext.Request.RawUrl;
filterContext.HttpContext.Response.Redirect(url);
}
 
base.OnActionExecuting(filterContext);
}
This entry was posted in ASP.Net, C#, MVC. Bookmark the permalink.

2 Responses to ASP.Net MVC: Partially Secured Sites / Switching from HTTPS back to HTTP

  1. Eric Carr says:

    This will result in an endless loop if a Controller has [RequiresHttps], so I’ve modified your code slightly to check the Controller as well (passing false to not check up the chain) as such:


    static Type _t = typeof(RequireHttpsAttribute);

    protected override void OnActionExecuting(ActionExecutingContext filterContext)
    {
    if (filterContext.HttpContext.Request.IsSecureConnection &&
    !filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(_t,false) &&
    !filterContext.ActionDescriptor.IsDefined(_t, true))
    {
    // redirect to un-secured page
    string url = "http://" + filterContext.HttpContext.Request.Url.Host + filterContext.HttpContext.Request.RawUrl;
    filterContext.HttpContext.Response.Redirect(url);
    }

    base.OnActionExecuting(filterContext);
    }

  2. Greg says:

    I found a better way that seems more in tune with ASP.Net MVC filtering. Instead of allowing the action to continue to execute, redirecting back to HTTP from HTTPS is better suited to be an AuthorizationFilter. This happens before the action is executed so you won’t perform the action twice (and helps with logging so you don’t see a “double audit” of the action). Here’s the implementation:

    [cc lang=”csharp”]

    [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
    public class NoRequireHttpsRedirectAttribute : FilterAttribute, IAuthorizationFilter
    {
    protected static Type RequireHttpsType = typeof(RequireHttpsAttribute);

    public void OnAuthorization(AuthorizationContext filterContext)
    {
    if (filterContext == null)
    {
    throw new ArgumentNullException(“filterContext”);
    }

    HttpRequestBase request = filterContext.HttpContext.Request;
    ActionDescriptor descriptor = filterContext.ActionDescriptor;
    if (request.IsSecureConnection
    && request.Url != null
    && String.Equals(request.HttpMethod, “GET”, StringComparison.OrdinalIgnoreCase)
    && !descriptor.ControllerDescriptor.IsDefined(RequireHttpsType, false)
    && !descriptor.IsDefined(RequireHttpsType, true))
    {
    // redirect to un-secured page
    string url = “http://” + request.Url.Host + request.RawUrl;
    filterContext.Result = new RedirectResult(url);
    }
    }
    }

    [/cc]

Leave a Reply

Your email address will not be published. Required fields are marked *