Securing your HTML Form in ASP.NET MVC

By now, developers should really understand how to build a form and properly secure it.  But this still seems to allude some.  It’s rather embarrassing to fail security assessments for certain secuirty flaws that can be easily avoided.

In this blog, a refresher on the basics will be covered for securing your post as well as writing an extension to add to your MVC Infrastrucutre to be used by all of your team members.

It does not cover data validation.  I am really focusing on the form and the action of that form.  In addition, this is also from the perspective of a business web application that is only accessed via an authenticated user.

Let’s get started…

Poorly Secured Form and Action

Let’s take a simple Edit many developers write everyday and show the numerous flaws with this.  Here is the Razor View:

<h2>Edit</h2>
@using (Html.BeginForm())
{
     ...  Something here with a submit button...
}

Then the controller action would look something similar to this:

public ActionResult Edit(YourModel yourModel)
{
     if (ModelState.IsValid)
     {
          SaveYourModel(yourModel);
          return RedirectToAction("Index");
     }
     return View(client);
}

There are numerous concerns with the above form.

  1. When changing sensitive data, it should only happen via the proper HTTP Action.  So setup your ActionMethodSelectorAttributes properly.
  2. What about Cross-Site Request Forgery?  The above easily allows a hacker to submit data so prevent that as best as possible.
  3. Check the referrer.  Make sure the referrer is your site.
  4. Who is the originator?  Usually, this is the site that served the form.  So check the refferer.
  5. Next, who can change this data.  If only authenticated users, then which ones?

Crash course on ActionMethodSelectorAttribute

What is an ActionMethodSelectorAttribute?  It is an attribute on your controller’s action that is used to influence the selection of an action method.  This is easy to see the benefit of using them.

You can control the routing in MVC to actions decorated with HTTPGet.

[HttpGet()]
public ActionResult Edit(int id)
{
     YourModel yourModel = GetYourModel(id)
     return View(yourModel);
}

Or control the routing for inserting, updating and deleting of data using HTTPPost.

[HttpPost()]
public ActionResult Edit(YourModel yourModel)
{
     if (ModelState.IsValid)
     {
          SaveYourModel(yourModel);
          return RedirectToAction("Index");
     }
     return View(client);
}

When a user navigates to the Edit page for from a link, double clicking a row in a grid, or by any other means, that action should be called via a HTTPGet; therefore the first Action is called due to the HTTPGet attribute on that method.  Once on that page, the user then modifies the data and clicks a submit button in a form performing a POST thus calling the second Action decorated with HTTPPost.

For a complete list of action methods, click the following link for ActionMethodSelectorAttributes.

When do you want to use an ActionMethodSelectorAttribute?  In my opinion, pretty much on every Action in your controller.

Rules to live by:

1.  If you are selecting data to display in your Action method, then your Action should be decorated with the HTTPGet Attribute.

2.  If you are creating, updating or deleting data via your Action method, then your Action should be decorated with the HTTPPost Attribute.

Oh, and by the way, using HTTPPost helps prevent some attacks via CSRF (see next section).  Without that ActionMethodSelectorAttribute, it’s easy for a hacker to create links that a user can click and unknowingly modify their data.  

Without the HTTPPost a well crafted link (obviously depending on your model and your action etc…) can be used to update sensitive info.  Even worse, if your id is just an identity column in SQL Server and if you did not properly secure your form, a hacker could call this link over and over again for each identity id in your database, thus updating your data to what ever he wants.

http://localhost:2572/InsecureDOR/EditSubmit?ClientId=3&FirstName=Maverick&MiddleInitial=A&LastName=Smith

Pretty scary if your site really contains sensitive information like account information, employee data or critical business processes that if disrupted by a hacker causes serious damage to your company’s reputation.

So use HTTPPost and you will prevent the above hacks via get from working.

Cross-Site Request Forgery (CSRF)

Cross-Site Request Forgery (CSRF) is the #8 security flaw on the OWASP Top 10 for 2013. Follow the link for great information about CSRF.  For nitty grittey detail, read “Part 5: Cross-Site Request Forgery (CSRF), 1 Nov 2010 in Troy Hunt’s OWASP Top 10 book. It’s free. This will explain in great detail how an attacker can take advantage of your site. Luckily for us, we don’t have to implement the “Synchronizer Token Pattern” as Tony explains. Instead, we just need to add the following in our form:

