Zapobiegaj skryptom między lokacjami (XSS) w ASP.NET CorePrevent Cross-Site Scripting (XSS) in ASP.NET Core

Autor: Rick AndersonBy Rick Anderson

Skrypt między lokacjami (XSS) stanowi lukę w zabezpieczeniach, która umożliwia atakującemu umieszczenie skryptów po stronie klienta (zazwyczaj JavaScript) na stronach sieci Web.Cross-Site Scripting (XSS) is a security vulnerability which enables an attacker to place client side scripts (usually JavaScript) into web pages. Gdy inni użytkownicy ładują strony, których dotyczy skrypt osoby atakującej, co umożliwi atakującemu kradzież cookie tokenów s i sesji, należy zmienić zawartość strony sieci Web za pomocą manipulowania dom lub przekierować przeglądarkę na inną stronę.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. Luki w zabezpieczeniach XSS są zwykle wykonywane, gdy aplikacja pobiera dane wejściowe użytkownika i wyprowadza ją na stronę bez sprawdzania poprawności, kodowania lub ucieczki.XSS vulnerabilities generally occur when an application takes user input and outputs it to a page without validating, encoding or escaping it.

Ochrona aplikacji przed XSSProtecting your application against XSS

Na poziomie podstawowym ataki polegają na zalewaniu aplikacji do wstawienia <script> tagów do renderowanej strony lub przez wstawienie On* zdarzenia do elementu.At a basic level XSS works by tricking your application into inserting a <script> tag into your rendered page, or by inserting an On* event into an element. Deweloperzy powinni używać następujących kroków zapobiegania, aby uniknąć wprowadzenia XSS do aplikacji.Developers should use the following prevention steps to avoid introducing XSS into their application.

  1. Nigdy nie umieszczaj niezaufanych danych w danych wejściowych HTML, chyba że wykonujesz poniższą procedurę.Never put untrusted data into your HTML input, unless you follow the rest of the steps below. Niezaufane dane to wszelkie dane, które mogą być kontrolowane przez atakującego, dane wejściowe formularza HTML, ciągi zapytań, nagłówki HTTP, nawet źródła danych z bazy danych, ponieważ osoba atakująca może mieć możliwość naruszenia bazy danych, nawet jeśli nie mogą naruszyć aplikacji.Untrusted data is any data that may be controlled by an attacker, HTML form inputs, query strings, HTTP headers, even data sourced from a database as an attacker may be able to breach your database even if they cannot breach your application.

  2. Przed umieszczeniem niezaufanych danych wewnątrz elementu HTML upewnij się, że jest on zakodowany w formacie HTML.Before putting untrusted data inside an HTML element ensure it's HTML encoded. Kodowanie HTML przyjmuje takie znaki, jak < i zmienia je na bezpieczną formę, taką jak & lt;HTML encoding takes characters such as < and changes them into a safe form like &lt;

  3. Przed umieszczeniem niezaufanych danych w atrybucie HTML upewnij się, że jest on zakodowany w formacie HTML.Before putting untrusted data into an HTML attribute ensure it's HTML encoded. Kodowanie atrybutu HTML jest nadzbiorem kodowania HTML i koduje dodatkowe znaki takie jak "i".HTML attribute encoding is a superset of HTML encoding and encodes additional characters such as " and '.

  4. Przed umieszczeniem niezaufanych danych w języku JavaScript Umieść dane w elemencie HTML, którego zawartość jest pobierana w czasie wykonywania.Before putting untrusted data into JavaScript place the data in an HTML element whose contents you retrieve at runtime. Jeśli to nie jest możliwe, upewnij się, że dane są kodowane w języku JavaScript.If this isn't possible, then ensure the data is JavaScript encoded. Kodowanie JavaScript pobiera niebezpieczne znaki dla języka JavaScript i zastępuje je szesnastkową, na przykład będzie < kodowane jako \u003C .JavaScript encoding takes dangerous characters for JavaScript and replaces them with their hex, for example < would be encoded as \u003C.

  5. Przed umieszczeniem niezaufanych danych w ciągu zapytania adresu URL upewnij się, że adres URL został zakodowany.Before putting untrusted data into a URL query string ensure it's URL encoded.

Kodowanie HTML przy użyciu RazorHTML Encoding using Razor

