Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Implement secure ASP.NET MVC applications

0.00/5 (No votes)
26 Nov 2011 1  
This article discuss various aspects of ASP.NET MVC security and shows some tips how you can implement these elements in your applications

Table of content 

  1. Introduction 
  2. Background
  3. User Authentication 
    1. Using ASP.NET MembershipProvider for user authentication
  4. Page access control
    1. Secure application using the standard action filters
    2. Implement custom security rules 
      1. Create a custom security action filter    
      2. Handling security errors 
      3. Alternative approach - inherit authorization attribute
    3. Using third party libraries for page access control
  5. Forcing HTTPS protocols 
  6. Cross-site request forgery
    1. Preventing Cross-site request forgery attacks
  7. Preventing Cross-site scripting 
    1. XSS vulnerable code - an example
    2. Using Anti-XSS Library
  8. Conclusion 

Introduction  

When you implement security in the web applications you will need to think about lot of security details. Some of the standard features you will need to implement are:

  1. Authentication of the user,
  2. Page access control where you can decide what pages could user open, depending on his role or access rights,  
  3. Preventing security attacks.  

In this article I will discuss some security elements and show you how they can be implemented in the MVC applications.    

Background    

In the code I will implement the following security elements:

  1. Login page that login user and put the user name and role in the authentication cookie,
  2. Simulation of some custom business logic that determines whether the user can access particular,   
  3. Filter that check whether the user can access the page. If user do not have enough access it will be redirected to login page.  

This is everything that you need to have to implement access restrictions to the pages in your application, and in this code you will find a simple way to implement this using the action filters.

For the demonstration purpose, I have created few actions where I will show you how the access to the pages is controlled. Some of the pages I have placed in the code sample are:

  • /Public/Index and /Public/Login that can be opened by everyone (public access)
  • /Registered/Index and /Registered/Home where registered users and administrators can come 
  • /Administrator/Index and /Administrator/Home  that can be opened by the administrator
  • /Administrator/Denied that can be opened by administrator only but when it is opened it will throw Security Exception. This page is simulation of the case when user can access the page but some internal component has thrown security exception.

Most of these views are fairly simple - each of them just outputs one word displaying which view is called. Login page (/Public/Login) contains a form that can be used for login, and /Public/Index is a landing page that has links to all other pages as it is shown on the following figure:

SecurityFilters.png 

Also, I will use three user roles - public, registered, and administrator, which are used to demonstrate the page access control. In the code I will show you how access can be denied on some of these actions depending on the user role.  

There are also few other pages where I have demonstrated how you can prevent some security attacks - you will see more details in rest of the article. 

User authentication   

In order to secure your application you will need to enable user to login, and you will need to determine role of user.     

In this example I will use forms authentication so I will need to configure this in the web.config and set the login page. Look of the web.config is shown in the following sample:  

    <authentication mode="Forms">
      <forms loginUrl="~/Public/Login" />
    </authentication>

In this part of web.config file is defined that I will use forms authentication (meaning that I will provide form for login - in this case this will be "~/Public/Login" form).  As an alternative you can use windows authentication.     

Login form will contains two fields, where user can enter his name and a select role:  

<form method="post" action="#">
    <input type="text" name="Username" value="" />
    <select name="Role">
        <option value="">No role</option>
        <option value="Public">Public</option>
        <option value="Registered">Registered</option>
        <option value="Admin">Admin</option>     
    </select>
    <input type="submit" name="Login" value="Login" />
</form> 

This form do not have any identity check but in your application you will probably replace this with username/password, check are they match to some user details, and read the role from database. This simple simulation will be enough "security check" for this article, but if you want to see complete solution with role bases security see something like Forms Authentication and Role based Authorization: A Quicker, Simpler, and Correct Approach.  

Note that I have set the action of the form to # - this way form will be posted back to the same URL and it will included any parameter that is posted to login form. This is handy because if parameter ReturnURL="...."   is send to a login page, where ReturnURL is a URL of the origin page where user should be redirected after he successfully logins to the system. If you need to put an explicit URL in the action attribute, then it would be good to put the ReturnURL as a hidden field and pass it to the controller when login page is submitted, as it is shown in the following example:     

