Sunday, September 9, 2012

Prevent Cross-Site Request Forgery (CSRF) in MVC web application using AntiForgeryToken() helper


Cross-site scripting (XSS) is the number one security issue on the web. Your application can be vulnerable to cross-site request forgery (CSRF) attacks not because you the developer did something wrong, but simply because of how the whole Web is designed to work. Basically web browsers allow GET and POST requests to be made between different web sites. Cross-site request forgery (CSRF) occurs when a user visits a malicious web page that makes their browser send requests to your application that the user did not intend. This can be done with the src attribute of the IMG, IFRAME or other tags and more complicated requests, including POSTs, can be made using JavaScript. Because the browser always sends the relevant cookies when making requests, requests like this appear to originate from an authenticated user. The malicious site isn’t able to see the results of these requests, but if create, update or delete functionality can be triggered; the malicious site may be able to perform unauthorized actions.

Example of CSRF works:

Here is your controller class (“ResultsController”). The user goes to Index(), which renders the form. Now they post that form to view the results ([HttpPost] method), which can do some useful staff i.e., modify user details, bank accounts details etc. Still now all looks good.

public class ResultsController : Controller
{
    //
    // GET: /Results/
    public ActionResult Index() { return View(); }

    [HttpPost]
    public ActionResult Index(ResultsModel model)
    {
        //do some staff
        return View(model);
    }
}

But that controller is easily target for CSRF. How? Let’s check the html generated by the controller below.

<form method="post" action="/results">
   User name: <input type="text" value="someusername" name="UserName" id="UserName"/>
   Email address: <input type="text" value="email@email.com" name="Email" id="Email"/>
  <input type="submit" value="Update">
</form>
   


The following shows the “HTTP POST” that is sent to the website (URL: http://localhost:51582/results). Here you can notice the following things:
  • We are posting to a well known URL, with or without sending a cookie.
  • .ASPXAUTH, which lets the site know that user is already logged in or not
  • We are posting some data (UserName=someusername&Email=email%40email.com)
The code is very much simple. Just creating a form and posting the data to do some useful works. So why we are fighting for CSRF? Now check below. Another guy can write the following piece of code:

<html>
<head>
    <title></title>
</head>
<body>
    <form method="post" name="csrf" action="http://localhost:51582/results">
    <input type="hidden" name="UserName" value="someusername" />
    <input type="hidden" name="Email" value="hereis@your.email" />
    </form>
    <script type="text/javascript">
        document.csrf.submit();
    </script>
</body>
</html>

That person just did nothing only create a HTML page hosted somewhere in the world with two input types, the same values and write a small script to post the form and he can successfully update those things.

How to block CSRF:

We can do the following things:

  • We can check the incoming request's “Referer” header to prevent this attack. That posted HTML is exactly the same as the form is created except the “Referer” because it is hosted somewhere in the world not in that server. But some proxy server, some people can disable their browser’s “Referer” header for privacy. So this is not a good solution at all.
  • We can put a token as a hidden filed inside the form & then check that the correct value was submitted or not. It is good to use a random generated value while submitting the form. So that third party cannot forge the valid form post.

The AntiForgeryToken helpers:

ASP.Net MVC introduces html helpers to detect and block CSRF using tokens. AntiForgeryToken is built in validation and simple to add in the form (it is a hidden input element with token). We need to add an @Html.AntiForgeryToken() into the form.

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    <div>
        UserName: @Html.TextBoxFor(m => m.UserName)
        Email: @Html.TextBoxFor(m => m.Email)
    </div>
    <input type="submit" value="Update" />  
}

This will generate a token and writes it inside the form. HTML will be like this:

<form method="post" action="/results">
<input type="hidden" value="TKjmpi-KfyhZZf79x-v0BzIN6W-hDL9DhUAZJE5RffDw6ZRDGMPajlrGWSV8a7oP5oXrNXGw1riZ7FE86CO3to6i2rfpZ6_KoAHWEOUCwmFlL6-beCKZYKbf1pxL3xLnnEQ4qrTggZoDrxwPrB0AeEFeu8wJukwL0SB2iwi55oU1"
    name="__RequestVerificationToken">
<div>
    UserName: <input type="text" value="" name="UserName" id="UserName">
    Email: <input type="text" value="" name="Email" id="Email">
</div>
<input type="submit" value="Update">
</form>

This (AntiForgeryToken) generated a visitor cookie name “__RequestVerificationToken”, with the same value as the random hidden value.



Now, to validate the incoming form post, need to add the “[ValidateAntiForgeryToken]” to your action method.

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(ResultsModel model)
{
    //do some staff
    return View(model);
}

This will validate the token, when the form post is submitted, compares the cookie value to the submitted verification token.

The simple and excellent mechanism of AntiForgeryToken:

a.  The server writes tokens to cookie and inside the form.b. When the form is submitted to server, token in cookie and token inside the form are sent in the HTTP request.c. Server validates the tokens.

