Статьи

Предотвращение XSS в ASP.NET

Многие проблемы с безопасностью сайта возникают из-за того, что он слишком доверяет пользователю. Большинство пользователей вашего веб-приложения будут делать только то, что им нужно, любопытный или злонамеренный пользователь часто захочет раздвинуть границы доступа. На этих краях дыры в безопасности часто появляются в вашем приложении. Ранее я писал о предотвращении двух распространенных типов уязвимостей, инъекции SQL и подделки межсайтовых запросов , в приложениях ASP.NET. В этой статье рассматривается предотвращение межсайтовых сценариев, третьего распространенного типа уязвимостей на веб-сайтах.

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

Межсайтовый скриптинг (часто сокращенно XSS) позволяет внедрять вредоносные скрипты в доверенный веб-сайт. Эта инъекция происходит без ведома пользователя. Внедренный скрипт выполняется так, как если бы он пришел с исходного сайта. Таким образом, вредоносный сценарий может получить доступ к любым ресурсам размещенного веб-сайта, к которым у пользователя будет доступ, например к файлам cookie или токенам сеанса.

Открытие атаки межсайтового скриптинга происходит, когда веб-приложение отображает входные данные от пользователей или внешних ресурсов без надлежащей проверки или кодирования. В большинстве атак с использованием межсайтовых сценариев злоумышленник пытается внедрить JavaScript в веб-страницу доверенного сервера. Злоумышленник также может попытаться внедрить HTML, Flash или что-либо еще, что выполнит браузер. Независимо от сценария, цель остается заставить браузер выполнять код по выбору злоумышленника.

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

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

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

Третья межсайтовая скриптовая атака происходит полностью в браузере. Атака функционирует путем манипулирования внутренней моделью веб-страницы в браузере, известной как DOM, и называется атакой на основе DOM. Это снова позволяет злоумышленнику выполнять вредоносный код, но код, возвращаемый сервером, обрабатывается веб-страницей в исполняемый JavaScript.

В конечном счете, межсайтовая скриптовая атака — это межсайтовая скриптовая атака, независимо от того, как она выполняется. Поскольку внедренный код поступает с другого доверенного сервера, он часто может выполняться с разрешения сайта. Поэтому он может действовать так, как если бы он был нативным кодом на веб-сайте.

Успешная атака с использованием межсайтовых сценариев может разрешить доступ к файлам cookie на веб-странице. Эти файлы cookie могут содержать конфиденциальную информацию, включая идентификаторы сеанса, которые позволят злоумышленнику выдать себя за атакованного пользователя. Атака также может изменить содержимое HTML на странице, чтобы отобразить поддельную форму входа и украсть учетные данные пользователя. Злоумышленник может проверить и отправить любое содержимое страницы, позволяющее собирать конфиденциальную информацию, например номера счетов. Более совершенная атака может, по сути, установить регистратор ключей, отправляющий любую информацию, введенную на веб-странице, злоумышленнику.

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

Веб-приложение должно проверять любой ввод в приложение, прежде чем оно будет использовано. Так же, как и с другими атаками внедрения, такими как SQL-инъекция Приложение предпочтительно проверяет этот вход по белому списку допустимых значений. Проверка удаляет или заменяет любые непредвиденные компоненты ввода на закодированное значение. Можно использовать метод черного списка, который удаляет только список известных нежелательных символов, но он более уязвим для новых методов атаки.

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

1
2
3
4
int memberId;
if (!int.TryParse(externalValue, out memberId)) {
   return RedirectToAction(«InputError»);
}

Если платформа не может проанализировать ранее извлеченное externalValue как целое число, код перенаправляет на страницу, на которой будет отображаться ошибка. В противном случае мы знаем, что memberId содержит целочисленное значение. Этот процесс также работает с другими основными типами. Некоторые более распространенные типы также предоставляют методы для проверки информации. Класс .NET Uri содержит метод IsWellFormedUriString который может проверять URL-адрес. Это позволило бы проверить, что запись домашней страницы пользователя содержит действительный URL-адрес перед отображением.

1
2
3
4
5
6
7
8
9
var userHomePage = userRecord[«homepage»];
if (!Uri.IsWellFormedUriString(newUrl, UriKind.Absolute))
{
  Model.homepage = «none»;
}
else
{
  Model.homepage = Html.Encode(userHomePage);
}

Другие и более сложные типы данных требуют более сложной проверки. Проверка поля номера кредитной карты может удалить любые символы в строке, которые не являются цифрами. Для проверки более сложных строк могут потребоваться регулярные выражения. Валидация класса может также потребовать более сложных проверок.

ASP.NET обеспечивает эффективную защиту от отраженных атак с помощью проверки запросов. Если ASP.NET обнаруживает разметку или код в запросе, он генерирует исключение «Обнаружено потенциально опасное значение» и останавливает обработку запроса.

Несмотря на ценность, бывают случаи, когда вам необходимо разрешить эти значения в запросе. Типичным примером является возможность ввода расширенного текста в форме. К сожалению, в этих случаях проверка запросов слишком часто отключается для всего сайта. Лучшее решение отключает эту проверку только при необходимости. В более ранних версиях ASP.NET добавление validateRequest="false" к директиве Page в Webforms отключило бы проверку страницы. В ASP.NET MVC добавление атрибута [ValidateInput(false)] к действию контроллера отключает проверку для этого действия, а добавление [AllowHtml] отключает проверку для поля.

ASP.NET 4.0 изменил проверку запросов несколькими способами. Эта и более поздние версии платформы выполняют проверку в начале HTTP-запроса. Проверка также применяется ко всем запросам ASP.NET, а не только к запросам страниц ASPX. Это также включает в себя пользовательские модули HTTP. Страницы, использующие исходное поведение, могут вернуться к старому методу, установив для атрибута requestValidationMode в файле web.config версию 2.0 .