<form method="post" action="/Public/Login">
    <input type="hidden" name="ReturnURL" value="@System.Web.HttpContext.Current.Request["ReturnURL"]" />
    <input type="text" name="Username" value="" />
    <select name="Role">
        <option value="Public">Public</option>
        <option value="Registered">Registered</option>
        <option value="Admin">Admin</option>     
    </select>
    <input type="submit" name="Login" value="Login" />
</form>       

In this form I have just taken a value from the ReturnURL request parameter and putted it into the form's hidden field.     

The Login form will submit username and role to the action that will put username and role into the authentication cookie. Example of such kind of action is shown in the following listing:  

        public ActionResult Login(string Username, string Role, string ReturnUrl)
        {
            if (string.IsNullOrEmpty(Username))
                Username = "Unknown";//Default value that is set if nothing is entered

            var authTicket = new FormsAuthenticationTicket(1,   Username, DateTime.Now, DateTime.Now.AddMinutes(30), true, 
                                                                Role);
            string cookieContents = FormsAuthentication.Encrypt(authTicket);
            var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, cookieContents)
                                        {
                                            Expires = authTicket.Expiration,
                                            Path = FormsAuthentication.FormsCookiePath
                                        };
            Response.Cookies.Add(cookie);

            if(!string.IsNullOrEmpty(ReturnUrl))
                    Response.Redirect(ReturnUrl);

            return View("Index");
        } 

This code creates authentication cookie and puts username and role to the cookie. Details of the creating forms authentication cookie are already covered in the other articles, so if you are not familiar with this you can see more details in the Forms Authentication and Role based Authorization: A Quicker, Simpler, and Correct Approach. If return URL is provided, user will be redirected there, otherwise it will be redirected to the index page.   

Using ASP.NET Membership provider for user authentication

In the example above I have not implement any code that check is the user valid, and that takes the user details (e.g. role). However, you will need to decide where user information are placed and implement the code that read these information.

The simplest way to implement authentication is to use ASP.NET Membership provider to handle user accounts.  With Membership provider you will get all standard operations for authentication, and user management such as:

  • bool Membership.ValidateUser(string username, string password) that returns true value if username/password are valid,  
  • MembershipUserCollection Membership.GetUsersByName(string username) that search for users by username, 
  • MembershipUserCollection Membership.GetUsersByEmail(string email) that search for users by email, 
  • MembershipUser Membership.CreateUser(string username, string password) that creates new user,  
  • void Membership.UpdateUser(MembershipUser user) that updates user data, 
  • void Roles.AddUserToRole(string username, strig roleName) that associates user to role, 
  • string[] Roles.GetRolesForUser(string username) returns set of roles for user,  
  • bool Roles.IsUserInRole(string username, string roleName) check whether the user is in the particular role.

There are lot of other static methods available in the Membership and Roles classes that can be used, including a number of overloads for the methods are shown above.  

However, these classes are only an interface to the actual user storage, so you will need to bind membership provide to actual storage.

Using SqlServer membership provider 

When you use Membership provider classes, you will need to bind it to some data source where user information are placed. As an example, you can bind your Membership provider to the Sql Server database using the SqlMembershipProvider. In order to setup SqlMembershipProvider, you will need to setup connection to database where user accounts will be stored and bind provider to connection string. All these configurations can be placed in the web.config file as it is shown in the following example:

<configuration>

  <connectionStrings>
    <add name="UserDatabaseConnection"
         connectionString="CONNECTION STRING"
         providerName="System.Data.SqlClient" />
  </connectionStrings>

  <system.web>

    <membership>
      <providers>
        <clear />
        <add name="AspNetSqlMembershipProvider"
            type="System.Web.Security.SqlMembershipProvider"
            connectionStringName="UserDatabaseConnection" />
      </providers>
    </membership>
    <roleManager>
      <providers>
        <add
          name="SqlProvider"
          type="System.Web.Security.SqlRoleProvider"
          connectionStringName="UserDatabaseConnection" />
      </providers>
    </roleManager>
  </system.web>

</configuration>

You will need to define connection string to the SqlServer database were user information will be placed (it is called UserDatabaseConnection in the example above), and to add membership provider that will use this connection. If you wan to use roles associated to users for trole based security, then you will ned ti configure role manager too. There are few other parameters of the SqlMembershipProvider that can be set, but they are not shown. You can see more details about the SqlMembershipProvider parameters and configuration in the MSDN articles abotu the SqlMembershipProvider Class and SqlRoleProvider Class