Multiple forms in application & wrapper class:

To protect multiple forms in one controller we can easily avoid a large number of “[ValidateAntiForgeryToken]” attributes. We can use the following wrapper class, where HTTP verbs can be specified:

 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class ValidateAntiForgeryTokenWrapperAttribute : FilterAttribute, IAuthorizationFilter {
   private readonly ValidateAntiForgeryTokenAttribute _validator;
   private readonly AcceptVerbsAttribute _verbs;
   public ValidateAntiForgeryTokenWrapperAttribute(HttpVerbs verbs)
         : this(verbs, null) { }

   public ValidateAntiForgeryTokenWrapperAttribute(HttpVerbs verbs, string salt) {
       this._verbs = new AcceptVerbsAttribute(verbs);
       this._validator = new ValidateAntiForgeryTokenAttribute() { Salt = salt };
   }

   public void OnAuthorization(AuthorizationContext filterContext) {
       string httpMethodOverride = filterContext.HttpContext.Request.GetHttpMethodOverride();
       if (this._verbs.Verbs.Contains(httpMethodOverride, StringComparer.OrdinalIgnoreCase))
       { this._validator.OnAuthorization(filterContext); }
   }
}

We can call that like following:

[ValidateAntiForgeryTokenWrapper(HttpVerbs.Post)]
public class ResultsController : Controller
{
// All GET: actions, which are not affected.
// All POST: actions, those requests are validated.
}

Add the token in the AJAX request:

When AJAX Post, we can include the verification token manually. We can simply add the parameter “__RequestVerificationToken” with the token from the form as follow:

    $.ajax({
        type: "POST",
        url: URL, //this will be the url
        data: { value: value, __RequestVerificationToken: getVeryficationToken() },
        success: function (result) {
            // Success
        }
    });

    function getVeryficationToken() {
        var inputElements = $("input");
        for (var i = 0; i < inputElements.length; i++) {
            var inputElement = inputElements[i];
            if (inputElement.name === "__RequestVerificationToken") {
                return inputElement.value;
            }
        }
        return null;
    }

Some helpful articles:

Saturday, September 8, 2012

ASP.NET MVC4: Bundling and Minification


One of the new features in ASP.NET MVC 4 is the ability to easily bundle and minify your JavaScript and CSS. With .NET 4.5, Microsoft introduced a new featured called Bundling and Minification which bundle multiple JavaScript and CSS files in one requests and minify it by removing white spaces and characters which is not required. Microsoft introduced a new class called BundleTable which take care of Bundling and Minification. BundleTable class is shipped with two inbuilt Bundle for JavaScript and CSS respectively. However one can easily create their own custom Bundle as per requirements.

Example

To get started, create new MVC 4 application, build it and open it in Firefox or any other browser. And inspect (IE F-12 or open Firebug at Mozilla) the loaded JavaScript information with the help of developer tools of browser you are using.
In IE select the Script tab or in Mozilla open “Net è JS” to view JavaScript files 


To view CSS files, in IE select the CSS tab or in Mozilla open “Net è CSS”.


You can see there are lots of JavaScript files and CSS files are used.

Bundling

The process of combining all of your JavaScript and CSS files into one file (one for js and one for css). This is a new feature in ASP.NET 4.5 that makes it easy to combine or bundle multiple files into a single file. You can create CSS, JavaScript and other bundles. Fewer files means fewer HTTP requests and that can improve first page load performance.

Minification

The process of shrinking the js and css content. Minification performs a variety of different code optimizations to scripts or css, such as removing unnecessary white space and comments and shortening variable names to one character.

Creating the Bundles

Simply add jQuery, jQuery.UI, jQuery validation etc to the BundleConfig.cs class in the App_Start folder.
Note: ScriptBundle is used to bundle the JavaScript files & StyleBundle used for CSS files bundle.

Note: Make sure the application should have the Microsoft ASP.NET Web Optimization Framework. To install the package from nuget, go to "Tools" --> "Library Package Manager" --> "Package Manager Console".
Install the package from nuget: Install-Package Microsoft.AspNet.Web.Optimization



Class below:
using System.Web.Optimization;
public class BundleConfig
{
    public static void RegisterBundles(BundleCollection bundles)
    {
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
               "~/Scripts/jquery-1.6.2.js",
               "~/Scripts/common.js",
               "~/Scripts/modernizr-1.7.min.js",
               "~/Scripts/jquery.unobtrusive-ajax.min.js"));

        bundles.Add(new ScriptBundle("~/bundles/jqueryui").Include(
                    "~/Scripts/jquery-ui*"));

 bundles.Add(new ScriptBundle("~/bundles/validation").Include(
                     "~/Scripts/jquery.validate_min.js",
                     "~/Scripts/jquery.validate.unobtrusive.min.js"));

        bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site.css"));

        bundles.Add(new StyleBundle("~/Content/themes/base/css").Include(
                    "~/Content/themes/base/jquery.ui.core.css",
                    "~/Content/themes/base/jquery.ui.resizable.css",
                    "~/Content/themes/base/jquery.ui.selectable.css",
                    "~/Content/themes/base/jquery.ui.accordion.css",
                    "~/Content/themes/base/jquery.ui.autocomplete.css",
                    "~/Content/themes/base/jquery.ui.button.css",
                    "~/Content/themes/base/jquery.ui.dialog.css",
                    "~/Content/themes/base/jquery.ui.slider.css",
                    "~/Content/themes/base/jquery.ui.tabs.css",
                    "~/Content/themes/base/jquery.ui.datepicker.css",
                    "~/Content/themes/base/jquery.ui.progressbar.css",
                    "~/Content/themes/base/jquery.ui.theme.css"));
    }
}