1
<httpRuntime requestValidationMode=»2.0″ />

Еще лучше отключить это только для страниц, где это необходимо, используя синтаксис в файле web.config :

1
2
3
4
5
<location path=»novalidationpage.aspx»>
  <system.web>
    <httpRuntime requestValidationMode=»2.0″ />
  </system.web>
</location>

В ASP.NET 4.5 добавлена ​​возможность откладывать проверку до запроса данных. Установка атрибута requestValidationMode в файле web.config на версию 4.5 активирует это новое поведение.

1
<httpRuntime requestValidationMode=»4.5″ />

В ASP.NET 4.5 также добавлено свойство HttpRequest.Unvalidated . Использование этого свойства упрощает доступ к непроверенному значению формы, где это необходимо. Комбинируя отложенную проверку и свойство Unvalidated , вы можете получить доступ к неподтвержденным значениям при необходимости, но защитить другие входные данные формы.

Перед отображением внешних данных на веб-странице ваш HTML должен быть закодирован, чтобы браузер не обрабатывал его. В качестве примера возьмем страницу ASP.NET, написанную так, чтобы сообщение могло быть передано для отображения, например, обновление статуса. Приложение может использовать эту страницу, чтобы показать пользователю, что его учетная запись была создана без ошибок. URL-адрес этой страницы обычно выглядит примерно так http://appname/placeorder/Account+Created . Полученная страница показывает сообщение пользователю с полем, таким как:

1
<%= Html.Label(«Message», Model.message) %>

… и отображается как:

Если мы изменим URL-вызов на http:/appname/placeorder/<script>alert('hello!');</script> , мы теперь получим что-то другое.

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

ASP.NET позволяет легко кодировать данные, чтобы предотвратить атаки. Ранние версии MVC, использующие синтаксис Webform, часто содержали такой код, который не кодировал HTML.

1
<p id=»status»><%= status ></p>

Вы должны были вручную закодировать вывод, чтобы любой HTML был преобразован в формат отображения. Таким образом, символ < становится строкой &lt; , Функция Html.Encode обеспечивает это преобразование. Более безопасная форма кода, таким образом, становится:

1
<p id=»status»><%= Html.Encode(status) ></p>

ASP.NET MVC позже ввел синтаксис для выполнения этого за один шаг, заменив <= на <: чтобы код можно было сократить до:

1
<p id=»status»><%: status ></p>

Используя механизм представления Razor, весь вывод кодируется в формате HTML, если только вы не используете метод, чтобы не кодировать его. В Razor код, эквивалентный приведенному выше, становится:

1
<p id=»status»>@status</p>

Razor автоматически обрабатывает HTML-кодировку любого содержимого строки. В случае, когда вам нужно визуализировать необработанные данные, вы можете использовать метод HTML.Raw() . Чтобы отобразить результат без кодирования, мы можем использовать:

1
<p id=»status»>@Html.Raw(status)</p>

В этом примере приведенный выше код снова сделает наше приложение уязвимым. Итак, есть несколько обстоятельств, когда вы не должны кодировать вывод. Если вы отключите эту функцию в поле, вы должны проявить особую осторожность, чтобы обеспечить очистку данных перед их отображением. К счастью, есть библиотека, которая помогает в этом, а также делает больше для защиты вашего приложения от межсайтовых скриптов.

Если вы пишете приложение ASP.NET, вы должны использовать библиотеку AntiXSS для ASP.NET. На веб-сайте проекта «AntiXSS предоставляет множество функций кодирования для пользовательского ввода, включая HTML, атрибуты HTML, XML, CSS и JavaScript».

Библиотека содержит методы, предназначенные для очистки внешних данных на основе предполагаемого использования этих данных. Эти методы используют предпочтительный подход на основе белого списка. Это означает, что закодированные данные, предназначенные для атрибута HTML, можно очистить, чтобы они содержали только допустимые данные для атрибута HTML. Традиционные методы ASP.NET HtmlEncode используют черный список, который кодирует только определенные, потенциально опасные символы.

Microsoft начала включать основные подпрограммы из этой библиотеки в ASP.NET 4.5 в новом System.Web.Security.AntiXss имен System.Web.Security.AntiXss . Вы также можете настроить платформу для использования этих методов AntiXSS вместо встроенных процедур кодирования. Это можно сделать, установив атрибут encoderType для httpRuntime в файле web.config для приложения:

1
<httpRuntime … encoderType=»System.Web.Security.AntiXss.AntiXssEncoder,System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a» />

Если ваше приложение выполняет какое-либо существенное отображение внешних данных, то использование AntiXSS во многом защитит ваше приложение от межсайтовых сценариев. Если вы используете ASP.NET 4.5, то изменение вашего приложения для использования новых методов AntiXSS для кодировки по умолчанию обеспечивает еще большую защиту вашего веб-приложения.

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

Если вы не гарантируете, что все внешние данные, введенные в ваше приложение, правильно экранированы или не проверяете ввод перед размещением его на странице вывода, вы оставляете свое веб-приложение уязвимым для межсайтовых сценариев. В ASP.NET это можно сделать:

  1. Проверка всех внешних входных данных в вашем приложении перед отображением на веб-странице.
  2. Используйте проверку запросов везде, где ваше приложение не должно специально отключать его, например, форму, позволяющую вводить расширенный HTML. Если вы должны разрешить использование непроверенной информации, оставьте проверку повсюду в вашем приложении.
  3. Кодировать HTML перед отображением внешних данных на веб-странице
  4. Используйте методы на основе AntiXSS, включенные в ASP.NET 4.5, и используйте библиотеку AntiXSS для более старых версий ASP.NET.