Developing secure web applications: XSS attack, the Confused Deputy and Over-Posting

The reality is that securing applications is not as much fun as we would like it to be. Nobody comes and says “Wow! Thumbs up for securing my personal data!”. However, security is undoubtedly important in many contexts and cannot be underestimated. We do not want to pass through an embarrassing position caused by a security breach.

In this article, I cover XSS, XSRF and Over-Posting, a fraction of the most common web attacks, and explain how to protect your applications against them.

Some web security principles

  • Implement security in depth: the Web tier responsible for receiving HTTP requests should not be the only layer to perform security checks. Each subsystem must take responsibility for their own security, disregarding the quality of the security checks of the upper layers.
  • Never trust user input: Never assume that you do not need to perform a security check just because it has already been done elsewhere. Moreover, validations in JavaScript can improve the user experience by avoiding unnecessary http requests, but never assume that these validations on the client side are secure. An attacker can bypass client validation without any difficulty.
  • Reduce surface area: Minimize the amount of exposed operations and restrict the inputs of each action to contain only the data required to process the action. Do not expose to the end user exception details or information about the database schema.
  • Enforce the principle of Least Privilege: Perform operations using only the privileges required for the task. If for some reason you need to elevate permissions, grant them but remove when these permissions are no longer needed.
  • Disable unnecessary features: Platforms can provide security flaws. Uninstall features that are not relevant to the execution of your application.
  • Evaluate a model of authentication and authorization that fits well to your application: Authentication is the process of identifying the user who accesses the application. Authorization is the process of verifying what operations the authenticated user can perform. There are different strategies for authentication and authorization. Check the one that best suits your application.

Defending your code against the most common attacks

Users of your site are likely to discover bugs. Some of these bugs reveal security holes. And when an attacker discovers one of these gaps, we have a problem.

Cross-Site Scripting (XSS)

XSS is one of the most common web attacks. According to WhiteHat Security, 40% of the websites has at least one breach for Cross-Site Scripting. In XSS, we inject some client script code to the remote server through user inputs or query strings.

Open http://www.insecurelabs.org/Talk/Details/6 to start playing with XSS. Pay attention to the content written inside the input of the form. Everything that you write in a comment will be rendered after the form is submitted. In a real application, a malicious script inside a comment could inject code to the page and every user that opens the browser would run that script.

XSS01

This is the result

XSS02

This is a classical XSS attack. My posted comment containing a bad script will be rendered within the list of comments of the page. When someone opens the page, the script is executed. In this particular case, the attacker is stealing the cookies related to the domain where the script was injected. Open the article Session hijacking (Wikipedia) to understand the implications of exposing your cookies.

In the words of Jaff Atwood (CodingHoror.com), article Protecting Your Cookies: HttpOnly:

Imagine, then, the surprise of my friend when he noticed some enterprising users on his website were logged in as him and happily banging away on the system with full unfettered administrative privileges.

Preventing XSS

Never trust user input. Encode everything. Instead of displaying content as-is, use HTML encode to render content.

In ASP.NET Web Forms, the code below will not be encoded.

  <%= Model.Comment %> 

Instead, use one of these approaches:

 <%: Model.Comment %> 

 

 <%= Html.Encode(Model.Comment) %> 

Razor encodes by default. The sample below gives an encoded output:

 @Model.Comment 

In ASP.NET MVC, if you want to write raw content as-is (without any encoding), you should write it explicitly and decorate your action with a [ValidateInput(false)] attribute. In this case, security concerns are at your own risk.

 @Html.Raw(Model.HtmlContent) 
[ValidateInput(false)]
public ViewResult Save(FormDataWithRawContent form)
{
...
}

Preventing Cookie Theft – Use HttpOnly and Require SSL

In the Web.config file, write:

<httpCookies domain="" httpOnlyCookies="true" requireSSL="true" />

The httpOnlyCookies attribute will prevent cookies from being accessed from client scripts. The requireSSL attribute will prevent cookies from being sent back to the server when the connection is not secure with SSL. This configuration will stop most XSS attacks and should be used whenever possible.

Cross-Site Request Forgery (XSRF) – The confused deputy

Cross-site request forgery is an attack where the attacker creates a page that includes a form that posts to the attacked site.