RazorAparat używany w MVC automatycznie koduje wszystkie dane wyjściowe pochodzące ze zmiennych, chyba że naprawdę nie zadziała to w ten sposób.The Razor engine used in MVC automatically encodes all output sourced from variables, unless you work really hard to prevent it doing so. Używa reguł kodowania atrybutu języka HTML za każdym razem, gdy używasz @ dyrektywy.It uses HTML attribute encoding rules whenever you use the @ directive. Ponieważ kodowanie atrybutu HTML jest nadzbiorem kodowania HTML, oznacza to, że nie trzeba niczego zachodzić, niezależnie od tego, czy należy użyć kodowania HTML czy kodowania atrybutów HTML.As HTML attribute encoding is a superset of HTML encoding this means you don't have to concern yourself with whether you should use HTML encoding or HTML attribute encoding. Musisz się upewnić, że w kontekście HTML użyto tylko @, a nie przy próbie wstawienia niezaufanych danych wejściowych bezpośrednio do języka JavaScript.You must ensure that you only use @ in an HTML context, not when attempting to insert untrusted input directly into JavaScript. Pomocnicy tagów również kodują dane wejściowe, które są używane w parametrach tagów.Tag helpers will also encode input you use in tag parameters.

Wykonaj następujące czynności Razor :Take the following Razor view:

@{
       var untrustedInput = "<\"123\">";
   }

   @untrustedInput

Ten widok wyprowadza zawartość zmiennej untrustedInput .This view outputs the contents of the untrustedInput variable. Ta zmienna zawiera znaki, które są używane w atakach XSS, mianowicie < "i > .This variable includes some characters which are used in XSS attacks, namely <, " and >. Badanie źródła pokazuje renderowane dane wyjściowe kodowane jako:Examining the source shows the rendered output encoded as:

&lt;&quot;123&quot;&gt;

Ostrzeżenie

ASP.NET Core MVC udostępnia HtmlString klasę, która nie jest automatycznie zakodowana w danych wyjściowych.ASP.NET Core MVC provides an HtmlString class which isn't automatically encoded upon output. Tego elementu nie należy używać w połączeniu z niezaufanymi danymi wejściowymi, ponieważ spowoduje to ujawnienie luki w zabezpieczeniach XSS.This should never be used in combination with untrusted input as this will expose an XSS vulnerability.

Kodowanie JavaScript przy użyciu RazorJavaScript Encoding using Razor

Czasami może się okazać, że chcesz wstawić wartość do języka JavaScript, aby przetworzyć ją w widoku.There may be times you want to insert a value into JavaScript to process in your view. Istnieją dwa sposoby, aby to zrobić.There are two ways to do this. Najbezpieczniejszym sposobem wstawiania wartości jest umieszczenie wartości w atrybucie danych tagu i pobranie go w języku JavaScript.The safest way to insert values is to place the value in a data attribute of a tag and retrieve it in your JavaScript. Przykład:For example:

@{
    var untrustedInput = "<script>alert(1)</script>";
}

<div id="injectedData"
     data-untrustedinput="@untrustedInput" />

<div id="scriptedWrite" />
<div id="scriptedWrite-html5" />

<script>
    var injectedData = document.getElementById("injectedData");

    // All clients
    var clientSideUntrustedInputOldStyle =
        injectedData.getAttribute("data-untrustedinput");

    // HTML 5 clients only
    var clientSideUntrustedInputHtml5 =
        injectedData.dataset.untrustedinput;

    // Put the injected, untrusted data into the scriptedWrite div tag.
    // Do NOT use document.write() on dynamically generated data as it
    // can lead to XSS.

    document.getElementById("scriptedWrite").innerText += clientSideUntrustedInputOldStyle;

    // Or you can use createElement() to dynamically create document elements
    // This time we're using textContent to ensure the data is properly encoded.
    var x = document.createElement("div");
    x.textContent = clientSideUntrustedInputHtml5;
    document.body.appendChild(x);

    // You can also use createTextNode on an element to ensure data is properly encoded.
    var y = document.createElement("div");
    y.appendChild(document.createTextNode(clientSideUntrustedInputHtml5));
    document.body.appendChild(y);

</script>

Powyższy znacznik generuje następujący kod HTML:The preceding markup generates the following HTML:

<div id="injectedData"
     data-untrustedinput="&lt;script&gt;alert(1)&lt;/script&gt;" />

<div id="scriptedWrite" />
<div id="scriptedWrite-html5" />

<script>
    var injectedData = document.getElementById("injectedData");

    // All clients
    var clientSideUntrustedInputOldStyle =
        injectedData.getAttribute("data-untrustedinput");

    // HTML 5 clients only
    var clientSideUntrustedInputHtml5 =
        injectedData.dataset.untrustedinput;

    // Put the injected, untrusted data into the scriptedWrite div tag.
    // Do NOT use document.write() on dynamically generated data as it can
    // lead to XSS.

    document.getElementById("scriptedWrite").innerText += clientSideUntrustedInputOldStyle;

    // Or you can use createElement() to dynamically create document elements
    // This time we're using textContent to ensure the data is properly encoded.
    var x = document.createElement("div");
    x.textContent = clientSideUntrustedInputHtml5;
    document.body.appendChild(x);

    // You can also use createTextNode on an element to ensure data is properly encoded.
    var y = document.createElement("div");
    y.appendChild(document.createTextNode(clientSideUntrustedInputHtml5));
    document.body.appendChild(y);

