Предотвращение атак XSRF и CSRF в ASP.NET MVC и на веб-страницах

Рик Андерсон

Подделка межсайтовых запросов (также известная как XSRF или CSRF) — это атака на веб-приложения, при которой вредоносный веб-сайт может повлиять на взаимодействие между клиентским браузером и веб-сайтом, доверенным этим браузером. Эти атаки становятся возможными, так как веб-браузеры будут автоматически отправлять маркеры проверки подлинности с каждым запросом на веб-сайт. Типичный пример – файл cookie для проверки подлинности, например билет проверки форм ASP.NET. Однако веб-сайты, использующие любой механизм постоянной проверки подлинности (например, проверка подлинности Windows, обычная и т. д.), могут быть мишенью этих атак.

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

Дополнительные сведения см. в разделе Open Web Application Security Project (OWASP) XSRF.

Анатомия нападения

Чтобы пройти через XSRF-атаку, рассмотрим пользователя, который хочет выполнить некоторые банковские операции в Интернете. Этот пользователь сначала посещает WoodgroveBank.com и входит в систему, после чего заголовок ответа будет содержать файл cookie проверки подлинности:

HTTP/1.1 200 OK
Date: Mon, 18 Jun 2012 21:22:33 GMT
X-AspNet-Version: 4.0.30319
Set-Cookie: .ASPXAUTH={authentication-token}; path=/; secure; HttpOnly;
{ Cache-Control, Content-Type, Location, Server and other keys/values not listed. }

Так как файл cookie проверки подлинности является файлом cookie сеанса, он автоматически очищается браузером при завершении процесса браузера. Однако до этого времени браузер будет автоматически включать файл cookie при каждом запросе на WoodgroveBank.com. Теперь пользователь хочет перевести $ 1000 на другой счет, поэтому он заполняет форму на банковском сайте, и браузер делает этот запрос к серверу:

POST /DoTransfer HTTP/1.1
Host: WoodgroveBank.com
Content-Type: application/x-www-form-urlencoded
Cookie: .ASPXAUTH={authentication-token}
toAcct=12345&amount=1,000.00

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

Ее онлайн-банкинг завершен, пользователь переходит от банковского сайта и посещает другие места в Интернете. Один из этих сайтов ( fabrikam.com ) содержит следующую разметку на странице, внедренной <в iframe>:

<form id="theForm" action="https://WoodgroveBank.com/DoTransfer" method="post">
    <input type="hidden" name="toAcct" value="67890" />
    <input type="hidden" name="amount" value="250.00" />
</form>
<script type="text/javascript">
    document.getElementById('theForm').submit();
</script>

Это приводит к тому, что браузер выполняет этот запрос:

POST /DoTransfer HTTP/1.1
Host: WoodgroveBank.com
Content-Type: application/x-www-form-urlencoded
Cookie: .ASPXAUTH={authentication-token}
toAcct=67890&amount=250.00

Злоумышленник использует тот факт, что у пользователя по-прежнему может быть действительный маркер проверки подлинности для целевого веб-сайта, и он использует небольшой фрагмент JavaScript, чтобы браузер автоматически выполнил HTTP POST на целевой сайт. Если маркер проверки подлинности по-прежнему действителен, банковский сайт инициирует перевод 250 долл. США на учетную запись, выбранную злоумышленником.

Неэффективные меры по устранению рисков

Интересно отметить, что в приведенном выше сценарии тот факт, что доступ к WoodgroveBank.com осуществляется через SSL и имеет файл cookie проверки подлинности только SSL, был недостаточным для того, чтобы сорвать атаку. Злоумышленник может указать схему URI (https) в своем <элементе формы> , и браузер будет продолжать отправлять неиспользовавшиеся файлы cookie на целевой сайт до тех пор, пока эти файлы cookie соответствуют схеме URI целевого объекта.