SqlMembershipProvider uses predefined structure of database tables and stored procedures that must exist in the database so this provider can read/update user information. In the following figure are shown tables that are required by the SqlMembershipProvider: 

aspnet.png

If these tables are not present in the database, you will get exception when you call any of the Membership methods. Sql membership procedures/tables can be easily added in the existing database you just need to run Aspnet_regsql.exe tool - see more details about this in the Using SQL Membership with ASP.NET Application article.

Creating custom membership provider

If you do not want to use standard schema, or if you have your own data structure that you need to use, you can create your own custom membership provider. All you need to do is to inherit MembershipProvider class and implementation static membership methods you need in the application as it is shown in the following example:

public class MyMembershipProvider : MembershipProvider
{   
    public override bool ValidateUser(string username, string password)
    {
        throw new NotImplementedException();
    }

    public override MembershipUser CreateUser(string username, 
       string password, string email, string passwordQuestion, 
       string passwordAnswer, bool isApproved, 
       object providerUserKey, out MembershipCreateStatus status)
    {
        throw new NotImplementedException();
    }

    public override MembershipUser GetUser()
    {
        throw new NotImplementedException();
    }
}

Here you can put any custom code that handle user information (e.g. reading from file, LDAP, web service, etc.). I have not included details about implementation in this example because this is already explained in more details in the Custom Membership Providers article. Also, you as take a look at the Custom MembershipProvider and RoleProvider Implementations that use Web Services article where is shown how you can implement MembershipProvider and RoleProvider using the web services.  

Now lets see how we can control access to the page in this application using the action filters.  

Page access control       

Once you implement proper authentication you will need to control to what pages users can access depending on the role.     

ASP.NET MVC has one great feature that can be used to implement page access security - the action filters. The Action filters are classes that can be attached to the controllers or particular actions which contains methods that are executed before or after action is called, when error occurs etc.  Filters are usually attached to actions in the controllers using annotations, as it is shown in the following example:    

    public class PublicController : Controller
    {
        [Authorize]
        public string Home()
        {
            return "Home";
        }
    }

In this example, Authorize filter attribute is added to Home action of the Public controller. Now you cannot call this action if you are not authorized.  

You can find various usage of filters that log errors, track IP addresses, or display ads, in Creating Custom Action Filters in ASP.NET MVC- CodeGuru. In this article I will demonstrate one usage of action filters - securing your application.   

Action filters enables centralized place for managing application-wide rules - one of this rule is controlling access to your application. In this article I will create action filter that controls whether the current user have enough permission rights to call the particular controller/actions in the application.    

Secure application using the standard MVC filters  

The easiest way to implement security is to use filters that are already provided in the MVC framework. MVC comes with the number of filters that can be applied to your pages. One of the most important is [Authorize] filter. In order to force authorization one some page you can add authorize attribute on the particular action something like in the following example:  

    public class JovanController : Controller
    {
        [Authorize(Users="Jovan")]
        public string Home()
        {
            return "Home";
        }
    }     

This code will allow only user with name "Jovan" to call this controller.  

Another way to apply authorization is to put the attribute on the entire controller class, as it is shown in the following example:    

 [Authorize(Roles="Administrator")]
 public class AdministratorController : Controller
    {
        public string Home()
        {
            return "Home";
        }
    } 

In this case all actions in the controller can be called only if the user that calls actions has a role "Administrator".      

Third way is to apply global attribute that will be used in all controllers and all actions. You can apply filters globally this by adding the filter as a global filter in the RegisterGlobalFilters method of the Global.asax.cs file - example of the code is shown in the following listing:  

    public class MvcApplication : System.Web.HttpApplication
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new AuthorizeAttribute());
        }
    } 

This authorize attribute will be applied to all controllers and classes in the application.
 

Implement custom security rules    

The standard MVC filters are fine if you can hard-code roles and users in the application, but if you need to create some custom security like IP restricted access you will need to define your own filter actions.  In this application I will assume that I have one class that determines whether some user that comes from some IP address can access some particular action in some controller. For the demonstration purposes I have created the following class:

    public class PageAccessManager
    {
        public static bool IsAccessAllowed(string Controller, string Action, IPrincipal User, string IP)
        {
            if (Controller == "Public")
                return true;
            if (Controller == "Registered" && Action == "Login")
                return true;
            if (Controller == "Registered" && Action != "Login" && (User.IsInRole("Registered") || User.IsInRole("Admin")))
                return true;
            if (Controller == "Admin" && User.IsInRole("Admin"))
                return true;

            return false;
        }
    } 