<form id="someform"
action="http://attackedTargetSite/Entity/Update"
method="post">

<input type="text" />
<input type="text" />

If the user who submitted the form is authenticated on the target site, the target site will receive and process the post without presenting any complications related to authentication, since the action is being performed by an authenticated user.

The confused deputy attack

XSRF is a form of confused deputy attack.

If an attacker want to perform some administrative actions on a web application that he does not have the proper privileges, a feasible approach is to confuse an user to do these things for him. In the case of an XSRF attack, the confusing deputy is the user’s browser. Here (Haacked.com) we can see a nice practical example about XSRF attack.

A confused deputy is a computer program that is innocently fooled by some other party into misusing its authority. It is a specific type of privilege escalation. In information security, the confused deputy problem is often cited as an example of why capability-based security is important.

From Wikipedia

Preventing XSRF

Reduce surface area. Minimize the amount of actions exposed. Furthermore, create a hidden HTML input field that stores a token generated by your server and validate if a submitted token is valid. This token can be stored in a session variable or cookie.

ASP.NET MVC includes some helpers to prevent against this kind of attack. It generates a anti forgery token inside the form and validate this token against the server when the form is submitted:

@using (Html.BeginForm(...))
{
@Html.AntiForgeryToken("salt")
...
}

 

[ValidateAntiForgeryToken(Salt="salt")]
public ViewResult Update()
{
...
}

Thus, if the source of the request is unknown (i.e. the antiforgery token does not exist or it is not consistent), the action will not be triggered and an error will be thrown to the client application.

Known limitations

  • Users must have cookies enabled, or requests will be rejected.
  • This method works with POST, but not with GET. This should not be a very big problem, since GET requests should only read information and never change the state of the database.
  • XSS holes create possibilities for cookies hijacking and access to the antiforgery token.

Over-Posting

ASP.NET MVC maps model properties in GET and POST operations by using some naming conventions. However, this convenience introduces a security flaw: the attacker can populate properties of the model even if they are not displayed in the form.

Consider a model PlaceReview bound to an action.


public class PlaceReview
{
	public int ReviewID { get; set; } // PK
	public int PlaceID { get; set; } // FK
	public Place Place { get; set; } // FK
	public int NumberOfLikes { get; set; }
	public string UserName { get; set; }
	public string UserComment { get; set; }
}

Now consider that the action is only interested on the UserName and UserComment properties of the model.


<ul>
		<li>
			@Html.LabelFor(m => m.UserName)
			@Html.TextBoxFor(m => m.UserName)
		</li>
		<li>
			@Html.LabelFor(m => m.UserComment)
			@Html.TextBoxFor(m => m.UserComment)
		</li>
	</ul>

A malicious user can manipulate the querystring or post data to add information and change other properties of the model. For instance, he could add “NumberOfLikes = 5000” and the corresponding property would be populated accordingly in the server side application.

Preventing Over-Posting

You can use a BindAttribute on the model class or action parameter to explicitly control the properties that should be mapped by the model binder.

[System.Web.Mvc.Bind(Include="UserName, UserComment")]
public class PlaceReview
{
	public int ReviewID { get; set; } // PK
	public int PlaceID { get; set; } // FK
	public Place Place { get; set; } // FK
	public int NumberOfLikes { get; set; }
	public string UserName { get; set; }
	public string UserComment { get; set; }
}

A similar approach involves calling UpdateModel or TryUpdateModel within the Action.

UpdateModel(placeReview, "PlaceReview",
new string[] { "UserName", "UserComment" });

A better approach is not to use data mapping to represent view model and create specific classes that contain only the properties required for the action and nothing else.

public class PlaceReviewModel
{
	public string UserName { get; set; }
	public string UserComment { get; set; }
}

This last approach significantly reduces security holes related to over-posting and eliminates a problem of stamp coupling.

Stamp coupling occurs when modules share objects and use only a part of it. Sharing more data than what was needed allows the called module to access more data than it really needs.

From Cohesion and coupling: Principles of orthogonal, scalable design

Putting it all together

No application is totally secure, but there are some best practices that can be used to avoid several vulnerabilities. We talked about XSS, XSRF and Over-Posting. Fortunately, there are enough resources available and ready to protect web applications from dangerous attacks that occur frequently out there.

Related readings