Можно утверждать, что пользователь не должен просто посещать ненадежные сайты, так как посещение только надежных сайтов помогает оставаться в безопасности в Интернете. В этом есть доля правды, но, к сожалению, этот совет не всегда практично. Возможно, пользователь "доверяет" местному новостному сайту ConsolidatedMessenger.com и переходит на этот сайт, но этот сайт имеет уязвимость XSS, которая позволяет злоумышленнику внедрить тот же фрагмент кода, который выполнялся на fabrikam.com.

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

Устранение рисков XSRF в среде выполнения Web Stack

Среда выполнения веб-стека ASP.NET использует вариант шаблона маркера синхронизатора для защиты от атак XSRF. Общая форма шаблона маркера синхронизатора заключается в том, что два маркера защиты от XSRF отправляются на сервер с каждым HTTP POST (в дополнение к маркеру проверки подлинности): один маркер в виде файла cookie, а другой — как значение формы. Значения маркеров, созданные средой выполнения ASP.NET, не являются детерминированными или предсказуемыми злоумышленниками. При отправке маркеров сервер разрешает выполнение запроса только в том случае, если оба маркера проходят сравнение проверка.

Маркер сеанса проверки запроса XSRF хранится в виде файла cookie HTTP и в настоящее время содержит следующие сведения в полезных данных:

  • Маркер безопасности, состоящий из случайного 128-разрядного идентификатора.
    На следующем рисунке показан маркер сеанса проверки запроса XSRF, отображаемый с помощью средств разработчика F12 в Интернете Обозреватель: (Обратите внимание, что это текущая реализация, и она может даже измениться.)

Снимок экрана: страница

Маркер поля хранится в виде <input type="hidden" /> и содержит следующие сведения в полезных данных:

  • Имя пользователя, выполнившего вход (при проверке подлинности).
  • Любые дополнительные данные, предоставляемые IAntiForgeryAdditionalDataProvider.

Полезные данные маркеров защиты от XSRF шифруются и подписываются, поэтому вы не можете просмотреть имя пользователя при использовании средств для проверки маркеров. Когда веб-приложение предназначено для ASP.NET 4.0, криптографические службы предоставляются подпрограммой MachineKey.Encode . Когда веб-приложение предназначено для ASP.NET 4.5 или более поздней версии, криптографические службы предоставляются подпрограммой MachineKey.Protect , которая обеспечивает лучшую производительность, расширяемость и безопасность. Дополнительные сведения см. в следующих записях блога:

Создание маркеров

Чтобы создать токены защиты от XSRF, вызовите метод @Html.AntiForgeryToken из представления MVC или @AntiForgery.GetHtml() со страницы Razor. Затем среда выполнения выполнит следующие действия.

  1. Если текущий HTTP-запрос уже содержит маркер сеанса защиты от XSRF (__RequestVerificationToken файла cookie anti-XSRF), маркер безопасности извлекается из него. Если HTTP-запрос не содержит маркер сеанса защиты от XSRF или если извлечение маркера безопасности завершается сбоем, будет создан новый случайный маркер защиты от XSRF.
  2. Маркер поля anti-XSRF создается с помощью маркера безопасности из шага (1) выше и удостоверения текущего пользователя, выполнившего вход. (Дополнительные сведения об определении удостоверения пользователя см. в разделе Сценарии со специальной поддержкой ниже.) Кроме того, если настроен IAntiForgeryAdditionalDataProvider , среда выполнения вызовет метод GetAdditionalData и включит возвращаемую строку в маркер поля. (Дополнительные сведения см. в разделе Конфигурация и расширяемость .)
  3. Если на шаге (1) был создан новый токен защиты от XSRF, будет создан новый маркер сеанса для его хранения и будет добавлен в коллекцию исходящих файлов cookie HTTP. Маркер поля из шага (2) будет заключен в <input type="hidden" /> элемент, и эта HTML-разметка будет возвращаемым значением Html.AntiForgeryToken() или AntiForgery.GetHtml().

Проверка маркеров