This page has some custom logic that checks can some user obtain access to the certain action in the controller. In your real application you will probably create some kind of custom code that reads these rules  from the configuration files or database, but for the demo purposes this will be good enough. In this code, IP address is passed to the class but not used in the rules (although it can be easily added if needed).  

Creating a custom action filters   

Custom action filters are simple classes derived from the System.Web.MVC.FilterAttribute class which implements one of the following interfaces:

  • IAuthorizationFilter - if you want to authorize page access,
  • IActionFilter - if you wan to attach handlers before and after come action is called,
  • IResultsFilter - if you want to attach handlers before or after some result(view) is generated,  
  • IExceptionFilter - if you want to handle exceptions that occurred in actions.  

You can see more details about the usage of this custom filters in Creating Custom Action Filters in ASP.NET MVC- CodeGuru. I'm implementing custom authorization rule, so I will create filter that implements IAuthorizationFilter interface. This filter is shown in the following code:

public class SecurityFilter : FilterAttribute, IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationContext filterContext)
        {
            HttpCookie authCookie = filterContext.HttpContext.Request.Cookies[FormsAuthentication.FormsCookieName];

            if (authCookie != null)
            {
                FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
                var identity = new GenericIdentity(authTicket.Name, "Forms");
                var principal = new GenericPrincipal(identity, new string[]{ authTicket.UserData });
                filterContext.HttpContext.User = principal;
            }

            var Controller = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
            var Action = filterContext.ActionDescriptor.ActionName;
            var User = filterContext.HttpContext.User;
            var IP = filterContext.HttpContext.Request.UserHostAddress;

            var isAccessAllowed = PageAccessManager.IsAccessAllowed(Controller, Action, User, IP);
            if (!isAccessAllowed)
            {
                FormsAuthentication.RedirectToLoginPage();
            }
        }
}

This filter takes information from the authentication cookie that is populated in the login action described above and put this information in the User object in the HttpContext. Then, information about the controller, action, and IP address are taken from the context and passed to the PageSecurityManager class that will determine should the access be allowed to the user.

If access the controller's action is not allowed, user will be redirected to the login page (the one that is set in the web.config file - see code above). FormsAuthentication.RedirectToLoginPage method is useful not only because it automatically read login page from the config, but also because it puts the current URL as a ReturnURL parameter that is sent to the login page. This fit-in to the logic of the login action described above - if the current page is passed as a ReturnURL, login controller will redirect request to the current page if login is successful.

This filter can be applied on the action in one of the three ways described above:

  1. Adding the filter to individual action,   
  2. Adding the filter to individual controller,  
  3. Setting the filter globally.   

In this example I will add this filter globally as it is shown in the following code example:

    public class MvcApplication : System.Web.HttpApplication
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new SecurityFilter());
        }
    }     

Using this code, my custom security filter is applied on all actions in the application. If page access manager do not allow access to the certain controller's action login page will be shown.

Handling security errors   

Code shown above works fine if you want to deny access to the pages using one page access manager class. This way, the page/action will never be called at all. However, in your application there are other components that can deny access to the user. As an example, some code can throw security error, even if the current role has access to the page. In the code sample that you can download in this article, /Administrator/DenyAccess simulates this situation - if you are administrator you will be able to call this URL after the login, but it will immediately throw SecurityException. In that case some "access denied page" should be shown to the user. 

I will handle this situation in the same filter by implementing the IExceptionFilter interface where I will implement method that will handle exception, if the one is thrown. This code will check is the thrown exception security exception, and if is, it will redirect the user to security error page. Additional code is shown in the following listing (code for the OnAuthorization method is omitted because it is shown above):  

