--- title: Prevent Cross-Site Scripting (XSS) in ASP.NET Core author: rick-anderson description: Learn about Cross-Site Scripting (XSS) and techniques for addressing this vulnerability in an ASP.NET Core app. ms.author: riande ms.date: 10/02/2018 no-loc: [Home, Privacy, Kestrel, appsettings.json, "ASP.NET Core Identity", cookie, Cookie, Blazor, "Blazor Server", "Blazor WebAssembly", "Identity", "Let's Encrypt", Razor, SignalR] uid: security/cross-site-scripting --- # Prevent Cross-Site Scripting (XSS) in ASP.NET Core By [Rick Anderson](https://twitter.com/RickAndMSFT) Cross-Site Scripting (XSS) is a security vulnerability which enables an attacker to place client side scripts (usually JavaScript) into web pages. When other users load affected pages the attacker's scripts will run, enabling the attacker to steal cookies and session tokens, change the contents of the web page through DOM manipulation or redirect the browser to another page. XSS vulnerabilities generally occur when an application takes user input and outputs it to a page without validating, encoding or escaping it. ## Protecting your application against XSS At a basic level XSS works by tricking your application into inserting a `"; }
``` The preceding markup generates the following HTML: ```html
``` The preceding code generates the following output: ``` ``` >[!WARNING] > Do ***NOT*** concatenate untrusted input in JavaScript to create DOM elements or use `document.write()` on dynamically generated content. > > Use one of the following approaches to prevent code from being exposed to DOM-based XSS: > * `createElement()` and assign property values with appropriate methods or properties such as `node.textContent=` or `node.InnerText=`. > * `document.CreateTextNode()` and append it in the appropriate DOM location. > * `element.SetAttribute()` > * `element[attribute]=` ## Accessing encoders in code The HTML, JavaScript and URL encoders are available to your code in two ways, you can inject them via [dependency injection](xref:fundamentals/dependency-injection) or you can use the default encoders contained in the `System.Text.Encodings.Web` namespace. If you use the default encoders then any you applied to character ranges to be treated as safe won't take effect - the default encoders use the safest encoding rules possible. To use the configurable encoders via DI your constructors should take an *HtmlEncoder*, *JavaScriptEncoder* and *UrlEncoder* parameter as appropriate. For example; ```csharp public class HomeController : Controller { HtmlEncoder _htmlEncoder; JavaScriptEncoder _javaScriptEncoder; UrlEncoder _urlEncoder; public HomeController(HtmlEncoder htmlEncoder, JavaScriptEncoder javascriptEncoder, UrlEncoder urlEncoder) { _htmlEncoder = htmlEncoder; _javaScriptEncoder = javascriptEncoder; _urlEncoder = urlEncoder; } } ``` ## Encoding URL Parameters If you want to build a URL query string with untrusted input as a value use the `UrlEncoder` to encode the value. For example, ```csharp var example = "\"Quoted Value with spaces and &\""; var encodedValue = _urlEncoder.Encode(example); ``` After encoding the encodedValue variable will contain `%22Quoted%20Value%20with%20spaces%20and%20%26%22`. Spaces, quotes, punctuation and other unsafe characters will be percent encoded to their hexadecimal value, for example a space character will become %20. >[!WARNING] > Don't use untrusted input as part of a URL path. Always pass untrusted input as a query string value. ## Customizing the Encoders By default encoders use a safe list limited to the Basic Latin Unicode range and encode all characters outside of that range as their character code equivalents. This behavior also affects Razor TagHelper and HtmlHelper rendering as it will use the encoders to output your strings. The reasoning behind this is to protect against unknown or future browser bugs (previous browser bugs have tripped up parsing based on the processing of non-English characters). If your web site makes heavy use of non-Latin characters, such as Chinese, Cyrillic or others this is probably not the behavior you want. You can customize the encoder safe lists to include Unicode ranges appropriate to your application during startup, in `ConfigureServices()`. For example, using the default configuration you might use a Razor HtmlHelper like so; ```html

This link text is in Chinese: @Html.ActionLink("汉语/漢語", "Index")

``` When you view the source of the web page you will see it has been rendered as follows, with the Chinese text encoded; ```html

This link text is in Chinese: 汉语/漢語

``` To widen the characters treated as safe by the encoder you would insert the following line into the `ConfigureServices()` method in `startup.cs`; ```csharp services.AddSingleton( HtmlEncoder.Create(allowedRanges: new[] { UnicodeRanges.BasicLatin, UnicodeRanges.CjkUnifiedIdeographs })); ``` This example widens the safe list to include the Unicode Range CjkUnifiedIdeographs. The rendered output would now become ```html

This link text is in Chinese: 汉语/漢語

``` Safe list ranges are specified as Unicode code charts, not languages. The [Unicode standard](https://unicode.org/) has a list of [code charts](https://www.unicode.org/charts/index.html) you can use to find the chart containing your characters. Each encoder, Html, JavaScript and Url, must be configured separately. > [!NOTE] > Customization of the safe list only affects encoders sourced via DI. If you directly access an encoder via `System.Text.Encodings.Web.*Encoder.Default` then the default, Basic Latin only safelist will be used. ## Where should encoding take place? The general accepted practice is that encoding takes place at the point of output and encoded values should never be stored in a database. Encoding at the point of output allows you to change the use of data, for example, from HTML to a query string value. It also enables you to easily search your data without having to encode values before searching and allows you to take advantage of any changes or bug fixes made to encoders. ## Validation as an XSS prevention technique Validation can be a useful tool in limiting XSS attacks. For example, a numeric string containing only the characters 0-9 won't trigger an XSS attack. Validation becomes more complicated when accepting HTML in user input. Parsing HTML input is difficult, if not impossible. Markdown, coupled with a parser that strips embedded HTML, is a safer option for accepting rich input. Never rely on validation alone. Always encode untrusted input before output, no matter what validation or sanitization has been performed.