Microsoft Anti-Cross Site Scripting Library V1.5: Protecting the Contoso Bookmark Page

 

Microsoft Anti-Cross Site Scripting Library V1.5: Protecting the Contoso Bookmark Page

Kevin Lam
Microsoft Application Consulting & Engineering (ACE)

November 2006

Summary: This tutorial shows you how to use the Microsoft Anti-Cross Site Scripting Library to protect your Web application from cross-site scripting (XSS) bugs, how to determine which outputs actually require encoding, and how to apply other techniques such as input validation in situations where the Microsoft Anti-Cross Site Scripting Library may not apply.

Contents

Introduction
About the Application
Attacking the Application
Protecting the Application
   Step 1: Review ASP.NET Code That Generates Output
   Step 2: Determine If Output Could Contain Untrusted Input
   Step 3: Determine Encoding Method to Use
   Step 4: Encode Output
Defense-in-Depth
Additional XSS Attacks
Conclusion

Introduction

In this tutorial, I'll take the Contoso Bookmark Page application (a sample application that gets installed along with the Microsoft Anti-Cross Site Scripting Library V1.5) and show you how the Microsoft Anti-Cross Site Scripting Library can be used to protect users from Cross-Site Scripting (XSS) attacks. I'll also show you an easy method for assessing use case scenarios for potential XSS vectors using nothing more than a simple table.

Aa973813.anticross_sitescript01(en-us,MSDN.10).gif

Figure 1. Contoso Bookmark Page source code

Note   Cross-site scripting (XSS) attacks exploit vulnerabilities in Web-based applications that fail to properly validate and/or encode input that is embedded in response data. Malicious users can then inject client-side script into response data causing the unsuspecting user's browser to execute the script code. The script code will appear to have originated from a trusted site and may be able to bypass browser protection mechanisms such as security zones.

These attacks are platform and browser independent, and can allow malicious users to perform undesired actions such as gaining unauthorized access to client data like cookies or hijacking sessions entirely.

For more information on XSS attacks, some good references are:
Microsoft Patterns & Practices
Wikipedia.com

About the Anti-Cross Site Scripting Library V1.5   The Microsoft Anti-Cross Site Scripting Library V1.5 is an encoding library, provided by the ASP.NET and Application Consulting & Engineering (ACE) teams at Microsoft, designed to help developers protect their Web-based applications from XSS attacks. This library differs from most encoding libraries in that it uses the principle-of-inclusions technique to provide protection against XSS attacks. This approach works by defining a valid or allowable set of characters, and encoding anything outside this set (invalid characters or potential attacks). It offers several advantages over other encoding schemes.

Microsoft recently released v3.0 of the Anti-Cross Site Scripting Library which is available for download at https://www.microsoft.com/downloads/details.aspx?FamilyId=051ee83c-5ccf-48ed-8463-02f56a6bfc09&displaylang;=en. You can also learn more from the CISG Blog

About the Application

