Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Автор: Рик Андерсон (Rick Anderson)
Межсайтовый скрипт (XSS) — это уязвимость безопасности, которая позволяет кибератаке размещать клиентские скрипты (обычно JavaScript) на веб-страницах. Когда другие пользователи загружают затронутые страницы, скрипты кибератаки выполняются. Затем кибератака может украсть файлы cookie и маркеры сеанса, изменить содержимое веб-страницы с помощью манипуляции DOM или перенаправить браузер на другую страницу. Уязвимости XSS обычно возникают, когда приложение принимает входные данные пользователя и выводит их на веб-страницу без проверки, кодирования или экранирования этих данных.
Эта статья в первую очередь касается ASP.NET Core MVC с представлениями, Razor страницами и других приложений, возвращающих HTML и потенциально уязвимых к XSS. Веб-API, возвращающие данные в виде HTML, XML или JSON, могут активировать атаки XSS в клиентских приложениях, если они не правильно очищают входные данные пользователей. Это поведение зависит от того, сколько доверия клиентское приложение помещает в API. Если API принимает созданное пользователем содержимое и возвращает его в HTML-ответе, данные открыты для атаки. Киберзлоумышленник может внедрить в содержимое вредоносные скрипты, которые выполняются, когда ответ отображается в браузере пользователя.
Чтобы предотвратить атаки XSS, веб-API должны реализовать кодирование входных и выходных данных. Проверка входных данных гарантирует, что входные данные пользователя соответствуют ожидаемым критериям и не включают вредоносный код. Кодирование выходных данных гарантирует правильность очистки любых данных, возвращаемых API, чтобы его нельзя было выполнять в виде кода браузером пользователя. Дополнительные сведения см. в статье GitHub dotnet/aspnetcore.docs проблема #28789.
Защита приложения от XSS
На базовом уровне XSS работает, заставляя ваше приложение вставить тег <script> в сформированную страницу либо добавляя событие On* в элемент.
Чтобы избежать внедрения XSS в приложение, разработчики должны реализовать следующие методы предотвращения:
Никогда не помещайте ненадежные данные в входные данные HTML, если вы не следуйте другим методам, перечисленным в этом разделе.
Ненадежные данные — это любые данные, управляемые кибератакой. Примеры включают входные данные HTML-формы, строки запроса, заголовки HTTP или даже данные, полученные из базы данных. Киберзлоумышленник может скомпрометировать вашу базу данных, даже если не может взломать ваше приложение.
Прежде чем помещать ненадежные данные в HTML-элемент, убедитесь, что данные кодируются в формате HTML.
Кодирование HTML принимает такие символы, как левая угловая скобка или меньше (
<) и изменяет их в безопасную форму(<).Прежде чем помещать ненадежные данные в атрибут HTML, убедитесь, что данные кодируются в формате HTML.
Эта специализированная форма кодирования HTML обрабатывает двойные кавычки (), одинарные кавычки (
"), амперсанды ('&) и меньше (<) символов. При работе с ненадежными входными данными используйте кодировку HTML для общего содержимого HTML и кодировки атрибутов HTML для атрибутов HTML.Прежде чем поместить ненадежные данные в JavaScript, поместите данные в HTML-элемент, содержимое которого извлекается во время выполнения.
Если вы не можете следовать этому методу, убедитесь, что данные закодированы в JavaScript. Кодировка JavaScript преобразует опасные символы для JavaScript в шестнадцатеричное эквивалентное значение. Например, JavaScript-кодирование преобразует символ «меньше» (
<) в шестнадцатеричное значение\u003C.Прежде чем включать ненадёжные данные в строку запроса URL, убедитесь, что они закодированы с помощью URL-кодирования.
Изучение кодировки HTML с помощью Razor
Модуль Razor, используемый в MVC, автоматически кодирует весь вывод, формируемый на основе переменных, если только вы специально не предпримете мер, чтобы предотвратить такое поведение. Он использует правила кодирования HTML-атрибутов каждый раз, когда вы используете директиву с символом @ @. Так как кодировка атрибутов HTML является супермножеством кодировки HTML, вам не нужно учитывать, следует ли использовать кодировку HTML или кодировку HTML-атрибутов. Необходимо убедиться, что вы используете @ символ только в контексте HTML, а не при попытке вставки ненадежных входных данных непосредственно в JavaScript.
Razor Вспомогательные функции тегов также кодируют входные данные, используемые в параметрах тегов.
Рассмотрим следующее Razor представление:
@{
var untrustedInput = "<\"123\">";
}
@untrustedInput
Это представление выводит содержимое переменной untrustedInput . Переменная содержит некоторые символы, используемые в атаках XSS: меньше (<), двойная кавычка ("), а также прямоугольная скобка или больше (>). При просмотре исходного кода видно, что вывод закодирован следующим образом:
<"123">
Предупреждение
ASP.NET Core MVC предоставляет класс HtmlString, который не кодируется автоматически при выходных данных. Этот класс никогда не следует использовать в сочетании с ненадежными входными данными, так как он предоставляет уязвимость XSS.
Изучение кодирования JavaScript с помощью Razor
В некоторых случаях может потребоваться вставить значение в JavaScript для обработки в представлении. Это можно сделать двумя способами. Самый безопасный способ вставки значений — поместить значение в атрибут данных тега и получить его в JavaScript. Например:
@{
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 instance uses 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>
Предыдущая разметка создает следующий HTML-код:
<div id="injectedData"
data-untrustedinput="<script>alert(1)</script>" />
<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 instance uses 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>
Приведенный выше код создает следующие выходные данные:
<script>alert(1)</script>
<script>alert(1)</script>
<script>alert(1)</script>
Предупреждение
Не объединяйте непроверенные входные данные в коде JavaScript для создания элементов DOM и не используйте document.write() для динамически создаваемого содержимого.
Вместо этого используйте один из следующих подходов, чтобы запретить доступ кода к XSS на основе DOM:
- Вызовите
createElement()и задайте значения свойств с помощью соответствующих методов или свойств, напримерnode.textContent=илиnode.InnerText=. -
document.CreateTextNode()Вызовите метод и добавьте его в соответствующее расположение DOM. - Вызовите метод
element.SetAttribute(). - Используйте назначение
element[attribute]=.
Кодировщики доступа в коде
В своём коде можно использовать кодировщики HTML, JavaScript и URL двумя способами:
- Внедрите их с помощью внедрения зависимостей.
- Используйте кодировщики по умолчанию, содержащиеся в
System.Text.Encodings.Webпространстве имен.
При использовании кодировщиков по умолчанию все настройки, применяемые к диапазонам символов (поэтому они рассматриваются как безопасные) не вступают в силу. Кодировщики по умолчанию используют наиболее безопасные правила кодирования.
Чтобы использовать настраиваемые кодировщики через внедрение зависимостей, ваши конструкторы должны принимать параметры HtmlEncoder, JavaScriptEncoder и UrlEncoder, в зависимости от ситуации.
Например:
public class HomeController : Controller
{
HtmlEncoder _htmlEncoder;
JavaScriptEncoder _javaScriptEncoder;
UrlEncoder _urlEncoder;
public HomeController(HtmlEncoder htmlEncoder,
JavaScriptEncoder javascriptEncoder,
UrlEncoder urlEncoder)
{
_htmlEncoder = htmlEncoder;
_javaScriptEncoder = javascriptEncoder;
_urlEncoder = urlEncoder;
}
}
Кодирование параметров URL-адреса
Если вы хотите создать строку запроса URL-адреса с ненадежными входными данными в качестве значения, используйте UrlEncoder параметр для кодирования значения:
var example = "\"Quoted Value with spaces and &\"";
var encodedValue = _urlEncoder.Encode(example);
После кодирования encodedValue переменная содержит строку %22Quoted%20Value%20with%20spaces%20and%20%26%22. Пробелы, кавычки, знаки препинания и другие небезопасные символы кодируются в шестнадцатеричное значение. Например, символ пробела преобразуется в %20.
Предупреждение
Не используйте ненадежные входные данные в рамках пути URL-адреса. Всегда передавать ненадежные входные данные в виде значения строки запроса.
Настройка кодировщиков
По умолчанию кодировщики используют безопасный список символов, ограниченный диапазоном Unicode Basic Latin. Все символы за пределами указанного диапазона кодируются в качестве эквивалентов кода символов. Это поведение также влияет на отрисовку, выполняемую вспомогательными функциями тегов Razor и вспомогательными функциями HTML, поскольку они используют кодировщики для вывода ваших строк.
Целью этого поведения является защита от неизвестных или будущих ошибок браузера. Предыдущие ошибки браузера мешали разбору, связанному с обработкой неанглийских символов. Если веб-сайт использует не латинские символы, такие как китайский, кириллица или другие, это поведение, вероятно, не подходит для вашей конфигурации.
Вы можете настроить безопасные списки кодировщика, чтобы включить диапазоны Юникода, соответствующие приложению во время запуска. Внесите настройки в файл Program.cs .
Например, можно использовать конфигурацию по умолчанию с HTML-хелпером Razor, подобным показанному в следующем примере HTML:
<p>This link text is in Chinese: @Html.ActionLink("汉语/漢語", "Index")</p>
Предыдущая разметка отображается с закодированным китайским текстом:
<p>This link text is in Chinese: <a href="/">汉语/漢語</a></p>
Чтобы расширить диапазон символов, которые считаются безопасными кодировщиком, вставьте следующую строку в файл Program.cs :
builder.Services.AddSingleton<HtmlEncoder>(
HtmlEncoder.Create(allowedRanges: new[] { UnicodeRanges.BasicLatin,
UnicodeRanges.CjkUnifiedIdeographs }));
Вы можете настроить безопасные списки кодировщика, чтобы включить диапазоны Юникода, соответствующие приложению во время запуска, в ConfigureServices().
Например, используя конфигурацию по умолчанию, можно использовать Razor HtmlHelper, как показано ниже.
<p>This link text is in Chinese: @Html.ActionLink("汉语/漢語", "Index")</p>
При просмотре источника веб-страницы вы увидите, что он отображается следующим образом, с закодированным китайским текстом;
<p>This link text is in Chinese: <a href="/">汉语/漢語</a></p>
Чтобы расширить набор символов, которые кодировщик считает безопасными, следует вставить следующую строку в метод ConfigureServices() в startup.cs;
services.AddSingleton<HtmlEncoder>(
HtmlEncoder.Create(allowedRanges: new[] { UnicodeRanges.BasicLatin,
UnicodeRanges.CjkUnifiedIdeographs }));
В этом примере разрешённый список расширяется, чтобы включить в него диапазон Юникода «Унифицированные идеографы CJK». Следующий результат показывает визуализированное представление для более широкого диапазона безопасных символов:
<p>This link text is in Chinese: <a href="/">汉语/漢語</a></p>
Диапазоны безопасных списков указываются как кодовые диаграммы Юникода, а не языки. Стандарт Юникода содержит список кодовых диаграмм, которые можно использовать для поиска диаграммы, содержащей символы. Каждый кодировщик (HTML, JavaScript, URL-адрес) должен быть настроен отдельно.
Примечание.
Настройка списка разрешённых элементов влияет только на кодировщики, получаемые через внедрение зависимостей.
Если вы напрямую обращаетесь к кодировщику через System.Text.Encodings.Web.*Encoder.Default, используется только безопасный список по умолчанию — базовая латиница.
Определение времени и места для кодирования
Как правило, принятой практикой является то, что кодирование происходит в точке вывода и кодированных значений, никогда не должно храниться в базе данных.
Кодировка в точке вывода позволяет изменить использование данных. Например, измените html-код на значение строки запроса. Этот подход позволяет легко искать данные без необходимости кодировать значения перед поиском. Кроме того, вы можете воспользоваться любыми изменениями или исправлениями ошибок, внесенных в кодировщики.
Использование проверки в качестве метода предотвращения XSS
Проверка может быть полезным средством ограничения атак XSS. Например, числовая строка, содержащая только символы 0-9, не активирует атаку XSS.
Проверка сложнее, если HTML принимается в пользовательском вводе. Анализ входных данных HTML может быть сложным, а иногда и невозможным. Markdown в сочетании с парсером, который удаляет встроенный HTML, является более безопасным вариантом для приема форматированного ввода.
Никогда не полагаться только на проверку. Всегда кодировать ненадежные входные данные перед выходными данными независимо от того, что выполняется проверка или очистка.
Связанный контент
ASP.NET Core