Skip to main content
Cross-Site Scripting (XSS) is a web security vulnerability by which a malicious user is able to inject content into a web page that will impact other website visitors.  The injected content could then perform any number of unwarranted acts, including hijacking the user’s session, stealing private information, or performing a denial-of-service attack.  An XSS exploit often involves manipulating an online form that presents some piece of the input back to the user, such as a search form.  In this post we’ll explore some strategies to assist developers with mitigating XSS vulnerabilities, including input validation, sanitation, and output encoding.

Cross-Site Scripting Vulnerabilities

The classic XSS security exploit involves tricking a webpage to execute malicious Javascript code, which exposes the user’s authentication cookies to another website, all without the user’s knowledge.  This allows the owner of the malicious website to then spoof the user’s log in session on the original web site, effectively allowing them to hijack the original user’s session and gain access to their account and information.  On an e-commerce site, the attacker could gain access to the user’s address or payment information, and potentially even place fraudulent orders. Another form of a XSS exploit can be used to launch a denial-of-service (DOS) attack against a website.  This exploit involves injecting a <meta http-equiv=”refresh”> tag into the page, or Javascript that makes AJAX requests or alters the window.location.  By refreshing the page very quickly, or by making large number of web requests, it is possible to overload a website’s server.

Mitigation Strategies

The specific techniques for mitigating XSS vary by the server-side framework (PHP, ASP.NET, etc.) in use.  However, the overarching concept is very straight-forward: never trust user input.  Before working with any value that comes from the client (form fields, the URL query string, cookies, and HTTP headers) the value must be validated to the best of the application’s ability. It is important to remember that validation must take place on the web server.  Client-side validation techniques are for a legitimate user’s benefit – to help catch any errors or omissions without the need for a network round-trip.  Nothing is preventing an attacker from disabling Javascript, or even crafting an HTTP request without using a web browser at all. Server-side validation can take many forms:
  • Expecting a numeric identifier?  Try converting the value to a number.  Check that it is within the expected range (e.g. non-negative, non-zero)
  • Is the value expected to be one out of a few possible values, such as with a checkbox list?  Verify that the selected value(s) are in fact among of the possible options.
  • Need to accept HTML from the user?  Sanitize the input by ensuring that any <script> tags and other potentially malicious code is removed.

Mitigating XSS with ASP.NET

We’ll be looking at some specific strategies for mitigating XSS utilizing ASP.NET – both the WebForms and MVC frameworks.  These strategies include validation, output encoding, and sanitation.

ASP.NET Input Validation

By default, ASP.NET applications throw an HttpRequestValidationException in the event that HTML (or other potentially malicious values) are detected in the user input, which terminates the request.  Of course, such a blanket strategy can’t cover every possible case – further validation will be needed to ensure that input matches expectations.   Additionally, some applications need to be able to work with HTML, such as Web Content Management Systems (CMS).  In these cases, the CMS may disable this validation option entirely – even for other pages in the application.  It is important to keep this in mind when implementing custom functionality on a CMS-based website. Besides disabling the request validation option globally, there are several options for temporarily lifting validation for specific needs.  WebForms pages have a ValidateRequest attribute that can be set to “false”, and MVC controller actions can be decorated with a [ValidateInput(false)] attribute.  Individual MVC view model properties can also be decorated with [AllowHtml] for granular control. By opening only specific pages or components of pages that need to allow HTML the developer can ensure that the remainder of the application continues to benefit from built-in validation. In addition to the built-in validation logic, the application itself should validate specific values to ensure they meet expectations.  Let’s look at a brief example of resolving an XSS vulnerability.  Consider the following method:The code does several things well:
  • Ensures the query string values are not null.
  • Converts one parameter to a static type - integer (although, it does not do so safely).
At the same time, this code has several security issues.
  • Since the “ContentTypeId” parameter is not safely converted to an integer, the possibility exists for a runtime exception to be thrown, which in turn could show an attacker valuable information such as a stack trace.
  • The parameter “ContentId” is not sanitized, and as such this code is vulnerable to an XSS attack.