The Contoso Bookmark Page is a simple Web application that is designed to allow friends to share their favorite bookmarks with one another. Users enter their name, a description, and the bookmark or link itself (for example, https://www.microsoft.com or https://www.asp.net).

Aa973813.anticross_sitescript02(en-us,MSDN.10).gif

Figure 2. Contoso Bookmark Page Web interface

The data is saved in a file called "bookmarks.txt" in the App Data Web application folder and is read by the application when displaying any saved bookmarks. When a bookmark is submitted, the user is shown the following thank you screen and provided a link to return back to the Web application.

Aa973813.anticross_sitescript03(en-us,MSDN.10).gif

Figure 3. Confirmation thank you page with embedded untrusted user input

If the application successfully saves the data provided by the user, listings for bookmarks are updated and any other users using the Web application can begin using the saved bookmarks.

Aa973813.anticross_sitescript04(en-us,MSDN.10).gif

Figure 4. Exploring saved bookmark links

Finally, the user can reset the bookmark file by clicking Delete Bookmark File, which will cause the file bookmarks.txt to be deleted from disk.

Attacking the Application

In order for a malicious user to conduct an XSS attack against the application, they first need to find a vector where all of the following are true:

  • The application is not validating input; and
  • The application is not encoding output that contains untrusted inputs.

One area of the Contoso Bookmark Page application that meets the above attack requirements is the thank you page. When a user submits a link and the data is saved, the application responds by thanking the user for the submission.

Aa973813.anticross_sitescript05(en-us,MSDN.10).gif

Figure 5. XSS attack vector in the ThankYou.aspx page

Note that the thank you page output is formed using untrusted user input without validation and using that input in response data without prior encoding. A quick inspection of the above code responsible for generating the thank you message confirms this.

A malicious user can easily exploit this XSS vector by tricking a user into visiting the ThankYou.aspx page while passing script such as <script>alert('Xss Vector!')</script> into the Name parameter.

Aa973813.anticross_sitescript06(en-us,MSDN.10).gif

Figure 6. Exploiting the XSS vulnerability in the ThankYou.aspx page

As seen above, the script injected by the malicious user gets executed in the unsuspecting user's Web browser. Other XSS vectors similar to this exist in the Contoso Bookmark Page application. In the next section, we'll go through a more formal process of identifying and mitigating issues like these.

Note   Finding issues like XSS vectors in your application after it has been implemented can become very expensive very quickly. Wouldn't it be great if there was a way to anticipate and understand threats to an application early in the software development lifecycle (SDLC) before any code was implemented or significant resources committed? Well, there is, and that is a process we use here at Microsoft IT called "threat modeling."

Protecting the Application

To protect the Contoso Bookmark Page application from XSS attacks we first need to understand the vectors that malicious users can use to conduct such attacks. Ideally, we should have done this at design time using threat modeling and a tool such as TAM; however, we can still do this on applications that have already been implemented using the following steps:

  • Step 1: Review ASP.NET code that generates output.
  • Step 2: Determine whether output includes untrusted input parameters.
  • Step 3: Determine the context in which the untrusted input is used as output.
  • Step 4: Encode output.

In this section, we'll go through these steps using the Contoso Bookmark Page application and see how we can use the Microsoft Anti-Cross Site Scripting Library V1.5 to protect its users from XSS attacks.

Step 1: Review ASP.NET Code That Generates Output

Remember that in order for an XSS attack to succeed, malicious users must find a way to embed their input as part of the response data from the application; therefore, we need to identify code in the application that generates output. This might not always be an easy task, especially for large applications, and some output may not necessarily require encoding. In these situations, the following table may help you to coordinate the deluge of data:

Use Case Scenario Scenario Inputs Input Trusted? Scenario Outputs Output Contains Untrusted Input? Requires Encoding Encoding Method to Use
    [Yes/No]   [Yes/No] [Yes/No]  

To use this table, we start with what we know about the application— which, by the way, is the best approach. A few of the things in the table we can fill in immediately are:

  • Use case scenarios
  • Inputs into those use case scenarios
  • Whether the input is trusted or not
  • Outputs from the scenario

Note   If you aren't sure if input is trusted or not, always err on the side of caution and assume that it is not trusted. Examples of common untrusted input include:

  • Application variables
  • Cookies
  • Databases
  • Form fields
  • Query string variables
  • Session variables

Based on what we know from About the Application about the Contoso Bookmark Page application, here's what our table looks like:

Use Case Scenario Scenario Inputs Input Trusted? Scenario Outputs Output Contains Untrusted Input? Requires Encoding Encoding Method to Use
User adds a bookmark User name, Description, Bookmark No Bookmark entry written to file (bookmarks.txt)      
Application thanks user User name No Thank you message page      
User resets bookmark file Button click event Yes None      

At this point we've met our objective for this step, which was to understand which areas of code generate output. From the table, these are:

  • The code that writes the bookmark entry into the file.
  • The code that generates the thank you message to the user.

Step 2: Determine If Output Could Contain Untrusted Input

In this step, our objective is to determine if any of the output identified in the previous step could contain untrusted user input. Based on the input and output scenarios, our table now looks like this:

Use Case Scenario Scenario Inputs Input Trusted? Scenario Outputs Output Contains Untrusted Input? Requires Encoding Encoding Method to Use
User adds a bookmark User name, Description, Bookmark No Bookmark entry written to file (bookmarks.txt) Yes    
Application thanks user User name No Thank you message page Yes    
User resets bookmark file Button click event Yes None N/A    

Note   If you're unsure if the output contains untrusted input, err on the side of caution and assume it does.

Step 3: Determine Encoding Method to Use

In this step, our objective is to understand which encoding method (if necessary) we need to use to encode our Web response data. Output will require encoding if all of the following conditions are true in the table:

  • Input is not trusted (column 3 has a "No" response).
  • Output contains untrusted input (column 5 has a "Yes"response).
  • Output is used in a Web response data context.
Use Case Scenario Scenario Inputs Input Trusted? Scenario Outputs Output Contains Untrusted Input? Requires Encoding Encoding Method to Use
User adds a bookmark User name, Description, Bookmark No Bookmark entry written to file (bookmarks.txt) Yes No (output is written to file not Web response data)  
Application thanks user User name No Thank you message page Yes Yes  
User resets bookmark file Button click event Yes None N/A N/A  

Finally, we need to determine the encoding method we need to use. The following table will be helpful in determining which encoding method to use:

Encoding Method Should Be Used If … Example/Pattern
HtmlEncode Untrusted input is used in HTML output except when assigning to an HTML attribute. <a href="http://www.contoso.com">Click Here [Untrusted input]</a>
HtmlAttributeEncode Untrusted input is used as an HTML attribute <hr noshade size=[Untrusted input]>
JavaScriptEncode Untrusted input is used within a JavaScript context <script type="text/javascript">

[Untrusted input]

</script>

UrlEncode Untrusted input is used in a URL (such as a value in a querystring) <a href="https://search.msn.com/results.aspx?q=[Untrusted-input]">Click Here!</a>
VisualBasicScriptEncode Untrusted input is used within a Visual Basic Script context <script type="text/vbscript" language="vbscript">

[Untrusted input]

</script>

XmlEncode Untrusted input is used in XML output, except when assigning to an XML attribute <xml_tag>[Untrusted input]</xml_tag>
XmlAttributeEncode Untrusted input is used as an XML attribute <xml_tag attribute=[Untrusted input]>Some Text</xml_tag>

Our final table now looks like this:

Use Case Scenario Scenario Inputs Input Trusted? Scenario Outputs Output Contains Untrusted Input? Requires Encoding Encoding Method to Use
User adds a bookmark User name, Description, Bookmark No Bookmark entry written to file (bookmarks.txt) Yes No (output is written to file not Web response data) N/A
Application thanks user User name No Thank you message page Yes Yes User name (HtmlEncode since we are writing in an HTML context)
User resets bookmark file Button click event Yes None N/A N/A N/A

According to our table, we only need to encode the untrusted input used in the scenario where the application thanks the user for their bookmark entry.

Step 4: Encode Output

Now that we've determined which scenarios require encoding, all that's left to do is add the Microsoft Anti-Cross Site Scripting Library to our project and encode the untrusted input as it is embedded in response data.

After you've installed the Microsoft Anti-Cross Site Scripting Library, you can add the reference to the library in your ASP.NET using the following steps:

  1. Right-click the project name.
  2. Select Add Reference … option.
  3. Under Browse, look in the library installation directory (%program files%\Microsoft Corporation\Anti-Cross Site Scripting Library V1.5\Library\[.NET 1.1|.NET 2.0]) and add the reference to appropriate library binary.

Aa973813.anticross_sitescript07(en-us,MSDN.10).gif

Figure 7. Adding the reference to the AntiXssLibrary.dll to Visual Studio project

After we've added the reference to the Anti-Cross Site Scripting Library, we encode the output generated by the thank you page. To do this:

  1. Open the code-behind for ThankYou.aspx (ThankYou.aspx.cs).

  2. Add the directive using Microsoft.Security.Application.

  3. In the Page_Load method, replace the following code:

    // Get the query string parameter 'Name', if it wasn't specified don't write anything
    String Name = Request.QueryString["Name"];

    with

    // Get the query string parameter 'Name', if it wasn't specified don't write anything         
    

String Name = AntiXss.HtmlEncode(Request.QueryString["Name"]);

  1. Rebuild the Web application.

Now any attempts to exploit the thank you page by injecting script into the Name parameter in the query string will fail because the untrusted data is encoded into a nonexecutable form by the AntiXss.HtmlEncode method.

Aa973813.anticross_sitescript08(en-us,MSDN.10).gif

Figure 8. Success! Encoding XSS injected data into nonexecutable form

Note   A common mistake is to encode untrusted input more than once. This often results in outputs being displayed incorrectly. For instance, an input of Hello Microsoft! encoded with the Microsoft.Security.Application.AntiXss.HtmlEncode method twice causes the browser to display Hello Microsoft&#38;&#35;33&#59;. Remember to encode untrusted inputs only once!

Defense-in-Depth

To make malicious users' jobs even harder, there are some additional layers of defense that can be implemented to further prevent XSS attacks in the Contoso Bookmark Page application.

  • Set the ASP.NET validateRequest attribute to true:

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="ThankYou.aspx.cs" Inherits="ThankYou"
    validateRequest="true" %>

  • Perform input validation on all inputs to the application (see How To: Use Regular Expressions to Constrain Input in ASP.NET).

  • While not related to protecting our application from XSS attacks, an additional step we can take to limit our overall attack surface is to lower the privilege with which the application starts. By default, applications will start with full trust, and so if a malicious user is able to compromise the application they will also have full-trust privileges. Our application simply creates a file, writes to it, and reads from it, which doesn't require full trust to run correctly. We can lower its trust level to medium by specifying its level in the web.config file as follows:

    <?xml version="1.0"?>
    <configuration xmlns="https://schemas.microsoft.com/.NetConfiguration/v2.0">
    <system.web>
    <!-- Lowers trust level of application to only what we need, instead of full -->
    <trust level="Medium"/>
    </system.web> </configuration>

Additional XSS Attacks

We forgot one use case scenario! That is where the user views the currently loaded bookmarks (for instance, another user simply navigates to the main site). In this instance, the input into this scenario is the bookmarks.txt file. Even though we fixed the thank you page problem, the data (injected script and all) still gets saved into the bookmarks.txt file.

Aa973813.anticross_sitescript09(en-us,MSDN.10).gif

Figure 9. Persistent XSS injected data in the bookmarks.txt file

When the user refreshes the main page and the bookmarks get displayed, the injected script is executed!

Aa973813.anticross_sitescript10(en-us,MSDN.10).gif

Figure 10. Persistent XSS attack

Note that the malicious user could also have injected the script into the Description or Bookmark fields, not just the Name field. We need to encode any data we read from the bookmarks file as we're displaying it on the browser. Our additional XSS encoding table entry looks like this:

Use Case Scenario Scenario Inputs Input Trusted? Scenario Outputs Output Contains Untrusted Input? Requires Encoding Encoding Method to Use
User views saved bookmarks Bookmark file data No Contributed by, description, and link data is displayed in browser on main page Yes Yes Name (HtmlEncode since we are writing in an HTML context)

Description (HtmlEncode since we are writing in an HTML context)

BookmarkLink (No encoding, but requires input validation. Remember we can only use UrlEncode to encode values used in a URL and not the URL itself, so we need to perform input validation with regular expressions)

Conclusion

XSS attacks are easily one of the most common encountered by IT teams, and with the number of Web applications increasing each day, that number is expected to continue growing. Developers need to — make that must — protect their customers by employing best practices to fend off these attacks such as:

  • Validating and constraining input.
  • Encoding output.

In this tutorial I've shown you how to use some of the Anti-Cross Site Scripting Library V1.5 encoding methods as well as a method for breaking down use case scenarios and assessing them for potential XSS vectors using a simple table. I also mentioned some important encoding tips such as:

  • Encoding untrusted inputs only once.
  • Using UrlEncode to encode untrusted values used in URL query strings. If the untrusted input is a URL itself, such as is the case with our application, then input validation with regular expressions against the URL is the proper countermeasure.

With that, you have all the necessary knowledge and tools you need to start eliminating those nasty XSS bugs. Happy hunting!

About the Author

Kevin Lam is a Senior Security Strategist at Microsoft with over seven years experience in information security. At Microsoft he is responsible for conducting security assessments (security code review, penetration testing, and architectural review) for high-valued targets and critical business services. Kevin is also responsible for driving security strategy and policy related to application security. Kevin recently published a book for Microsoft Press titled Assessing Network Security (ISBN: 0-7356-2033-4) and has also been published in literature such as Microsoft TechNet magazine. He is a frequent speaker and has participated on several expert security panel discussions. Kevin's blog is located at https://blogs.msdn.com/kevinlam.

Kevin works for the ACE Services team, which helps customers secure their enterprise environments through services such as training, code reviews, threat modeling, infrastructure reviews and other best practices developed and used internally at Microsoft IT. If you are interested in learning more about how these services can help your organization improve its security posture, please contact sdl-it@microsoft.com or visit the ACE Services team at https://msdn2.microsoft.com/en-us/security/aa570410.aspx.