public class SecurityFilter : FilterAttribute, IAuthorizationFilter, IExceptionFilter
    {
        public void OnAuthorization(AuthorizationContext filterContext)
        {
            ...
        }

        public void OnException(ExceptionContext filterContext)
        {

            if (filterContext.Exception != null && filterContext.Exception is System.Security.SecurityException)
            {
                var result = new ViewResult();
                result.ViewName = "SecurityError";
                filterContext.Result = result;
                filterContext.ExceptionHandled = true;
            }
        } 

As you can see, this code receives exception that is thrown by the action, check is it SecurityException, and if it is, it shows the SecurityError view to the page. The important line is a part where ExceptionHandled property of the filterContext is set to true - this line tells the context that exception is successfully handled by this filter and that is should not propagate further.  

Using this filter, I have managed security exception on one place and applied this to all actions in the application.   

Alternative approach - Inheriting Authorization Attribute 

Alternative for filter implement is creating custom authorization attribute. In order to create a custom authorization attribute you will need to extend AuthorizationAttribute class and implement AuthorizeCore that should return true if page is authorized and HandleUnauthorizedRequest that is called when unauthorized request should be processed, as it is shown in the following example:   

public class CustomSecurityAttribute : AuthorizeAttribute
{

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {           
        return base.AuthorizeCore(httpContext);
    }

    protected override void HandleUnauthorizedRequest(AuthorizationContext context)
    {
        base.HandleUnauthorizedRequest(context);
    }
}

In the overridden method you will need to add code similar to the code above and return true/false if user have access. Code in the methods is similar to the code in custom filter so you can use any of these approaches, but it would be bests to apply it as a global filter in the Global.asax.cs file: 

 public static void RegisterGlobalFilters(GlobalFilterCollection filters)
 {
        filters.Add(new CustomSecurityAttribute());
 }

In the sample code that you can download in the article this attribute is not implemented because it is more-less copy of the previous code. Also, this line of code in commented out in the Global.asax.cs file. 

Using third party libraries for page access control  

When you implement page access security you can use some of the existing third party libraries. I will show you how you can implement page access security using the Fluent Security library.

With Fluent Security library you can programmatically set page access rules to the individual controllers/action. In the following code sample is shown how you can apply Fluent Security policies to controllers and actions.    

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
	SecurityConfigurator.Configure(configuration =>
	{
		// Let Fluent Security know how to get the authentication status of the current user
		// And let Fluent Security know how to get the roles for the current user

		// This is where you set up the policies you want Fluent Security to enforce
	});
        //Add configured attribute as a global filter
	GlobalFilters.Filters.Add(new HandleSecurityAttribute(), 0);
}    

In order to apply Fluent Security policies, you will need to attach the HandleSecurityAttribute as a global filter in the RegisterGlobalFilters method in the Global.asax.cs file.  When you attach attribute you will need to configure it first, which includes:

  1. Definition of method that will tell Fluent Security how to determine user roles,
  2. Definition of security policies that will be applied to controllers and actions.

In the first part of the configuration code you will need to define how Fluent Security library will take information about the user (e.g. is user authenticated and what are his roles). This part of code is shown in the following listing:  

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
	SecurityConfigurator.Configure(configuration =>
	{
		// Let Fluent Security know how to get the authentication status of the current user
		configuration.GetAuthenticationStatusFrom(() => HttpContext.Current.User.Identity.IsAuthenticated);

		// Let Fluent Security know how to get the roles for the current user
		configuration.GetRolesFrom(() =>
					{
						var authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];

						if (authCookie != null)
						{
							var authTicket = FormsAuthentication.Decrypt(authCookie.Value);
							return authTicket.UserData.Split(',');
						}
						else
						{
							return new[]{""};
						}
					});

		// This is where you set up the policies you want Fluent Security to enforce
	});
        //Add configured attribute as a global filter
	GlobalFilters.Filters.Add(new HandleSecurityAttribute(), 0);
}

In the code is defined that Fluent Security will determine is user authenticated and where it will find an array of user roles (from the authentication cookie in this case). Code that is used to configure access policies is shown in the following example.