@Html.AntiForgeryToken()

Then on the Controller’s Action, the following ActionFilter must be added.

[HttpPost()]
[ValidateAntiForgeryToken()]
public ActionResult Edit(YourModel yourModel)

This handles most CSRF attacks.

Note:  The user must accept cookies.  This only works with POST Requests.  It does not work with GET Requests.

Without a valideAntiForgeryToken, the server will threw exceptions like the following:

AntiForgeryException

AntiForgeryExceptionMissing

Can this be circumvented?  Why, yes….  But, a hacker has to actually get the AntiForgeryToken, then craft a POST using the correct form values.  Gettign the AntiForgeryToken is possible if your site  is vulnerable to XSS or your users are on older browser’s that allow cross-domain access.  Therefore, dropping support for older browsers in web applications is critical when the data is sensitve.  But that might be easier said than done.

The next step is to check the referrer.

Checking the Referrer

The next issue that I see with the above code is that the post could originate from another site.   There are expections, but for most business web application, a post originates from your site.

In order to check the referrer, you need to write a Attribute that inherits from AuthorizeAttribute:

public class IsPostedFromThisSiteAttribute : AuthorizeAttribute
{
  public override void OnAuthorization(AuthorizationContext filterContext)  {
    if (filterContext.HttpContext != null)
    {
      if (filterContext.HttpContext.Request.UrlReferrer == null)
        throw new System.Web.HttpException("IsPostedFromThisSite has invalid post - Missing UrlReferrer!"); 
       if (filterContext.HttpContext.Request.UrlReferrer.Host != filterContext.HttpContext.Request.Url.Host)
          throw new System.Web.HttpException("IsPostedFromThisSite has invalid post - Form was not submitted from this site!");
    }
    base.OnAuthorization(filterContext);
 }
}

Now, use this Attribute on your posts by applying it to the Action:

 [AcceptVerbs(HttpVerbs.Post)]
 [IsPostedFromThisSite]
 public ActionResult MyAction()

Checking the Origin

See the Origin on the following site:

https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet

Authenticated or Authorized

Next check the user to see if the user is authenticated and authorized to perform the action.

Finally

Build an HTML Extension to make this even easier to follow in your Business Application.  It is so easy to do…

Conclusion

These techniques help tremendously when securing your site, protecting your data and for passing security assessments.  So don’t forget to use them in all your forms and protect your reputation, your companies reputation and your bottom line.

More coming soon…

KendoUI: Understanding ToDataSourceResult

Using server filtering is rather easy with Kendo UI MVC, unless your new to it.  Then that first couple hours is pretty frustrating untill you find the right article, information and samples.  I have very few gripes with Telerik and Kendo UI but they do have a problem with the Kendo UI Demos.  They do not include enough sample code from controllers and web services.  So hopefully this will help out those newbies to KendoUI.

When would I use this?

Server-side Filtering, Paging, and Sorting with the Grid or ListView.

How to use it?

When would I use this?  Server-side Filtering with the Grid or ListView.

First thing you want to do is add the following the following using statement to you Controller or API Controller:

using Kendo.Mvc.Extensions;

Now, you can easily take advantage of ToDataSourceResult extension method to convert any IQueryable or IEnumerable to a DataSourceResult object.  It will help you page, filter, sort or group your data using the information provided by the DataSourceRequestObject.

Your AJAX action will take one parameter:  DataSourceRequest.

public ActionResult GetAllOrders([DataSourceRequest] DataSourceRequest request)

Now in the method, you just call ToDataSourceResult on your IQueryable or IEnumerator.  Pretty simple, although you have to be careful when dealing with large volumes of data o make sure your implementation does not return all the data before applying filter, sorting, and paging.

How is ToDataSourceResult being implemented under the hood by Telerik?  C# Extension Methods.  If you need a refresher, check it out here:

If you want to see the implementation, then use JustDecompile and run it against Kendo.MVC.dll.

Which Kendo UI Widgets

