ASP.NET MVC RequireHttps in Production Only

43,689

Solution 1

This won't help if you run Release builds on your development workstation, but conditional compilation could do the job...

#if !DEBUG
[RequireHttps] //apply to all actions in controller
#endif
public class SomeController 
{
    //... or ...
#if !DEBUG
    [RequireHttps] //apply to this action only
#endif
    public ActionResult SomeAction()
    {
    }

}

Update

In Visual Basic, attributes are technically part of the same line as the definition they apply to. You can't put conditional compilation statements inside a line, so you're forced to write the function declaration twice - once with the attribute, and once without. It does work, though, if you don't mind the ugliness.

#If Not Debug Then
    <RequireHttps()> _
    Function SomeAction() As ActionResult
#Else
    Function SomeAction() As ActionResult
#End If
        ...
    End Function

Update 2

Several people have mentioned deriving from RequireHttpsAttribute without providing an example, so here's one for you. I think that this approach would be much cleaner than the conditional compilation approach, and it would be my preference in your position.

DISCLAIMER: I haven't tested this code, even a little bit, and my VB is fairly rusty. All I know is that it compiles. I wrote it based on the suggestions of spot, queen3, and Lance Fisher. If it doesn't work, it should at least convey the general idea, and give you starting point.

Public Class RemoteRequireHttpsAttribute
    Inherits System.Web.Mvc.RequireHttpsAttribute

    Public Overrides Sub OnAuthorization(ByVal filterContext As  _
                                         System.Web.Mvc.AuthorizationContext)
        If IsNothing(filterContext) Then
            Throw New ArgumentNullException("filterContext")
        End If

        If Not IsNothing(filterContext.HttpContext) AndAlso _
            filterContext.HttpContext.Request.IsLocal Then
            Return
        End If

        MyBase.OnAuthorization(filterContext)
    End Sub

End Class

Basically, the new attribute just quits out instead of running the default SSL authorization code, if the current request is local (that is, you're accessing the site through localhost). You can use it like this:

<RemoteRequireHttps()> _
Public Class SomeController

    <RemoteRequireHttps()> _
    Public Function SomeAction() As ActionResult
        ...
    End Function

End Class

Much cleaner! Provided my un-tested code actually works.

Solution 2

If anyone needs the C# version:

using System;
using System.Web.Mvc;

namespace My.Utils
{
    public class MyRequireHttpsAttribute : RequireHttpsAttribute
    {
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException("filterContext");
            }

            if (filterContext.HttpContext != null && filterContext.HttpContext.Request.IsLocal)
            {
                return;
            }

            base.OnAuthorization(filterContext);
        }
    }
}

Solution 3

Deriving from RequireHttps is a good approach.

To side step the issue entirely, you can use IIS on your local machine with a self-signed certificate too. IIS is faster than the built-in webserver, and you have the advantage that your development environment is more like production.

Scott Hanselman has a great resource on a few ways to implement local HTTPS with VS2010 and IIS Express.

Solution 4

Leveraging the MVC filter system and Global.asax.cs, I'm assuming you could do this...

    protected void Application_Start()
    {
      RegisterGlobalFilters(GlobalFilters.Filters);
    }

    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
      filters.Add(new HandleErrorAttribute());
      if(Config.IsProduction) //Some flag that you can tell if you are in your production environment.
      {
        filters.Add(new RequireHttpsAttribute());
      }
    }

Solution 5

As it was the ASP.Net Development Server that caused your problem in the first place, it's worth noting that Microsoft now has IIS Express, which ships with Visual Studio (since VS2010 SP1). This is a cut-down version of IIS that is as easy to use as the Development Server, but supports the full feature set of IIS 7.5 including SSL.

Scott Hanselman has a detailed post on working with SSL in IIS Express.

Share:
43,689
Zack Peterson
Author by

Zack Peterson

Specializes in the design and creation of web and desktop applications. Contributes in all aspects of the software development process such as: requirements analysis and product definition; prototyping; choosing architecture and framework; interface design; database design; installation and integration; documentation and training; gathering feedback; and maintenance.

Updated on November 04, 2020