Чтобы проверить входящие маркеры защиты от XSRF, разработчик включает атрибут ValidateAntiForgeryToken в действие или контроллер MVC или вызывает @AntiForgery.Validate() со страницы Razor. Среда выполнения выполнит следующие действия.

  1. Входящий маркер сеанса и маркер поля считываются, а маркер защиты от XSRF извлекается из каждого из них. Маркеры защиты от XSRF должны быть идентичными для каждого шага (2) в процедуре создания.
  2. Если текущий пользователь прошел проверку подлинности, его имя пользователя сравнивается с именем пользователя, хранящимся в маркере поля. Имена пользователей должны совпадать.
  3. Если настроен IAntiForgeryAdditionalDataProvider , среда выполнения вызывает его метод ValidateAdditionalData . Метод должен возвращать логическое значение true.

Если проверка выполнена успешно, запрос будет продолжен. Если проверка не пройдена, платформа вызовет исключение HttpAntiForgeryException.

Условия сбоя

Начиная с the ASP.NET Web Stack Runtime версии 2, любое исключение HttpAntiForgeryException , которое создается во время проверки, будет содержать подробные сведения о том, что пошло не так. В настоящее время определенные условия сбоя:

  • Маркер сеанса или маркер формы отсутствует в запросе.
  • Маркер сеанса или маркер формы недоступен для чтения. Наиболее вероятной причиной этого является ферма с несовпадными версиями среды выполнения веб-стека ASP.NET или ферма, в <которой элемент machineKey> в Web.config различается на разных компьютерах. Вы можете использовать такое средство, как Fiddler, для принудительного применения этого исключения путем изменения с помощью маркера защиты от XSRF.
  • Токен сеанса и маркер поля были заменены местами.
  • Маркер сеанса и маркер поля содержат несовпадения маркеров безопасности.
  • Имя пользователя, внедренное в маркер поля, не соответствует имени текущего пользователя, выполнившего вход.
  • Метод IAntiForgeryAdditionalDataProvider.ValidateAdditionalData вернул значение false.

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

Сценарии со специальной поддержкой

анонимная аутентификация;

Система anti-XSRF содержит специальную поддержку для анонимных пользователей, где "анонимный" определяется как пользователь, где свойство IIdentity.IsAuthenticated возвращает значение false. Сценарии включают предоставление защиты XSRF на странице входа (до проверки подлинности пользователя) и пользовательские схемы проверки подлинности, в которых приложение использует механизм, отличный от IIdentity , для идентификации пользователей.

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

Проверка подлинности на основе утверждений WIF, ACS и утверждений

Как правило, классы IIdentity, встроенные в платформа .NET Framework, имеют свойство, которое IIdentity.Name достаточно для уникальной идентификации конкретного пользователя в определенном приложении. Например, FormsIdentity.Name возвращает имя пользователя, хранящееся в базе данных членства (которое является уникальным для всех приложений в зависимости от этой базы данных), WindowsIdentity.Name возвращает доменное удостоверение пользователя и т. д. Эти системы обеспечивают не только проверку подлинности; они также идентифицируют пользователей для приложения.

С другой стороны, проверка подлинности на основе утверждений не обязательно требует идентификации конкретного пользователя. Вместо этого типы ClaimsPrincipal и ClaimsIdentity связаны с набором экземпляров Claim , где отдельные утверждения могут быть "старше 18 лет" или "является администратором" для всех остальных. Так как пользователь не обязательно был идентифицирован, среда выполнения не может использовать свойство ClaimsIdentity.Name в качестве уникального идентификатора для конкретного пользователя. Команда видела реальные примеры, в которых ClaimsIdentity.Name возвращает значение NULL, возвращает понятное (отображаемое) имя или иным образом возвращает строку, которая не подходит для использования в качестве уникального идентификатора пользователя.