Register the Bundles

Now the created templates of bundle registration need to register in the “Application_Start” method in Global.asax file in the following way.
protected void Application_Start()
{
     AreaRegistration.RegisterAllAreas();
     FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
     RouteConfig.RegisterRoutes(RouteTable.Routes);

     BundleConfig.RegisterBundles(BundleTable.Bundles);
}

Reference the Bundles

Add the bundles in the following code:
For JavaScript bundle: @Scripts.Render("~/bundles/jquery")
For CSS bundle: @Styles.Render("~/Content/themes/base/css", "~/Content/css")

Controlling Bundling and Minification

Bundling and minification is enabled or disabled by setting the value of the debug attribute in the compilation Element in the Web.config file, debug is set to true so bundling and minification is disabled.
<compilation debug="true" targetFramework="4.0" />

To enable bundling and minification, set the debug value to "false".
<compilation debug="false" targetFramework="4.0" />
We can override the Web.config setting with the “EnableOptimizations” property on the BundleTable class.
BundleTable.EnableOptimizations = true;

Note: Unless EnableOptimizations is true or the debug attribute in the compilation Element  in the Web.config file is set to false, files will not be bundled or minified. Additionally, the .min version of files will not be used, the full debug versions will be selected.EnableOptimizations overrides the debug attribute in the compilation Element  in the Web.config file

After bundle we get the following “CSS” and “JavaScript” bundle.



Conclusion

With .NET 4.5, it is easier to implement Bundling and Minification with very less effort and without major changes.

Here are some articles


Sunday, June 3, 2012

ASP.Net MVC3 Areas

Normally in a MVC3 application we have generally 3 sections i.e., Model, View, Controller. In real-world application there may be many modules. So separating each of the modules in our MVC3 application is highly recommendable. You can partition Web applications into smaller units that are referred to as areas. Areas provide a way to separate a large MVC Web application into smaller functional groupings. An area is effectively an MVC structure inside an application. An application could contain several MVC structures (areas).

How to create: To create an “Area” in MVC3 app, there is a template.

      a. First create an ASP.Net MVC3 application.
      b.  “Right-click” on the solution and choose “Add” -> “Area”.
  
      c.    A dialog comes up to allow you to name the area.

      d.    Once you are done the template will create the Area in an "Areas" folder in the MVC project. If you don't already have an “Areas” folder it will be added. If you already have other “areas” a new “area” will be added to that “areas” folder. Each area has its own Model, Views and Controllers folder. Each area can have its own layout, Content, Scripts etc.

You will now add area-enabled controllers and action methods for each area.
To add area controllers:
  1. In Solution Explorer, right-click the Controllers subfolder for the Blog area, click Add, and then click Controller.

  1. Name the controller BlogController and then click Add.

  1. Add the following code to the BlogController class.
  2. Now “Add View”.


  1. Name the View Index and then choose layout on “Use a layout or master page:”
  2. You can choose a separate layout for your area (Copy/create the "_layout.cshtml" from the main project and paste it under the "Areas" – “Blog” Shared folder).
  3. Click Add.

  1. Now add a new action link for "Blog" under the _layout.cshtml". Where “Blog Area” è Menu name, “Index” è “Action Name”, “Blog” è “Controller name” “new { area = “blog” }” è routes Values and “null” è “Htmlattributes”.
<li>@Html.ActionLink("Blog Area", "Index", "Blog", new { area = "blog" }, null)</li>



         i. So the blog link will be created and when we click the "blog area" link it will redirect to the "blog" part of our project which is under the "Areas".

  1. Now go to the "BlogAreaRegistration" file (just the following picture) and modify the existing code like below:

  1. I have added here only Controller Name "Blog" (controller = "Blog") extra under the new {} section. Now run the application it will look like the following picture:

public override void RegisterArea(AreaRegistrationContext context)
        {
            context.MapRoute(
                "Blog_default", //string name
                "Blog/{value}", //string URL
                new { Controller = "Blog", action = "Index", value = UrlParameter.Optional } ///object defaults
            );
        }

  1. See "blog" link has come. See the url routing. It calls our "Blog " Areas part.