Comments

  • Zack Peterson
    Zack Peterson over 3 years

    I want to use the RequireHttpsAttribute to prevent unsecured HTTP requests from being sent to an action method.

    C#

    [RequireHttps] //apply to all actions in controller
    public class SomeController 
    {
        [RequireHttps] //apply to this action only
        public ActionResult SomeAction()
        {
            ...
        }
    }
    

    VB

    <RequireHttps()> _
    Public Class SomeController
    
        <RequireHttps()> _
        Public Function SomeAction() As ActionResult
            ...
        End Function
    
    End Class
    

    Unfortunately, ASP.NET Development Server doesn't support HTTPS.

    How can I make my ASP.NET MVC application use RequireHttps when published to the production environment, but not when run on my development workstation on the ASP.NET Development Server?

  • Joel Mueller
    Joel Mueller over 14 years
    Thanks for, um, editing my post for me, Zack. Your question was in C#, so I posted a C# response. I didn't know VB was relevant. Anyone know if there is a way to use conditional compilation to control attributes in VB, or is that just not possible?
  • Joel Mueller
    Joel Mueller over 14 years
    Yes, it works for C#, and it works for VB too, but you have to do some rather ugly duplication of the function/class definition. See my updated answer above.
  • Zack Peterson
    Zack Peterson over 14 years
    Sorry. VB code samples are getting harder and harder to come by. I didn't think it would matter. I've updated the original question. Do conditional compilation around attributes work for sure in C#? I haven't tested. That seems like a perfect, elegant solution.
  • Zack Peterson
    Zack Peterson over 14 years
    Your RemoteRequireHttpsAttribute code works perfectly. That's much more elegant for VB than the conditional compilation. Thanks again Joel.
  • aruno
    aruno about 13 years
    ya - until you try to do port forwarding with a Mifi wifi Verizon device and find that port 443 is not available to forward!!! #*&#*&$
  • aruno
    aruno about 13 years
    how can filterContext ever be null? is this just your defensive programming standards - or is there ever a reason?
  • Joel Mueller
    Joel Mueller about 13 years
    That's me not knowing much about the context in which this code might be invoked, so I thought I'd play it safe. Feel free to leave the null check out...
  • davecoulter
    davecoulter about 13 years
    Thanks-- this was exactly what I needed. Cheers!
  • davecoulter
    davecoulter about 13 years
    What I don't like about using IIS on your local machine with a self-signed certificate is that I have to go through an extra step of deployment to test changes. I think that if you are testing something related to security than it makes sense, but say if you are just checking some other minor change, it is a pain to have to deploy just to get around Cassini's inability to support HTTPS.
  • tvanfosson
    tvanfosson almost 13 years
    Or you can just conditionally add it to the global filter collection when the request is local. Note that you'll want to check this in a try/catch block if the app is set to start up immediately since the request may not be available.
  • Erik Funkenbusch
    Erik Funkenbusch over 12 years
    @davecoulter - Use IIS express on client versions of windows, no cassini needed and it will work exactly like IIS, including having ssl capability.
  • davecoulter
    davecoulter over 12 years
    @Mystere Man - yeah, I did find that out since that comment. Thanks for the tip :)
  • Ranjith Kumar Nagiri
    Ranjith Kumar Nagiri over 10 years
    i am getting this error: XMLHttpRequest cannot load m.XXX.com/Auth/SignIn. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'm.XXX.com' is therefore not allowed access.
  • stephenbayer
    stephenbayer over 9 years
    more information or link should be added on how to go about doing such things.
  • Shaiju T
    Shaiju T over 8 years
    ok when reading this and this as a security measure should we add filters.Add(new MyRequireHttpsAttribute ()); in FilterConfig ?
  • Nick Niebling
    Nick Niebling almost 8 years
    Based on this answer I created a solution for MVC 6 using either filter in Startup.cs or attribute style on Controller.
  • MWD
    MWD over 7 years
    This is a easy solution that works great in MVC 5 :)
  • Abdulhameed
    Abdulhameed over 4 years
    I prefer this answer as it involves one check per application lifetime rather than implementing a new filter that's going to be executed\called with every single request.