Securing your MVC Application

Executive Overview

You cannot use routing or web.config files to secure your MVC application. The only supported way to secure your MVC application is to use a base class with an [Authorize] attribute,  and then have each controller type subclass that base type.

What’s the best way to secure a MVC application from anonymous users? A customer on the MVC Forum asked this question. Several of the responses where so horrifyingly wrong that I immediately deleted them. The first suggestion was the traditional ASP.NET WebForms approach; add a web.config to the folder you want to restrict. MVC uses routes and does not map URLs to physical file locations like WebForms, PHP and traditional web servers. Therefore using web.config will definitely open a security hole in your site.

The second suggestion was restriction of routes via route constraints. One of the tenants of the MVC pattern is maintainability. Even if you could prove a simple MVC application was secure via routes, any new methods or controllers added to the application would compound the complexity of proving your application is secure. Levi (the security expert on the MVC team) wrote:

Do not use a route constraint!

Let me be perfectly clear on this. The only supported way of securing your MVC application is to have a base class with an [Authorize] attribute, and then to have each controller type subclass that base type.  Any other way will open a security hole.

In general, it's extremely difficult to figure out all of the possible controllers that a particular route can hit.  Even if you think that a route can be used only to hit one particular controller or group of controllers, a user can probably feed some set of inputs to the system and direct it to a controller it wasn't intended to hit.

This is why we say that Routing should never be used to make a security decision.  Routing is essentially a communication channel with your application; it's a way to make your URLs pretty.  Because the controller is the resource you're actually trying to protect,  any security decisions should be done at the controller level rather than at the route level.  And currently the only way to associate a security decision with a controller is to slap an [Authorize] attribute on it (or another similar attribute that you write that subclasses it).

For example, assume you have a FooController inside your Blog area.  Normally, you would access this via /Blog/Foo/Action.  However, with the default {controller}/{action}/{id} route, you could also probably access this using just /Foo/Action (without the Blog prefix).  You may or may not be able to repro this on your own machine depending on your route configuration, but it's one of many examples.

Additionally, what happens if in a theoretical future version of MVC we add a handler MvcActivation.svc that is specifically meant to make your MVC application easier to consume by a WCF client?  Because this wouldn't go through routing at all, any decisions made at the routing level would not affect this.  Remember, the controller is the resource you want to protect.  It doesn't matter how you get there —via a route, a WCF activation path, or some other external component calling into the controller directly—the controller should secure itself.

You can read most of the original thread here (a few posts were deleted to protect the innocent). Thanks to Levi for explaining this.