The part of the configuration code that applies security policies to controllers is shown in the following listing:   

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
	SecurityConfigurator.Configure(configuration =>
	{
		// Let Fluent Security know how to get the authentication status of the current user
		// Let Fluent Security know how to get the roles for the current user

		// This is where you set up the policies you want Fluent Security to enforce
		configuration.For<PublicController>().Ignore();

		configuration.For<PublicController>(x => x.Dashboard()).RequireRole("Public");

		configuration.For<RegisteredController>(x => x.Index()).DenyAnonymousAccess();
		configuration.For<RegisteredController>(x => x.Dashboard()).RequireRole("Registered", "Admin");
		configuration.For<RegisteredController>(x => x.Home()).RequireRole("Registered", "Admin");
		configuration.For<RegisteredController>(x => x.MyAge()).RequireRole("Registered", "Admin");

		configuration.For<AdminController>(x => x.Index()).DenyAnonymousAccess();
		configuration.For<AdminController>(x => x.Dashboard()).RequireRole("Admin");
		configuration.For<AdminController>(x => x.Home()).RequireRole("Admin");
		configuration.For<AdminController>(x => x.Denied()).RequireRole("Admin");
	});
        //Add configured attribute as a global filter
	GlobalFilters.Filters.Add(new HandleSecurityAttribute(), 0);
}

Code for initialization of user roles that is explained in the previous example in not shown here. In this part of the configuration code is defined that rules should not be applied to the public controller except on the dashboard action where only user with "Public" role can access. On all index actions is denied anonymous access. In order to access actions in the registered controller user need to have "Registered" or "Admin" role, and to access Admin actions he would need to have an "Admin" role. 

Note that in the code sample that can be downloaded this attribute is commented out because custom code access security is active but you can easily comment out custom security filter and add this attribute. 

There is a number of policies that can be added to the controllers/actions such as:  

  1. DenyAnonymousAccess - The user must be authenticated. Requires no specific role. 
  2. DenyAuthenticatedAccess - The user must be anonymous. 
  3. RequireRole - The user must be authenticated with one or more of the specified roles.
  4. RequireAllRoles - The user must be authenticated with all of the specified roles.
  5. Ignore - All users are allowed.  

See more details on the fluent security web site.

Forcing HTTPS protocols  

In order to protect sensitive data you the best practice is to use HTTPS instead of the HTTP. HTTPS protocol will automatically encrypt sensitive information that are posted from the client to the server, so nobody can use network sniffers to intercept and read these information.

In MVC [RequireHttps] attribute can be used to force HTTPS. If you put this attribute on the particular action it will redirect request to https://SITE/Controller/Action URL if it is called with http://SITE/Controller/Action. This is useful if you want to make sure that some actions must be executed via HTTPS protocol instead of the plain HTTP. An example is shown below:

    public class PublicController : Controller
    {
        [RequireHttps]
        public string Login()
        {
            return View();
        }
    }    

If you try to call login page using http://..../Public/Login, you will be immediately redirected to the HTPS version of the page https://..../Public/Login where you can enter login details.

Note that HTTPS needs to be configured on the IIS in order to make this work (it is not enabled by default).  

Cross-site request forgery 

Cross-site request forgery attack is a kind of attack where external site/script exploits the user identity information stored in the browser (e.g. cookies).

Let assume that you are accessing your bank site and in the same time you are browsing other sites (e.g. in another tab). You are logged in to your banks site, authenticated and your authentication information are placed in the browser cookies. At the same time you have opened some page on another site www.evil.com in the second tab. In that case you will access two servers at the same time as it is shown in the following figure: 

CSRF.PNG

Imagine that you have opened some page on the second site (www.evil.com) where is placed some form with an action attribute that points to your bank site, and that have some script that immediately submits the form. Once you load this page from the evil site it will post request from your browser to your bank site. This request will take all authentication cookies from the browser, and your bank server will not know whether this call is performed via first tab(regular usage) or second tab(request forgery attack), so it will authenticate this malicious request and accept it. In this case, the script might clean your account.

Preventing cross-site request forgery attacks 

As an example I have added one dummy link on the page that post request to the /Registered/MyAge action and set the age to 0. 

<a id="CSFR">Click me to reset your age!!!!</a>

<script type="text/javascript">
    $("#CSFR").click(function () {
        $.ajax({
            url: "/Registered/MyAge",
            data: { age: "0" },
            type: 'POST',
            success: function () { alert("Attack succeeded");  },
            error: function () { alert("Attack failed"); }
        });
    });
</script>

If you click on the link, your age will be reset to 0 although you didn't wanted this, because this request sends cookies to server. The same thing would happen if this script is on the another site that you have opened in another tab (however in that case url parameter in the Ajax code will need to have direct URL to you application). MVC enables you to protect your pages from the CSRF attacks by adding the token on the page that will be checked on the server-side.  Example of the token that is added to the MyAge view is shown in the following code:

