Using BindAttribute In ASP.NET MVC To Exclude Bindable Data

Posted by: Malcolm Sheridan , on 12/30/2009, in Category ASP.NET MVC
Views: 28536
Abstract: The following article demonstrates how to use the bind attribute in MVC to exclude bindable values.
Using BindAttribute In ASP.NET MVC To Exclude Bindable Data
 
If you've used MVC you'll know how much time is saved thanks to model binding. That's where a form post is matched to a strongly typed object. This can save you time initially but it can also provide a way for a malicious user to exploit vulnerabilities in your code if you're not careful. You can optionally override what values to bind and what not to bind automatically. In my opinion it's better to code what not to allow in this case. 
To demonstrate this imagine you had an application that added new employees to your company. You could enter their department, given name, surname and salary. Here's what the Employee class might look like:

 

C#
public class Employee
{
      public string Department { get; set; }
      public string GivenName { get; set; }
      public string Surname { get; set; }
      public double Salary { get; set; }
}
VB.NET
Public Class Employee
      Private privateDepartment As String
      Public Property Department() As String
            Get
                  Return privateDepartment
            End Get
            Set(ByVal value As String)
                  privateDepartment = value
            End Set
      End Property
       Private privateGivenName As String
       Public Property GivenName() As String
             Get
                   Return privateGivenName
             End Get
             Set(ByVal value As String)
                   privateGivenName = value
             End Set
       End Property
       Private privateSurname As String
       Public Property Surname() As String
             Get
                   Return privateSurname
             End Get
             Set(ByVal value As String)
                   privateSurname = value
             End Set
       End Property
       Private privateSalary As Double
       Public Property Salary() As Double
             Get
                   Return privateSalary
             End Get
             Set(ByVal value As Double)
                   privateSalary = value
             End Set
       End Property
End Class
Salary is one value that you don't want any user to be able to adjust through this system. You could create your form so it hides the salary input field like this:
Fields
However if you did use model binding without setting any exclusions, a user could create a totally separate form and add the salary field to the form post. By doing this the user would be able to set their own salary!
FakePost
One way to stop this is to add exclusions to your action and explicitly state what can and can't be binded. Here's one example of how to do that:
C#
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreateWithAttributeBinding([Bind(Exclude = "Salary")] Employee emp)
{
      var employee = new Employee();
      if (!TryUpdateModel(employee))
      {
            // an error occured  
            return View("Create");
      }
      else
      {
            // add to database
            return RedirectToAction("Create");
      }
}
VB.NET
<AcceptVerbs(HttpVerbs.Post)> _
Public Function CreateWithAttributeBinding(<Bind(Exclude := "Salary")> ByVal emp As Employee) As ActionResult
      Dim employee = New Employee()
       If (Not TryUpdateModel(employee)) Then
             ' an error occured  
                  Return View("Create")
       Else
             ' add to database
                  Return RedirectToAction("Create")
       End If
End Function
Notice in the code above there's this line:
C#
([Bind(Exclude = "Salary")] Employee emp
VB.NET
((Bind(Exclude = "Salary")) Employee emp
By adding this line of code I'm explicitly saying that Salary cannot be set from the form post. Even if the user posts data from their fake form, the salary amount will be ignored.
Runtime
That's one way to override exclusions. Another way which is a little cleaner is by using an interface to define what fields are to be excluded. I'll create an interface called IEmployeeBinding and have Employee inherit from that:
C#
public interface IEmployeeBinding
{
      string Department { get; set; }
      string GivenName { get; set; }
      string Surname { get; set; }
}
 
public class Employee : IEmployeeBinding
{
      public string Department { get; set; }
      public string GivenName { get; set; }
      public string Surname { get; set; }
      public double Salary { get; set; }
}
VB.NET
Public Interface IEmployeeBinding
      Property Department() As String
       Property GivenName() As String
       Property Surname() As String
End Interface
 
Public Class Employee
      Implements IEmployeeBinding
      Private privateDepartment As String
      Public Property Department() As String Implements IEmployeeBinding.Department
            Get
                  Return privateDepartment
            End Get
            Set(ByVal value As String)
                  privateDepartment = value
            End Set
      End Property
       Private privateGivenName As String
       Public Property GivenName() As String Implements IEmployeeBinding.GivenName
             Get
                   Return privateGivenName
             End Get
             Set(ByVal value As String)
                   privateGivenName = value
             End Set
       End Property
       Private privateSurname As String
       Public Property Surname() As String Implements IEmployeeBinding.Surname
             Get
                   Return privateSurname
             End Get
             Set(ByVal value As String)
                   privateSurname = value
             End Set
       End Property
       Private privateSalary As Double
       Public Property Salary() As Double
             Get
                   Return privateSalary
             End Get
             Set(ByVal value As Double)
                   privateSalary = value
             End Set
       End Property
End Class
Nothing too complex about the code above. Where the magic happens is in the controller. You can take advantage of TryUpdateModel and update the model instance using values from the current values:
C#
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreateWithInterfaceBinding()
{
      var employee = new Employee();
      if (!TryUpdateModel<IEmployeeBinding>(employee))
      {
            // an error occured  
            return View("Create");
      }
      else
      {
            // add to database
            return RedirectToAction("Create");
      }
}
 
VB.NET
<AcceptVerbs(HttpVerbs.Post)> _
Public Function CreateWithInterfaceBinding() As ActionResult
      Dim employee = New Employee()
       If (Not TryUpdateModel(Of IEmployeeBinding)(employee)) Then
             ' an error occured  
                  Return View("Create")
       Else
             ' add to database
                  Return RedirectToAction("Create")
       End If
End Function
 
The line below does the work for us:
C#
if (!TryUpdateModel<IEmployeeBinding>(employee))
VB.NET
If (Not TryUpdateModel(Of IEmployeeBinding)(employee)) Then
The code will create a new instance of an employee and bind the values according to what properties have been specified by the interface. Pretty neat huh?!

You should always add exclusions to your actions whenever you accept user input that can change state. This way you'll become a more defensive programmer.

Give a +1 to this article if you think it was well written. Thanks!
Recommended Articles
Malcolm Sheridan is a Microsoft awarded MVP in ASP.NET, a Telerik Insider and a regular presenter at conferences and user groups throughout Australia and New Zealand. Being an ASP.NET guy, his focus is on web technologies and has been for the past 10 years. He loves working with ASP.NET MVC these days and also loves getting his hands dirty with jQuery and JavaScript. He also writes technical articles on ASP.NET for SitePoint and other various websites. Follow him on twitter @malcolmsheridan


Page copy protected against web site content infringement by Copyscape


User Feedback
Comment posted by e is required. on Monday, March 29, 2010 1:56 AM
comment
Comment posted by Shannon Deminick on Sunday, December 5, 2010 6:08 PM
You can also use the ReadOnly attribute on your properties to acheive the same thing which I prefer because then you're not relying on String representations of your property names.
Comment posted by e on Friday, March 22, 2013 6:47 AM
comment
Comment posted by karthik on Wednesday, January 8, 2014 1:16 AM
Nice Post..
Thanks a lot

Post your comment
Name:  
E-mail: (Will not be displayed)
Comment:
Insert Cancel