Preventing Cross Site Scripting Attacks in ASP.NET MVC 4

Introduction

A website is exposed to various types of attacks and one of the most common types of attack is what is known as Cross Site Scripting (XSS). In a cross site scripting attack, malicious markup and script is entered in the web pages that are viewed by other users. If proper care is not taken to filter this malicious piece of markup, the script gets stored in the system and also rendered on web pages. Depending on the script injected by the hacker it can cause damage ranging from annoying popups to stolen credentials to accessing data stored in cookies. Therefore, it is important for ASP.NET MVC developers to prevent these types of attacks. Luckily, ASP.NET MVC offers a helping hand in safeguarding your websites. This article discusses some of the basics involved in the process.

What is Cross Site Scripting Attack?

In order to understand what a cross site scripting attack is, let’s develop a simple ASP.NET MVC website that accepts some user input. Suppose that you are developing a blog engine and users are allowed to leave comments on blog posts. The following figure shows how the comments might be accepted:

Comment Box
Comment Box

As you might have guessed, the user can enter any text in the textbox and the textarea, including HTML markup tags and script fragments! Once the form is submitted the posted data is saved in the database as shown below:

public ActionResult SaveData(FormCollection form)

{
    BlogEntities1 db = new BlogEntities1();
    Comment comment = new Comment();
    comment.UserName = form["username"];
    comment.UserComment = form["usercomment"];
    comment.PostedOn = DateTime.Now;
    db.Comments.Add(comment);
    db.SaveChanges();
    return View("Index");
}

As shown above, the form is submitted to the SaveData() action method. The SaveData() method saves the data in a SQL Server database table named Comments. So far so good. Now assume that a use enters the following text in the comments textarea:

<h1>Hello   World!</h1>
<script>
alert('Cross   site scripting attack!');
</script>   

When such a user posts the above content it gets saved in the database. Later when this saved content is rendered on a web page it executes the script!

Executed Script
Executed Script

What the above example illustrates is a very mild version of a cross site scripting attack. Imagine what would happen if a clever hacker loads a malicious script from some different location and stole end user cookies or loaded undesirable content. That is why it is important for you to prevent cross site scripting attacks.

Note:
By default ASP.NET 4.5 throws an exception if potentially dangerous content is detected in the request. However, you may need to deviate from this default mechanism in certain cases. In certain legitimate cases it is perfectly acceptable for the user to submit markup. For example, a web page where a blog owner enters the content of a blog post should accept HTML tags. In such cases you can skip the default checking performed by ASP.NET. You can either set requestValidationMode in web.config or use the [ValidateInput] attribute on action methods.

Preventing Cross Site Scripting Attacks

Most of the cross site scripting attacks can be prevented if you encode all the user input properly. You need to ensure that strings are encoded properly at two distinct places as far as ASP.NET MVC applications are concerned:

  • Views
  • Controllers or classes

In order to encode strings in views you can use the Html.Encode() method as shown below:

<%= Html.Encode(c.UserComment) %>

As you can see the view that displays the user comment now encodes the comment using the Html.Encode() method; this way all of the special characters such as <, > and & are encoded properly. For example, once Encode() method is in place the same malicious input by the end user is encoded and then rendered on the page as shown below:

HTML.Encode() method
HTML.Encode() method

As you can see the script is no longer executed even if the comment saved in the database contains the <script> tag. Instead the HTML markup is encoded and then displayed on the page.

There is also a shortcut to using the Html.Encode(), you can use <%: and %> block instead of <%= and %>. The following code shows how:

<%: c.UserComment %>

The <%: and %> block HTML encodes the string and then emits on the page.

The above code takes care of displaying content on the page by HTML encoding it. Here the encoding happens at the View level but the database still contains the malicious markup and script. Wouldn’t it be nice if you HTML encode the content before saving it into the database? You can do so in your controllers or other classes using the Server.HtmlEncode() method.

comment.UserComment   = Server.HtmlEncode(form["usercomment"]);
...
db.SaveChanges();
...

As you can see the HtmlEncode() method of Server object accepts the raw string and returns an HTML encoded version of the same. The database now stores the HTML encoded version of the comments rather than the raw version. If you need to decode the HTML encoded version back you can use Server.HtmlDecode() method.

In addition to the HTML output displayed on a web page, you may also consider encoding attributes and URLs. Encoding attribute values is important if you are dynamically changing them based on user input. For example, you might be accepting a user’s website URL and then setting the href attribute of an anchor tag dynamically. In such cases it is better to encode attribute values using the Html.AttributeEncode() method. On the same lines you can encode URL values using the  Url.Encode() method.

Using AntiXssEncoder to Encode Strings

The techniques to prevent cross site scripting attacks that we covered so far are traditional techniques that have roots in the core ASP.NET framework. In some cases where security is extremely important you may want to use an even more secure technique of encoding. Luckily, System.Web.Security.AntiXss namespace provides a class – AntiXssEncoder – that can be used to encode HTML content and attribute values. The major difference between the default encoder used by ASP.NET and the AntiXssEncoder class is that the former uses a blacklist of a set of prohibited characters whereas the later uses a whitelist of a set of allowed characters making it more secure.

The following code shows how AntiXssEncoder class can be used in a controller:

 public   ActionResult SaveData(FormCollection form)
{
     BlogEntities1 db = new BlogEntities1();
     Comment comment = new Comment();
 comment.UserName   = AntiXssEncoder.HtmlEncode(form["username"], false);   comment.UserComment =   AntiXssEncoder.HtmlEncode(form["usercomment"], false);    comment.PostedOn =   DateTime.Now;
     db.Comments.Add(comment);
     db.SaveChanges();
     return View("Index");
}

As you can see, AntiXssEncoder class has static methods such as HtmlEncode() and HtmlAttributeEncode() that can be used to encode form data.

By default, methods such as Server.HtmlEncode() use the HttpEncoder class for performing the encoding. You can override this default with the AntiXssEncoder class by adding the following markup in the web.config file:

<httpRuntime encoderType="System.Web.Security.AntiXss.AntiXssEncoder" />

As shown above, the encoderType attribute of the <httpRuntime> tag is set to System.Web.Security.AntiXss.AntiXssEncoder so that the default encoder class is now set to AntiXssEncoder.

Summary

ASP.NET MVC applications that accept user input need to safeguard themselves against cross site scripting attacks. A common way to prevent such attacks is to encode data accepted from a user before displaying it on a web page. The Html.Encode() method and <%: %> code block allow you to do just that. If you wish to encode data before saving it in the database you can use the Server.HtmlEncode() method. A more secure form of encoder is available through the System.Web.Security.AntiXss.AntiXssEncoder class. Methods of the AntiXssEncoder class such as HtmlEncode() and HtmlAttributeEncode() allow you to encode raw strings. You can change the default encoder to AntiXssEncoder in the web.config.

About the Author:

Bipin Joshi is a blogger, author and an IT trainer who writes about apparently unrelated topics – Yoga & technology! Bipin has been programming since 1995 and is working with .NET framework ever since its inception. He has authored or co-authored half a dozen books and numerous articles on .NET technologies. He has also penned a few books on Yoga. You can read more about him here.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read