<form action="/Registered/MyAge" method="post">
  @Html.AntiForgeryToken()
  My Age:<input type="text" name="age" value="@Model" />
  <input type="submit" name="Save" value="Save" />
</form>
In the controller should be added [ValidateAntiForgeryTokenAttribute] attribute that checks whether the anti-forgery token exists in the request, as it is shown in the following example:
        [ValidateAntiForgeryTokenAttribute]
        public ActionResult MyAge(string age)
        {
            Session["age"] = age;
            return View(Session["age"]);
        }
If token is not sent in the request call will fail. If you try to click on the link you will get the error message. However, if you try to remove this token and attribute, Ajax call will succeed and your age will be reset. 

Preventing Cross-site scripting     

Cross site scripting occurs when someone enters potentially dangerous tags that executes some JavaScript. Example of the potentially dangerous script that can be injected in the page is shown in the following listing:    

<script>alert("hello");</script>

Instead of the simple alert here can be added any other script that takes your cookies, send them to some third party site, inject some ads in the page etc. MVC enables automatic protection of your code against the XSS attacks using the following rules:

  1. Any content that is placed on the pages is automatically HTML encoded so if you have some potentially dangerous script it will be shown as text.
  2. If request contains any potentially dangerous script in any parameter error will be returned back.    
 However in most cases you will need to turn off this default validation. Examples are:
  1. In CMS system raw HTML is placed in database and it should be shown to the user as HTML because it contains different formatting,
  2. If you are using any HTML WYSIWYG editor (e.g. TinyMCE, XStandard) that enables user to format text you will need to disable HTML validation because you know that you want to receive HTML from the browser.   
In the following example I will show you what could happen if you turn-off default validation and how can you implement some trade-off.

XSS vulnerable code  - An example  

In this section I will show you one example of the XSS vulnerable code. Lets assume that we need to create page that enables user to enter his profile. Also, I will assume that profile has a rich format so it need to allow HTML formatting. To implement this we will need to create two following actions:   

public class RegisteredController : Controller
{
    [HttpGet]
    public ActionResult Profile()
    {
        var age = Convert.ToString(Session["profile"]);
        return View(Session["profile"]);
    }

    [HttpPost]
    [ValidateInput(false)]
    public ActionResult Profile(string profile)
    {
        Session["profile"] = profile;
        return View(Session["profile"]);
    }
}

Get action shows user profile from the session, and post action write it back to session. Note that I have to place ValidateInput(false) attribute in order to prevent MVC framework to throw "Potentially dangerous request" exception when he finds HTML code in the profile.

View for this action is shown in the following listing: 

@model string

<h2>Profile</h2>
<p>@Html.Raw(Model)</p>

<h3>Update profile</h3>
<form action="/Registered/Profile" method="post">
    Profile:<textarea id="profile" name="profile" rows="10" cols="40">@Model</textarea>
    <input type="submit" name="Save" value="Save" />
</form>