This is meant to be used with the following controls:

  • Grid
  • ListView

Other controls like ComboBox and AutoComplete expect just a simple array and will not work with DataSourceResult.

Does this only work with a ORM?

No, it does not.  Note:  Any IQueryable or IEnumerable so LINQ, List, Dictionary, etc…

Let’s dive into a simple example

In my sample, I have a Domain POCO Class called Order.

public class Order
{
 public int Id { get; set; }
 public string LastName { get; set; }

 public decimal TotalAmount { get; set; }

 public decimal TotalAmountUsd { get; set; }

 public string OrderCurrencyCode { get; set; }

 public string OrderCurrencyCultureCode { get; set; }

 public DateTime OrderDate { get; set; }
}

Then I have a Domain Class that contains a list of Orders.  This has data stubbed out for now.

public class Orders
{
   private readonly List orders = new List();
   private int nextId = -1;

   public Orders()
   {
     Add(new Order() { LastName = "Federer", TotalAmount = 1023.23m, TotalAmountUsd = 400.23m, OrderCurrencyCode = "SEK", OrderCurrencyCultureCode = "sv-SE", OrderDate = DateTime.UtcNow.AddDays(-1) });
     // Add lots of data here........
     Add(new Order() { LastName = "Aikemo", TotalAmount = 1023.23m, TotalAmountUsd = 400.23m, OrderCurrencyCode = "JPY", OrderCurrencyCultureCode = "ja-JP", OrderDate = DateTime.UtcNow.AddDays(-8) });
 }

 public Order Add(Order item)
 {
   if (item == null)
   {
     throw new ArgumentNullException("item");
   }
   item.Id = nextId++;
   orders.Add(item);
   return item;
 }

 public List GetAll()
 {
  return orders;
 }
}

Then, I have a ViewModel which looks just like my Order class.
public class OrderViewModel
{
 public int Id { get; set; }
 public string LastName { get; set; }

 public decimal TotalAmount { get; set; }

 public decimal TotalAmountUsd { get; set; }

 public string OrderCurrencyCode { get; set; }

 public string OrderCurrencyCultureCode { get; set; }

 public DateTime OrderDate { get; set; }
}

In the controller, I have the following Action (Note:  My controller is importing  Kendo.Mvc.Extensions):

[HttpPost]
public ActionResult GetAllOrders([DataSourceRequest] DataSourceRequest request)
 {
   Orders orders = new Orders();
   List orderList = orders.GetAll();
   DataSourceResult result = orderList.ToDataSourceResult(request, 
     order => new OrderViewModel 
     { 
       Id = order.Id, LastName = order.LastName,
       OrderCurrencyCode = order.OrderCurrencyCode, OrderCurrencyCultureCode = order.OrderCurrencyCultureCode,
       TotalAmount = order.TotalAmount, TotalAmountUsd = order.TotalAmountUsd,
       OrderDate = order.OrderDate
     }
   );

   return Json(result);
 }

The call to ToDataSourceResult is taking the request information and using that to filter, sort, etc the results and transform them into the ViewModel.  Pretty simple and straightforward.

Finally, in your Razor view you can call your AJAX method which will easily page, filter, sort, etc…

@(Html.Kendo().Grid()
 .Name("grid")
 .HtmlAttributes(new { style = "width:700px" })
 .Columns(columns =>
 {
 columns.Bound(p => p.Id).Title("Order Id");
 columns.Bound(p => p.LastName).Title("Customer");
 columns.Bound(p => p.TotalAmount).Title("Total Amount");
 columns.Bound(p => p.TotalAmountUsd).Title("Total Amount (USD)");
 columns.Bound(p => p.OrderDate).Title("Ordered On");
 })
 .Pageable()
 .Sortable()
 .Scrollable()
 .Filterable()
 .DataSource(dataSource => dataSource
 .Ajax()
 .PageSize(5)
 .Read(read => read.Action("GetAllOrders", "Orders"))
 )
)

Now the user can sort, page, filter, …

Grid Filtering
Grid Filtering

KendoUI Resources

Here are a couple helpful resources from Telerik:

 

Conclusion

This is pretty simple once you get the basics down so good luck coding up your solutions with it.