开发者

MVC RequireHttps entire site

I have read the previous posts about usin开发者_JS百科g the RequireHttpsAttribute to secure individual controllers:

ASP.NET MVC RequireHttps in Production Only

but is there a way to apply this to the entire site? Due to my host (discountasp.net) I cannot use the "RequireSSL IIS" setting.


Register the RequireHttpsAttribute as a global filter.

In global.asax:

protected void Application_Start()
{
    GlobalFilters.Filters.Add(new RequireHttpsAttribute());

    //... other stuff
}


I ended up using IIS URL Rewrite 2.0 to force the site to switch to HTTPS. This code in web.config does the trick:

  <system.webServer>
    <!-- This uses URL Rewrite 2.0 to force the entire site into SSL mode -->
    <rewrite xdt:Transform="Insert">
      <rules>
        <rule name="Force HTTPS" enabled="true">
          <match url="(.*)" ignoreCase="false" />
          <conditions>
            <add input="{HTTPS}" pattern="off" />
          </conditions>
          <action type="Redirect" url="https://{HTTP_HOST}/{R:1}" appendQueryString="true" redirectType="Permanent" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>


You could always add a check at the application level in your global.asax

protected void Application_BeginRequest(Object sender, EventArgs e)
{
   if (!HttpContext.Current.Request.IsSecureConnection)
   {
    Response.Redirect("https://" + Request.ServerVariables["HTTP_HOST"]
                                 + HttpContext.Current.Request.RawUrl);
   }
}


Just to bring this answer upto date for MVC 3 and above use the following in your Filterconfig.cs file within the App_start folder

        filters.Add(new RequireHttpsAttribute());

Obviously you will need your servers IIS configured to use a valid SSL certificate, cheap certs can be purchased here: https://www.namecheap.com/ i think the last time i purchased one it was $9 per domain per year.


In your FilterConfig.cs apply this:

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
     // only if Debug is not enabled, do not require https for local development
     if (!HttpContext.Current.IsDebuggingEnabled)
          filters.Add(new RequireHttpsAttribute());

     //... any other filters
}

That should force your app to use https on every page.


This isn't using RequireHttps but I think it's a better solution because it catches the redirect sooner in the MVC Lifecycle.

public class RedirectModule : IHttpModule
{
    private HttpApplication _context;

    public void Init(HttpApplication context)
    {
        _context = context;
        _context.PostResolveRequestCache += HttpRedirect;
    }

    public void HttpRedirect(Object src, EventArgs args)
    {
        if (_context.Request.Url.Scheme == Uri.UriSchemeHttp)
        {
            //Redirect to https
            var scheme = Uri.UriSchemeHttps + "://";
            var authority = _context.Request.Url.Authority;
            var url = _context.Request.RawUrl;

            var redirectTo = scheme + authority + url;
            _context.Response.PermanentRedirect(redirectTo);
        }
    }

    public void Dispose() { }
}

The idea came from this article.

You can register the module in your Web.config or inside the Global.asax. I'll show you in the web.cofig.

<system.webServer>
    <modules>
        <add name="ConfigModuleName" type="Your.Namespace.RedirectModule"/>
    </modules>
</system.webServer>


MVC 6 (ASP.NET Core 1.0) works slightly different in it's way of registering filters:

Startup.cs - AddMvc with filter for RequireHttpsAttribute:

public void ConfigureServices(IServiceCollection services)
{
    // TODO: Register other services

    services.AddMvc(options =>
    {
        options.Filters.Add(typeof(RequireHttpsAttribute));
    });
}

Design decisions explained:

  1. Use filter in Startup.cs for global setup (since we want this to apply everywhere). Startup should be responsible for registering and setting up all global rules. If your company employ a new developer, she would expect to find global setup in Startup.cs.
  2. Use RequireHttpsAttribute logic since it's proven (by Microsoft). Never use "magical" strings like "http://" and "https://" when it can be avoided by reusing a Microsoft component created to provide the same logic.

If you are running your MVC website in localhost without SSL:

  • http://localhost:1337/ (no SSL)
  • https://localhost:1337/ (SSL)

Consider looking at how to run without SSL in localhost while still requiring https it in production.

Note:

As an alternative, we could make a "class BaseController : Controller" and make all our controllers inherit from "BaseController" (instead of Controller). Then we only have to set the attribute 1 global place (and don't need to register filter in Startup.cs).

Some people prefer the attribute style.

Example of usage:

[RequireHttpsAttribute]
public class BaseController : Controller
{
    // Maybe you have other shared controller logic..
}

public class HomeController : BaseController
{
    // Add endpoints (GET / POST) for Home controller
}


In Global.asax.cs, use "RegisterGlobalFilters" to register global attributes.

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new RequireHttpsAttribute());
    //e.g. filters.Add(new HandleErrorAttribute());
    //e.g. filters.Add(new System.Web.Mvc.AuthorizeAttribute());            
}


You could use a base class for all of your controllers, and decorate that with the require ssl attribute.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