This view displays profile as a HTML and allow user to update profile (In the real example I would user TinyMCE editor instead of the plain text area. Note that I have need to place Html.Raw because in order to prevent MVC to automatically encode model content. Html.Raw will display it as a raw HTML code.     

Setting the ValidateInput(false) makes this code vulnerable to the XSS attacks. If user enters something like a following text:    

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"
	type="text/javascript"></script>
<style type="text/css">
.red { color: red }
</style>
<hr />
<h2 id="title">Hello</h2>
<input type="text" name="keyword" id="keyword" data-rel="Custom"/>
<p style="border:solid">This is some <b>Profile</b>  <em>text</em>. <br/>
Validate Input <u>must be disabled</u>
<img src="http://i.msdn.microsoft.com/Areas/Sto/Content/Images/ShareThis/email.gif" />
in order to <span class="red">display</span> formatted text.</p>
<img alt="Hello" src="javascript:alert('Hello from image source')"  
		onload="javascript:alert('Hello after load')"
		onclick="javascript:alert('Hello after click')"/>
<script>alert("hello");</script>
<hr/>

You will see alert once you reload the view because there is potentially dangerous JavaScript tat has passed .Net validation. Now we have disabled strict .NET validation, but we have opened the door for various script attacks. Although input cannot be validated in order to accept HTML code there should be some validation that prevents dangerous code.  

Anti-XSS Library     

Microsoft's Anti-XSS library will enable you to clean posted HTML code with more intelligent rules than rejecting request that have any HTML tag. You can download Anti-XSS library from here,  and XSS libraries are included in the code sample.

If you want to clean HTML input taken from the user you can use GetSafeHtmlFragment method of the Sanitizer class (in the version 3.1 this method was placed in the AntiXSS class, but it is moved since 4.0): 

[HttpPost]
[ValidateInput(false)]
public ActionResult Profile(string profile)
{
      Session["profile"] = Sanitizer.GetSafeHtmlFragment(profile);
      return View(Session["profile"]);
}

This call will remove potentially dangerous tags (e.g. <script>) from the input text and leave just safe ones. If you want to store original HTML in the database or you cannot control input, other  solution might be to encode it directly in the view:  

@model string

<h2>Profile</h2>
<p>@Html.Raw(Sanitizer.GetSafeHtmlFragment(Model))</p>

<h3>Update profile</h3>
<form action="/Registered/Profile" method="post">
    Profile:<textarea id="profile" name="profile" rows="10" cols="40">@Model</textarea>
    <input type="submit" name="Save" value="Save" />
</form>

In this example unsafe HTML is encoded in plain text, but left as original in the text area so user can change it. GetSafeHtmlFragment method will make following changes to HTML:

  1. Any script tags will be removed  (both references and inline scripts)
  2. Inline CSS styles will be wrapped with <!-- and -->  
  3. Inline CSS classes and values for the id, class, and name attributes will get prefix x_
  4. Custom attributes will be removed (e.g. data-rel)   
  5. Potentially dangerous attributes will be removed (onload, onclick in the image tag)

When you get safe html using the Sanitizer class from the dangerous HTML source shown in the previous section you will get the following result: 

<style type="text/css">
<!--
.x_red
	{color:red}
-->
</style>
<div>
<hr>
<h2 id="x_title">Hello</h2>
<input type="text" name="x_keyword" id="x_keyword">
<p style="border:solid">This is some <b>Profile</b> <em>text</em>. <br>
Validate Input <u>must be disabled</u> <img src="http://i.msdn.microsoft.com/Areas/Sto/Content/Images/ShareThis/email.gif"> in order to
<span class="x_red">display</span> formatted text.</p>
<img alt="Hello" src="">
<hr>
</div>

As you can see, HTML is safe now - all dangerous code is removed. However, code is little bit messed because Sanitizer class modifies inline classes and values for name, id, and class attributes by adding the prefix "x_" (at least in this version). This is reported as an issue on Anti-XSS site but it is still not resolved. If this is a problem to you you will need to manually remove prefixes - I'm using the following code:    

            Session["profile"] = Sanitizer.GetSafeHtmlFragment(profile)
                                            .Replace("=\"x_","=\"")
                                            .Replace(".x_", ".");

I have replaced each ="x_ occurrence with =" to revert the fix made by Sanitizer in attributes, and any occurrence of .x_ with . in order to revert unwanted fixes in classes. The only remaining inconvenience is that custom HTML5 attributes such as data-rel, data-text are removed and cannot be reverted. I hope that this will be fixed in some future release of Sanitizer.     

If you will use AntiXSS library here are few tips for you:  

  1. Do not call Sanitizer.GetSafeHtmlFragment() directly - create your own class that will wrapp it. GetSafeHtmlMethod is moved from AntiXSS class in version 3.1. to Sanitizer class in 4.0 so it would be better to wrap this in your code and end up with less changes.   
  2. If you are using .Net 4, you can replace default encoder with the the custom one that will automatically sanitize output. This is already covered in the Using AntiXss As The Default Encoder For ASP.NET 

Conclusion      

In this article I have shown some basic security elements in the MVC applications such as:
  1. User authentication  
  2. Page access control   
  3. Script attack prevention    
  4. Cross-site request forgery prevention. 

I believe that you can easily modify this code and apply it in your applications. Note that code in the sample is not 100% identical to the examples shown in the article. You will need to switch on/off some parts of code, but I believe that you will be able to adjust it easily and run these examples. As an example, in the current code is turned on custom filter security and commented out Fluent security but you will be able to change this.

If you have any idea about security that might be included here let me know and I will update this article.   

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here