</script>

Poprzedni kod generuje następujące dane wyjściowe:The preceding code generates the following output:

<script>alert(1)</script>
<script>alert(1)</script>
<script>alert(1)</script>

Ostrzeżenie

Do * nie można łączyć niezaufanych danych wejściowych w języku JavaScript w celu tworzenia elementów dom lub korzystania document.write() z dynamicznie generowanej zawartości.Do * NOT _ concatenate untrusted input in JavaScript to create DOM elements or use document.write() on dynamically generated content.

Użyj jednego z poniższych metod, aby zapobiec ujawnieniu kodu w oparciu o dane z modelu DOM: _ createElement() i przypisz wartości właściwości z odpowiednimi metodami lub właściwościami, takimi jak node.textContent= lub węzłem. InnerText = ".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() i Dołącz je do odpowiedniej lokalizacji DOM.document.CreateTextNode() and append it in the appropriate DOM location.
  • element.SetAttribute()
  • element[attribute]=

Uzyskiwanie dostępu do koderów w kodzieAccessing encoders in code

Kodery HTML, JavaScript i URL są dostępne dla kodu na dwa sposoby, można je wstrzyknąć za pośrednictwem iniekcji zależności lub użyć domyślnych koderów zawartych w System.Text.Encodings.Web przestrzeni nazw.The HTML, JavaScript and URL encoders are available to your code in two ways, you can inject them via dependency injection or you can use the default encoders contained in the System.Text.Encodings.Web namespace. Jeśli używasz koderów domyślnych, wszystkie zastosowane do zakresów znaków, które mają być traktowane jako bezpieczne, nie zaczną obowiązywać — domyślne kodery będą używać najbezpieczniejszych reguł kodowania.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.

Aby użyć konfigurowalnych koderów za pośrednictwem narzędzi, konstruktory powinny przyjmować parametr HtmlEncode , JavaScriptEncoder i UrlEncoder , zgodnie z potrzebami.To use the configurable encoders via DI your constructors should take an HtmlEncoder , JavaScriptEncoder and UrlEncoder parameter as appropriate. Na przykład:For example;

public class HomeController : Controller
   {
       HtmlEncoder _htmlEncoder;
       JavaScriptEncoder _javaScriptEncoder;
       UrlEncoder _urlEncoder;

       public HomeController(HtmlEncoder htmlEncoder,
                             JavaScriptEncoder javascriptEncoder,
                             UrlEncoder urlEncoder)
       {
           _htmlEncoder = htmlEncoder;
           _javaScriptEncoder = javascriptEncoder;
           _urlEncoder = urlEncoder;
       }
   }

Parametry kodowania adresu URLEncoding URL Parameters

Jeśli chcesz skompilować ciąg zapytania URL z niezaufanymi danymi wejściowymi jako wartość, użyj UrlEncoder do kodowania wartości.If you want to build a URL query string with untrusted input as a value use the UrlEncoder to encode the value. Przykład:For example,

var example = "\"Quoted Value with spaces and &\"";
   var encodedValue = _urlEncoder.Encode(example);

Po kodowaniu zmienna encodedValue będzie zawierać %22Quoted%20Value%20with%20spaces%20and%20%26%22 .After encoding the encodedValue variable will contain %22Quoted%20Value%20with%20spaces%20and%20%26%22. Spacje, cudzysłowy, interpunkcja i inne niebezpieczne znaki będą zakodowane procentowo na ich wartość szesnastkową, na przykład znak spacji stanie się %20.Spaces, quotes, punctuation and other unsafe characters will be percent encoded to their hexadecimal value, for example a space character will become %20.

Ostrzeżenie

Nie używaj niezaufanych danych wejściowych jako części ścieżki URL.Don't use untrusted input as part of a URL path. Zawsze przekazuj niezaufane dane wejściowe jako wartość ciągu zapytania.Always pass untrusted input as a query string value.

Dostosowywanie koderówCustomizing the Encoders

Domyślnie kodery wykorzystują bezpieczną listę ograniczoną do podstawowego zakresu Unicode w języku łacińskim i kodują wszystkie znaki poza tym zakresem jako odpowiedniki kodu znaku.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. To zachowanie ma także wpływ na Razor renderowanie TagHelper i HtmlHelper, ponieważ użyje koderów do wyprowadzania ciągów.This behavior also affects Razor TagHelper and HtmlHelper rendering as it will use the encoders to output your strings.

W związku z tym należy chronić przed nieznanymi lub przyszłymi błędami przeglądarki (poprzednie błędy przeglądarki wyzwolenie analizy na podstawie przetwarzania znaków innych niż angielski).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). Jeśli witryna sieci Web wykonuje duże użycie znaków innych niż łacińskie, takich jak chińskie, cyrylica lub inne, to prawdopodobnie zachowanie nie jest wymagane.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.

