A Checklist To Holistically Mitigate Cross Site Scripting (XSS) In An ASP.NET Application

Introduction 

 
An application is susceptible to XSS vulnerability if 'user input' is returned back to the browser client without being validated or escaped. If the user enters a malicious input (script) instead of a legitimate input then that malicious input (script) can be executed by the browser client when returned. For brevity, the 'user input' when returned back from the server is referred to as 'returned input' in this article.
 
In order to holistically mitigate the XSS vulnerability, we have to apply all of the following controls:
 

Validate user input (Input Validation)

  • Use a whitelist of legitimate 'user input' to validate on the client-side as well as on the server side.
  • Validate all headers, cookies, URL querystring values, form fields, and hidden fields.
  • Validate the length, datatype and any bussiness rule for the 'user input'
  • Set 'validateRequest' flag to 'true' either at the application level (web.config file as illustrated below) or at page level
    1. <configuration>    
    2.    <system.web>    
    3.       <pages validateRequest="true" />    
    4.    </system.web>    
    5. </configuration>    

Saving 'user input' to database in the controller of ASP.NET MVC 4

The following snippet uses the whitelist of a set of allowed characters making it more secure as compare to the default encoder of ASP.NET.
  1. Comment comment = new Comment();  
  2. comment.usercomment = System.Web.Security.AntiXss.AntiXssEncoder.HtmlEncode(form[“usercomment”],false);  
  3. db.Comments.Add(comment);  
  4. db.SaveChanges();  
The default encoder of ASP.NET is used as shown below, which leverages a blacklisted set of prohibited characters.
  1. comment.usercomment=server.Html.Encoder(form["usercomment"]  

Escape or encode the 'returned input' before being sent to the browser client

  • HTML encoding for dynamic inputs (Client side-html context)
    In ASP .NET 4.5, the HTML encode binding shortcut (<%#:) binds dynamic values with HTML markup. In ASP.NET 4.0, the HTML encode render shortcut (<%:) renders dynamic values directly with the HTML markup.
    1. HTML encode binding shortcut <td><%#: Item.Address %></td>    
    2. HTML encode render shortcut <td><%: Item.Address %> </td>    
  • HTML encoding for server controls (Server side-html context)
    1. ASPX    
    2. <td><asp:Label id='lblAddress' runat='server'></asp:Label></td>    
    3. ASPX.CS    
    4. lblName.Text = Microsoft.Security.Application.Encoder.HtmlEncode(Request['Address']);    
  • JavaScript Encoding (Server side - Javascript context)
    Microsoft Web Protection Library (WPL) is used in this example before a dynamic property is written into the JavaScript context.
    1. <a onclick='<%# string.Format('ConfirmDelete({0})', Microsoft.Security.Application.Encoder.JavaScriptEncode(Item.Name))%>'>    
    2.    Delete    
    3. </a>    
  • URL Encoding (Server side – URL Context)
    Microsoft Web Protection Library (WPL) is used in this example before a dynamic property is written to the href attribute
    1. <a href=<%# Microsoft.Security.Application.Encoder.UrlEncode(Item.Url)%>>    
    2.    View Details    
    3. </a>    
  • Use innerText properties of HTML controls
    InnerText property of HTML controls should be used instead of innerHTML property so that the 'returned input' is rendered as literal instead of an executable script.
  • Use the Javascript function JSON.parse(text)
    Use the Javascript function JSON.parse(text) to convert text into a javascript object. Do not use eval(text)
    1. var text = ‘ { “name”: “John”, “age” : 30, “city” : “New York” } '    
    2. var obj = JSON.parse(text);    
References
  1. https://software-security.sans.org/developer-how-to/developer-guide-xss
  2. https://www.codeguru.com/csharp/.net/net_asp/preventing-cross-site-scripting-attacks-in-asp.net-mvc-4.htm