This code is vulnerable because of how these query string values are then used – they are written to a link’s href attribute.  It is possible that an attacker could alter the page’s markup to include a malicious script, or trick the user into visiting a different web page. Next let’s look at some improvements to the code that will eliminate this vulnerability.First, the ContentTypeID is converted to an integer in a safe manner – no exception will be thrown if the parameter is not actually an integer.  Second, the ContentID is validated against a regular expression to ensure it contains only alphanumeric characters.  This regex provides a “whitelist” of acceptable characters – all others will be rejected (removed, in this case). Other techniques for validating input with ASP.NET WebForms include Validation Controls such as the RequiredFieldValidator, RegularExpressionValidator, and CustomValidator.  These controls can automatically handle both server and client-side validation for a variety of purposes. ASP.NET MVC provides some additional validation capabilities, often with minor effort on the part of the developer.  MVC’s Model Binding allows for a developer to specify that a particular form field should be treated as a specific type of value, such as an Integer, or Enumerated value.  The framework takes care of validating and converting the value into the appropriate type.  This eliminates the need for boilerplate logic such as Int.TryParse() and Enum.TryParse(). MVC also supports a declarative validation technique utilizing Attributes that are applied to view model properties such as [Required], [MinLength], etc.  During the model binding stage of the request, MVC will automatically validate that the model meets the specifications given, and will generate error messages for invalid properties.  By writing custom validation attributes, a developer can implement complex validation logic very cleanly. Further information on ASP.NET WebForms and MVC validation can be found in the articles below.

ASP.NET Input Sanitation

In the case that the application should accept HTML input from the user, it is important to verify that the HTML does not contain potentially malicious markup or Javascript.  Any HTML tags or attributes that could be used to an attacker’s advantage should be removed.  For example, <script> and <meta http-equiv> should be removed, and event handlers such as onclick and even href attributes need to be handled with caution.  Due to the complexities involved, it is recommended to utilize a .NET library that whitelists only specific HTML elements and attributes.  Alternatively, a language such as Markdown could be used to avoid working with HTML all-together.

ASP.NET Output Encoding

Output encoding is the process of replacing symbols that have special meaning (such as < and > in HTML) with encoded versions (&lt; and &gt;).  This ensures that the web browser does not interpret the text as HTML, and instead, simply display the text on the page. With encoding:CommentsWithout encoding:Malicious codeEncoding ensures that any malicious code is simply shown on the page rather than being executed by the browser. Why are we showing malicious code on the page instead of removing it?  The validation and sanitation strategies discussed earlier are intended to catch any malicious input earlier in the process.  However, defending against security threats requires a robust approach.  By adhering to a defense in depth strategy, the application can be secured in many different ways which each add to the overall security.  If one component isn’t capable of detecting a problem, perhaps another will prevent a serious vulnerability. Exactly how we approach output encoding in ASP.NET depends on the framework.  In WebForms, we could either use a Literal user control, or the ASP syntax with a method call. With a Literal user control, just set the Mode attribute to “Encode”.Literal user controlFor ASP syntax, use the HttpUtility.HtmlEncode() method.ASP syntaxWith ASP.NET MVC and the Razor view engine, any String value is automatically encoded when using the @ operator.  In fact, to output un-encoded HTML a separate method call is required: @Html.Raw().Razor view engine 1Razor view engine 2

Next Steps

We’ve explored some common techniques for mitigating XSS vulnerabilities on ASP.NET websites.  By validating and sanitizing user input, and encoding the input before writing it back to the page, a developer can ensure that malicious users are not able to inject markup and code into other user’s web pages.  The most important thing to keep in mind is that any information from the user’s request is inherently untrustworthy.  By performing thorough validation of the input prior to use, a developer ensures the safety of the site’s visitors, the application itself, and its hosting environment.  For more information about XSS and other web application security vulnerabilities, we encourage you to review the OWASP Top Ten vulnerabilities listing.