Во многих развертываниях, использующих проверку подлинности на основе утверждений, используется, в частности, служба контроль доступа Azure (ACS). ACS позволяет разработчику настраивать отдельных поставщиков удостоверений (например, ADFS, поставщика учетных записей Майкрософт, поставщиков OpenID, таких как Yahoo!, и т. д.), а поставщики удостоверений возвращают идентификаторы имен. Эти идентификаторы имен могут содержать персональные данные (PII), например адрес электронной почты, или быть анонимными, как частный личный идентификатор (PPID). Несмотря на это, кортеж (поставщик удостоверений, идентификатор имени) достаточно служит соответствующим маркером отслеживания для конкретного пользователя во время просмотра сайта, поэтому ASP.NET Web Stack Runtime может использовать кортеж вместо имени пользователя при создании и проверке маркеров полей защиты от XSRF. Конкретные URI для поставщика удостоверений и идентификатор имени:

  • https://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider
  • http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier

(Дополнительные сведения см. на этой странице документации по ACS .)

При создании или проверке маркера среда выполнения веб-стека ASP.NET будет пытаться выполнить привязку к типам:

  • Microsoft.IdentityModel.Claims.IClaimsIdentity, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 (Для пакета SDK ДЛЯ WIF.)
  • System.Security.Claims.ClaimsIdentity (Для .NET 4.5).

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

Проверка подлинности OAuth или OpenID

Наконец, средство защиты от XSRF имеет специальную поддержку для приложений, использующих проверку подлинности OAuth или OpenID. Эта поддержка основана на эвристических принципах: если текущая IIdentity.Name начинается с http:// или https://, сравнение имен пользователей будет выполняться с помощью ординального компаратора, а не компаратора OrdinalIgnoreCase по умолчанию.

Конфигурация и расширяемость

Иногда разработчикам может потребоваться более строгий контроль над поведением создания и проверки защиты от XSRF. Например, возможно, поведение вспомогательных элементов MVC и Веб-страниц по умолчанию при автоматическом добавлении файлов cookie HTTP в ответ нежелательно, и разработчик может захотеть сохранить маркеры в другом месте. Существуют два API, которые помогают в этом.

AntiForgery.GetTokens(string oldCookieToken, out string newCookieToken, out string formToken);
AntiForgery.Validate(string cookieToken, string formToken);

Метод GetTokens принимает в качестве входных данных существующий маркер сеанса проверки запроса XSRF (который может иметь значение NULL) и создает в качестве выходных данных новый токен сеанса проверки запроса XSRF и маркер поля. Маркеры — это просто непрозрачные строки без оформления; Значение formToken для экземпляра не будет заключено во входной <> тег. Значение newCookieToken может иметь значение NULL; Если это происходит, то значение oldCookieToken по-прежнему является допустимым, и новый файл cookie ответа задавать не нужно. Вызывающий объект GetTokens отвечает за сохранение всех необходимых файлов cookie ответа или создание необходимой разметки; Сам метод GetTokens не изменит ответ как побочный эффект. Метод Validate принимает входящие маркеры сеанса и поля и запускает вышеупомянутую логику проверки.

AntiForgeryConfig

Разработчик может настроить систему защиты от XSRF из Application_Start. Конфигурация является программной. Свойства статического типа AntiForgeryConfig описаны ниже. Большинству пользователей, использующих утверждения, потребуется задать свойство UniqueClaimTypeIdentifier.