Można dostosować listy bezpiecznych koderów, aby uwzględnić zakresy Unicode odpowiednie dla aplikacji podczas uruchamiania, w programie ConfigureServices() .You can customize the encoder safe lists to include Unicode ranges appropriate to your application during startup, in ConfigureServices().

Na przykład przy użyciu konfiguracji domyślnej można użyć Razor HtmlHelper podobnej do tego;For example, using the default configuration you might use a Razor HtmlHelper like so;

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

Po wyświetleniu źródła strony sieci Web zobaczysz, że został on wyrenderowany w następujący sposób, z zakodowanym tekstem w języku chińskim.When you view the source of the web page you will see it has been rendered as follows, with the Chinese text encoded;

<p>This link text is in Chinese: <a href="/">&#x6C49;&#x8BED;/&#x6F22;&#x8A9E;</a></p>

Aby rozszerzyć znaki traktowane jako bezpieczne przez koder, należy wstawić następujący wiersz do ConfigureServices() metody w startup.cs ;To widen the characters treated as safe by the encoder you would insert the following line into the ConfigureServices() method in startup.cs;

services.AddSingleton<HtmlEncoder>(
     HtmlEncoder.Create(allowedRanges: new[] { UnicodeRanges.BasicLatin,
                                               UnicodeRanges.CjkUnifiedIdeographs }));

Ten przykład rozszerza bezpieczną listę w celu uwzględnienia zakresu Unicode CjkUnifiedIdeographs.This example widens the safe list to include the Unicode Range CjkUnifiedIdeographs. Renderowane dane wyjściowe staną się terazThe rendered output would now become

<p>This link text is in Chinese: <a href="/">汉语/漢語</a></p>

Zakresy bezpiecznych list są określone jako wykresy kodu Unicode, a nie Języki.Safe list ranges are specified as Unicode code charts, not languages. Standard Unicode ma listę wykresów kodu , których można użyć do znalezienia wykresu zawierającego znaki.The Unicode standard has a list of code charts you can use to find the chart containing your characters. Każdy koder, kod HTML, JavaScript i adres URL, muszą być skonfigurowane osobno.Each encoder, Html, JavaScript and Url, must be configured separately.

Uwaga

Dostosowanie listy bezpiecznych ma wpływ tylko na kodery, które są źródłem przez DI.Customization of the safe list only affects encoders sourced via DI. Jeśli użytkownik uzyskuje bezpośredni dostęp do kodera przy użyciu System.Text.Encodings.Web.*Encoder.Default domyślnego, zostanie użyty tylko podstawowy safelist.If you directly access an encoder via System.Text.Encodings.Web.*Encoder.Default then the default, Basic Latin only safelist will be used.

Gdzie ma nastąpić kodowanie?Where should encoding take place?

Ogólna przyjęta Metoda polega na tym, że kodowanie ma miejsce w punkcie wyjścia, a zakodowane wartości nigdy nie powinny być przechowywane w bazie danych.The general accepted practice is that encoding takes place at the point of output and encoded values should never be stored in a database. Kodowanie w punkcie wyjścia umożliwia zmianę użycia danych, na przykład z HTML do wartości ciągu zapytania.Encoding at the point of output allows you to change the use of data, for example, from HTML to a query string value. Umożliwia również łatwe wyszukiwanie danych bez konieczności kodowania wartości przed wyszukiwaniem i pozwala korzystać ze wszystkich zmian lub poprawek błędów w koderach.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.

Weryfikacja jako technika zapobiegania XSSValidation as an XSS prevention technique

Walidacja może być przydatnym narzędziem ograniczającym ataki XSS.Validation can be a useful tool in limiting XSS attacks. Na przykład ciąg liczbowy zawierający tylko znaki 0-9 nie wywoła ataku typu XSS.For example, a numeric string containing only the characters 0-9 won't trigger an XSS attack. Walidacja jest bardziej skomplikowana przy akceptowaniu kodu HTML w danych wejściowych użytkownika.Validation becomes more complicated when accepting HTML in user input. Analiza danych wejściowych HTML jest trudna, jeśli nie jest to możliwe.Parsing HTML input is difficult, if not impossible. Zaawansowana, powiązana z analizatorem, który oddziela osadzony kod HTML, jest bezpieczniejsza opcja przyjmowania danych wejściowych.Markdown, coupled with a parser that strips embedded HTML, is a safer option for accepting rich input. Nigdy nie należy polegać wyłącznie na walidacji.Never rely on validation alone. Zawsze Koduj niezaufane dane wejściowe przed wyjściem, niezależnie od tego, jakie sprawdzanie poprawności lub oczyszczanie zostało wykonane.Always encode untrusted input before output, no matter what validation or sanitization has been performed.