Свойство Описание
AdditionalDataProvider IAntiForgeryAdditionalDataProvider, который предоставляет дополнительные данные во время создания маркера и использует дополнительные данные во время проверки маркера. Значение по умолчанию — NULL. Дополнительные сведения см. в разделе IAntiForgeryAdditionalDataProvider .
Имя файла cookie Строка, которая предоставляет имя файла cookie HTTP, используемого для хранения маркера сеанса защиты от XSRF. Если это значение не задано, имя будет автоматически создано на основе развернутого виртуального пути приложения. Значение по умолчанию — NULL.
RequireSsl Логическое значение, определяющее, требуется ли отправлять маркеры защиты от XSRF через защищенный SSL-канал. Если это значение равно true, для всех автоматически создаваемых файлов cookie будет установлен флаг "безопасный", а API-интерфейсы защиты от XSRF будут вызываться при вызове из запроса, который не отправляется по протоколу SSL. Значение по умолчанию — false.
SuppressIdentityHeuristicChecks Логическое значение, определяющее, должна ли система защиты от XSRF отключить поддержку удостоверений на основе утверждений. Если это значение равно true, система будет предполагать, что IIdentity.Name подходит для использования в качестве уникального идентификатора пользователя, и не будет пытаться использовать специальные варианты IClaimsIdentity или ClClaimsIdentity , как описано в разделе WIF/ ACS /claims-based authentication . Значение по умолчанию — false.
UniqueClaimTypeIdentifier Строка, указывающая, какой тип утверждения подходит для использования в качестве уникального идентификатора для каждого пользователя. Если это значение задано и текущее значение IIdentity основано на утверждениях, система попытается извлечь утверждение типа, заданного UniqueClaimTypeIdentifier, и соответствующее значение будет использоваться вместо имени пользователя при создании маркера поля. Если тип утверждения не найден, система завершит запрос неудачей. Значение по умолчанию равно null, что означает, что система должна использовать кортеж (поставщик удостоверений, идентификатор имени), как описано ранее вместо имени пользователя пользователя.

IAntiForgeryAdditionalDataProvider

Тип IAntiForgeryAdditionalDataProvider позволяет разработчикам расширить поведение системы защиты от XSRF путем кругового обхода дополнительных данных в каждом токене. Метод GetAdditionalData вызывается при каждом создании маркера поля, а возвращаемое значение внедряется в созданный маркер. Реализующий объект может возвращать метку времени, nonce или любое другое значение, которое ей нужно из этого метода.

Аналогичным образом метод ValidateAdditionalData вызывается при каждой проверке маркера поля, а строка "дополнительные данные", внедренная в маркер, передается методу . Подпрограмма проверки может реализовать время ожидания (путем проверки текущего времени по времени, сохраненного при создании маркера), подпрограмму проверки nonce или любую другую желаемую логику.

Решения по проектированию и вопросы безопасности

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

Разработчикам следует соблюдать осторожность, если несколько приложений размещаются в одном домене. Например, несмотря на то, что example1.cloudapp.net и example2.cloudapp.net являются разными узлами, между всеми узлами в домене *.cloudapp.net существует неявное отношение доверия. Это неявное отношение доверия позволяет потенциально ненадежным узлам влиять на файлы cookie друг друга (политики того же источника, которые управляют запросами AJAX, не обязательно применяются к файлам cookie HTTP). Среда выполнения веб-стека ASP.NET обеспечивает некоторые меры, так как имя пользователя внедряется в маркер поля, поэтому даже если вредоносный поддомен может перезаписать маркер сеанса, он не сможет создать допустимый маркер поля для пользователя. Однако при размещении в такой среде встроенные процедуры защиты от XSRF по-прежнему не могут защититься от перехвата сеанса или входа XSRF.

Процедуры защиты от XSRF в настоящее время не защищают от clickjacking. Приложения, которые хотят защитить себя от clickjacking, могут легко сделать это, отправив заголовок X-Frame-Options: SAMEORIGIN с каждым ответом. Этот заголовок поддерживается всеми последними браузерами. Дополнительные сведения см. в блоге IE, блоге SDL и OWASP. Среда выполнения веб-стека ASP.NET может в будущем выпуске сделать так, чтобы вспомогательные функции MVC и Web Pages anti-XSRF автоматически устанавливали этот заголовок, чтобы приложения автоматически защищали от этой атаки.

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

Acknowledgment (Подтверждение)

@LeviBroderick, который написал большую часть кода безопасности ASP.NET основную часть этой информации.