Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Подделка межсайтовой заявки — это атака на веб-приложения, в которых вредоносное веб-приложение может вмешиваться во взаимодействие между браузером клиента и веб-приложением, которое доверяет этому браузеру. Эти атаки возможны, так как веб-браузеры автоматически отправляют некоторые типы маркеров проверки подлинности с каждым запросом на веб-сайт. Эта форма эксплойта также называется атакой одним щелчком или сеансовым угоном, так как атака использует прошедший аутентификацию сеанс пользователя. Подделка межсайтовых запросов также называется XSRF или CSRF.
Пример атаки CSRF:
Пользователь входит в
www.good-banking-site.example.comсистему с помощью проверки подлинности форм. Сервер выполняет проверку подлинности пользователя и выдает ответ, содержащий проверку подлинности cookie. Сайт уязвим к атакам, поскольку сайт доверяет любому полученному запросу с допустимой аутентификацией cookie.Пользователь посещает вредоносный сайт.
www.bad-crook-site.example.comВредоносный сайт
www.bad-crook-site.example.comсодержит HTML-форму, аналогичную следующему примеру:<h1>Congratulations! You're a Winner!</h1> <form action="https://www.good-banking-site.example.com/api/account" method="post"> <input type="hidden" name="Transaction" value="withdraw" /> <input type="hidden" name="Amount" value="1000000" /> <input type="submit" value="Click to collect your prize!" /> </form>Обратите внимание, что отправка формы
actionпроисходит на уязвимый сайт, а не на вредоносный сайт. Это "межсайтовая" часть CSRF.Пользователь выбирает кнопку отправки. Браузер выполняет запрос и автоматически включает проверку подлинности cookie для запрошенного домена
www.good-banking-site.example.com.Запрос выполняется на сервере
www.good-banking-site.example.comс контекстом проверки подлинности пользователя и может выполнять любое действие, которое разрешено выполнить пользователю, прошедшему проверку подлинности.
Помимо сценария, когда пользователь выбирает кнопку для отправки формы, вредоносный сайт может:
- Запустите скрипт, который автоматически отправляет форму.
- Отправьте отправку формы в виде запроса AJAX.
- Скрытие формы с помощью CSS.
Эти альтернативные сценарии не требуют никаких действий или входных данных от пользователя, кроме первоначального посещения вредоносного сайта.
Использование HTTPS не предотвращает атаку CSRF. Вредоносный сайт может отправлять https://www.good-banking-site.example.com/ запрос так же легко, как он может отправлять небезопасный запрос.
Некоторые атаки предназначены для конечных точек, реагирующих на запросы GET, в этом случае тег изображения можно использовать для выполнения действия. Эта форма атаки распространена на сайтах форума, которые разрешают изображения, но блокируют JavaScript. Приложения, изменяющие состояние запросов GET, в которых переменные или ресурсы изменяются, уязвимы для вредоносных атак. Запросы GET, изменяющие состояние, небезопасны. Рекомендуется никогда не изменять состояние запроса GET.
Атаки CSRF возможны для веб-приложений, использующих файлы cookie для проверки подлинности, так как:
- Браузеры хранят файлы cookie, выданные веб-приложением.
- Сохраненные файлы cookie включают файлы cookie сеанса для пользователей, прошедших аутентификацию.
- Браузеры отправляют все файлы cookie, связанные с доменом, в веб-приложение каждый запрос независимо от того, как был создан запрос к приложению в браузере.
Однако атаки CSRF не ограничиваются использованием файлов cookie. Например, Базовая и Дайджест-аутентификация также уязвимы. После входа пользователя с помощью базовой или дайджест-проверки подлинности браузер автоматически отправляет учетные данные до окончания сеанса.
В этом контексте сеанс ссылается на сеанс на стороне клиента, в течение которого пользователь проходит проверку подлинности. Это не связано с сеансами на стороне сервера или Промежуточным программным обеспечением сеансов ASP.NET Core.
Пользователи могут защищаться от уязвимостей CSRF, принимая меры предосторожности:
- Выйдите из веб-приложений после завершения работы с ними.
- Периодически очищать файлы cookie браузера.
Однако уязвимости CSRF являются основной проблемой веб-приложения, а не конечным пользователем.
Основы проверки подлинности
Аутентификация на основе Cookie является популярной формой проверки подлинности. Системы аутентификации на основе токенов становятся всё более популярными, особенно для одностраничных приложений (SPA).
Cookie-основанная аутентификация
Когда пользователь проходит проверку подлинности с помощью имени пользователя и пароля, им выдается токен, содержащий учетный талон аутентификации. Маркер можно использовать для проверки подлинности и авторизации. Маркер хранится как cookie, который отправляется с каждым запросом клиента. Создание и проверка этого cookie выполняется с помощью промежуточного программного обеспечения Cookie аутентификации. Промежуточное ПО
Проверка подлинности на основе токенов
Когда пользователь проходит проверку подлинности, ему выдается токен (а не антифальсификационный токен). Токен содержит информацию о пользователе в виде утверждений или ссылочного токена, который указывает приложению на состояние пользователя, сохраняемое в приложении. Когда пользователь пытается получить доступ к ресурсу, требующего проверки подлинности, токен отправляется приложению с дополнительным заголовком авторизации в виде токена типа Bearer. Такой подход делает приложение бессостоя́тельным. В каждом последующем запросе маркер передается в запросе на проверку на стороне сервера. Этот маркер не шифруется; он закодирован. На сервере маркер декодируется для доступа к его информации. Чтобы отправить маркер на последующие запросы, сохраните маркер в локальном хранилище браузера. Размещение маркера в локальном хранилище браузера и его извлечение и использование в качестве маркера носителя обеспечивает защиту от атак CSRF. Однако если приложение будет уязвимо для внедрения скриптов через XSS или скомпрометированный внешний файл JavaScript, кибератакующий может получить любое значение из локального хранилища и отправить его себе. ASP.NET Core кодирует все выходные данные на стороне сервера из переменных по умолчанию, что снижает риск XSS. При изменении этого поведения с помощью Html.Raw или пользовательского кода с непроверенными входными данными можно увеличить риск XSS.
Не беспокойтесь об уязвимости CSRF, если маркер хранится в локальном хранилище браузера. CSRF является проблемой, когда токен хранится в cookie. Для получения дополнительной информации см. проблему GitHub SPA code sample adds two cookies.
Несколько приложений, размещенных в одном домене
Среды общего хостинга уязвимы для угону сессий, CSRF-атакам при входе и других атак.
Хотя example1.contoso.net и example2.contoso.net являются разными узлами, существует неявная связь доверия между узлами в домене *.contoso.net . Эта неявная связь доверия позволяет потенциально ненадежным узлам влиять на файлы cookie друг друга (политики того же источника, которые управляют запросами AJAX, не обязательно применяются к файлам cookie HTTP).
Атаки, которые используют доверенные файлы cookie между приложениями, размещенными в одном домене, можно предотвратить, не предоставляя общий доступ к доменам. Если каждое приложение размещено в собственном домене, не существует неявных cookie отношений доверия для эксплойтов.
Защита от подделок в ASP.NET Core
Предупреждение
ASP.NET Core реализует антифоргерию с помощью ASP.NET Core Data Protection. Стек защиты данных должен быть настроен для работы в ферме серверов. Дополнительные сведения см. в разделе "Настройка защиты данных".
Промежуточное программное обеспечение для защиты от подделок добавляется в контейнер внедрения зависимостей, если вызывается один из следующих API:
Дополнительные сведения см. в разделе Антифальсификация в минимальных API.
FormTagHelper вставляет маркеры защиты от подделки в элементы HTML-форм. Следующий тег в Razor файле автоматически создает антифальсификационные токены:
<form method="post">
<!-- ... -->
</form>
Аналогичным образом IHtmlHelper.BeginForm создаёт маркеры антифальсификации по умолчанию, если метод формы не является GET.
Автоматическое создание маркеров антиподделки для элементов формы HTML происходит, когда <form> тег содержит method="post" атрибут, и выполняется любое из следующих условий:
- Атрибут действия пуст (
action=""). - Атрибут действия не предоставляется (
<form method="post">).
Автоматическое создание маркеров антифоргерии для элементов формы HTML можно отключить:
Явно отключите антифальсификационные маркеры с помощью атрибута
asp-antiforgery.<form method="post" asp-antiforgery="false"> <!-- ... --> </form>Элемент формы исключен из вспомогательных тегов, используя символ выхода из тегов !.
<!form method="post"> <!-- ... --> </!form>Удалите
FormTagHelperиз представления.FormTagHelperможно удалить из представления, добавив следующую директиву в представление Razor.@removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
Примечание.
Razor Страницы автоматически защищены от XSRF/CSRF. Дополнительные сведения см. в разделе XSRF/CSRF и Razor Pages.
Наиболее распространенный подход к защите от атак CSRF — использовать шаблон токена синхронизатора (STP). STP используется, когда пользователь запрашивает страницу с данными формы:
- Сервер отправляет маркер, связанный с удостоверением текущего пользователя клиенту.
- Клиент отправляет маркер на сервер для проверки.
- Если сервер получает маркер, который не соответствует удостоверению пользователя, прошедшего проверку подлинности, запрос отклоняется.
Токен является уникальным и непредсказуемым. Маркер также можно использовать для обеспечения правильной последовательности запросов (например, обеспечения последовательности запросов: страницы 1 > страницы 2 > страницы 3). Все формы в ASP.NET шаблонах Core MVC и Razor Pages создают маркеры защиты от подделки. Следующая пара примеров представления создает маркеры антифоргерии:
<form asp-action="Index" asp-controller="Home" method="post">
<!-- ... -->
</form>
@using (Html.BeginForm("Index", "Home"))
{
<!-- ... -->
}
Явно добавьте токен антиподделки в элемент <form> без использования вспомогателей тегов с HTML-вспомогателем @Html.AntiForgeryToken.
<form asp-action="Index" asp-controller="Home" method="post">
@Html.AntiForgeryToken()
<!-- ... -->
</form>
В каждом из предыдущих случаев ASP.NET Core добавляет скрытое поле формы, аналогичное следующему примеру:
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">
ASP.NET Core включает три фильтра для работы с маркерами защиты от подделки:
Защита от подделок с AddControllers
Вызов AddControllersне включает маркеры защиты от подделки. AddControllersWithViews должен быть вызван для включения встроенной поддержки маркеров защиты от подделки.
Несколько вкладок браузера и шаблон токена синхронизатора
Несколько вкладок, вошедших в систему как разные пользователи, или одна, вошедшая в систему как анонимный пользователь, не поддерживаются.
Настройка защиты от подделки с помощью AntiforgeryOptions
Настройте AntiforgeryOptions в файле приложения Program :
builder.Services.AddAntiforgery(options =>
{
// Set Cookie properties using CookieBuilder properties†.
options.FormFieldName = "AntiforgeryFieldname";
options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
options.SuppressXFrameOptionsHeader = false;
});
Установите свойства антиподделки cookie, используя свойства класса CookieBuilder, как показано в следующей таблице.
| Вариант | Описание |
|---|---|
| Cookie | Определяет параметры, используемые для создания файлов cookie антивзломной защиты. |
| FormFieldName | Имя скрытого поля формы, используемого системой защиты от подделки для отображения токенов в представлениях. |
| HeaderName | Имя заголовка, используемого антифоргерской системой. Если nullсистема рассматривает только данные формы. |
| SuppressXFrameOptionsHeader | Указывает, следует ли подавлять создание заголовка X-Frame-Options . По умолчанию заголовок создается со значением "SAMEORIGIN". По умолчанию — false. |
Некоторые браузеры не разрешают небезопасным конечным точкам устанавливать файлы cookie с флагом "безопасный" или перезаписывать файлы cookie, флаг безопасности которых установлен (дополнительные сведения см. в разделе "Нерекомендуемые изменения" файлов cookie из небезопасных источников). Так как сочетание безопасных и небезопасных конечных точек является общим сценарием в приложениях, ASP.NET Core смягчает ограничение на безопасную политику для некоторых файлов cookie, таких как antiforgery cookie, установив свойство SecurePolicy элемента cookie на CookieSecurePolicy.None. Даже если злоумышленник украдет маркер антифоргерии cookie, он также должен украсть сам маркер, который обычно отправляется через поле формы (более распространенное) или отдельный заголовок запроса (менее распространенный), а также маркер проверки подлинности cookie. Файлы cookie, связанные с проверкой подлинности или авторизацией, используют более надежную политику, чем CookieSecurePolicy.None.
Кроме того, в рабочих средах, не связанных с разработкой, вы можете защитить антимошеннические механизмы cookie, используя SSL по протоколу HTTPS, с использованием следующего значения свойства в файле приложения Program.
if (!builder.Environment.IsDevelopment())
{
builder.Services.AddAntiforgery(o =>
{
o.Cookie.SecurePolicy = CookieSecurePolicy.Always;
});
}
Дополнительные сведения см. в разделе CookieAuthenticationOptions.
Генерация маркеров защиты от подделки с помощью IAntiforgery
IAntiforgery предоставляет API для настройки функций антифоргерии.
IAntiforgery можно запросить Program.cs с помощью WebApplication.Services. В следующем примере используется промежуточное ПО (middleware) на главной странице приложения для создания маркера защиты от подделки и отправки его в ответ в виде cookie:
app.UseRouting();
app.UseAuthorization();
var antiforgery = app.Services.GetRequiredService<IAntiforgery>();
app.Use((context, next) =>
{
var requestPath = context.Request.Path.Value;
if (string.Equals(requestPath, "/", StringComparison.OrdinalIgnoreCase)
|| string.Equals(requestPath, "/index.html", StringComparison.OrdinalIgnoreCase))
{
var tokenSet = antiforgery.GetAndStoreTokens(context);
context.Response.Cookies.Append("XSRF-TOKEN", tokenSet.RequestToken!,
new CookieOptions { HttpOnly = false });
}
return next(context);
});
В предыдущем примере задается cookie, называемый XSRF-TOKEN. Клиент может прочитать это cookie и указать его значение в качестве заголовка, присоединенного к запросам AJAX. Например, Angular включает встроенную защиту XSRF, которая по умолчанию считывает cookie с именем cookieXSRF-TOKEN.
Требовать антифальсификационной проверки
Фильтр действий ValidateAntiForgeryToken можно применить к отдельному действию, контроллеру или глобально. Запросы, сделанные к действиям, к которым применяется этот фильтр, блокируются, если запрос не включает допустимый маркер антифоргерии.
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Index()
{
// ...
return RedirectToAction();
}
Атрибут ValidateAntiForgeryToken требует маркер для всех запросов к методам действия, которые он отмечает, включая запросы HTTP GET. Если атрибут ValidateAntiForgeryToken применяется ко всем контроллерам приложения, его можно переопределить с помощью атрибута IgnoreAntiforgeryToken.
Автоматическая проверка маркеров защиты от подделки только для небезопасных методов HTTP
Вместо широкого применения атрибута ValidateAntiForgeryToken и переопределения его атрибутами IgnoreAntiforgeryTokenможно использовать атрибут AutoValidateAntiforgeryToken . Этот атрибут работает идентично атрибуту ValidateAntiForgeryToken , за исключением того, что он не требует маркеров для запросов, выполненных с помощью следующих методов HTTP:
- ПОЛУЧИТЬ
- Заголовок
- ПАРАМЕТРЫ
- ТРАССИРОВКА
Рекомендуется использовать AutoValidateAntiforgeryToken широко для сценариев, отличных от API. Этот атрибут гарантирует, что действия POST защищены по умолчанию. Альтернативой является игнорирование маркеров антифоргерии по умолчанию, если ValidateAntiForgeryToken не применяется к отдельным методам действия. Скорее всего, в этом сценарии метод действия POST остается незащищенным по ошибке, оставляя приложение уязвимым к атакам CSRF. Все запросы POST должны отправлять антифорджери-токен.
API не имеют автоматического механизма для отправки той части токена, которая не является cookie. Реализация, вероятно, зависит от реализации клиентского кода. Ниже показаны некоторые примеры:
Пример уровня класса:
[AutoValidateAntiforgeryToken]
public class HomeController : Controller
Глобальный пример:
builder.Services.AddControllersWithViews(options =>
{
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
});
Переопределение глобальных атрибутов или атрибутов защиты от подделки в контроллере
Фильтр IgnoreAntiforgeryToken используется для устранения необходимости в токене защиты от подделки для данного действия (или контроллера). При применении этот фильтр переопределяет фильтры ValidateAntiForgeryToken и AutoValidateAntiforgeryToken, указанные на более высоком уровне (глобально или на контроллере).
[IgnoreAntiforgeryToken]
public IActionResult IndexOverride()
{
// ...
return RedirectToAction();
}
Обновление токенов после аутентификации
Маркеры должны обновляться после проверки подлинности пользователя, перенаправляя пользователя на страницу представления или Razor страницы.
JavaScript, AJAX и SPA
В традиционных приложениях на основе HTML маркеры защиты от подмен передаются серверу с помощью скрытых полей формы. В современных приложениях и spAs на основе JavaScript многие запросы выполняются программными средствами. Эти запросы AJAX могут использовать другие методы, такие как заголовки запросов или cookies, для передачи токена.
Если файлы cookie используются для хранения маркеров проверки подлинности и проверки подлинности запросов API на сервере, CSRF является потенциальной проблемой. Если локальное хранилище используется для хранения маркера, уязвимость CSRF может быть устранена, так как значения из локального хранилища не отправляются автоматически на сервер с каждым запросом. Использование локального хранилища для хранения маркера защиты от подделки на клиенте и отправка маркера в качестве заголовка запроса рекомендуется.
Blazor
Для получения дополнительной информации см. раздел ASP.NET Core Blazor аутентификация и авторизация.
JavaScript
Используя JavaScript в представлениях, маркер можно создать через службу непосредственно в представлении. Внедрите службу IAntiforgery в представление и вызовите GetAndStoreTokens.
@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Antiforgery
@{
ViewData["Title"] = "JavaScript";
var requestToken = Antiforgery.GetAndStoreTokens(Context).RequestToken;
}
<input id="RequestVerificationToken" type="hidden" value="@requestToken" />
<button id="button" class="btn btn-primary">Submit with Token</button>
<div id="result" class="mt-2"></div>
@section Scripts {
<script>
document.addEventListener("DOMContentLoaded", () => {
const resultElement = document.getElementById("result");
document.getElementById("button").addEventListener("click", async () => {
const response = await fetch("@Url.Action("FetchEndpoint")", {
method: "POST",
headers: {
RequestVerificationToken:
document.getElementById("RequestVerificationToken").value
}
});
if (response.ok) {
resultElement.innerText = await response.text();
} else {
resultElement.innerText = `Request Failed: ${response.status}`
}
});
});
</script>
}
В предыдущем примере используется JavaScript для чтения значения скрытого поля для заголовка AJAX POST.
Этот подход устраняет необходимость непосредственной настройки файлов cookie с сервера или их чтения от клиента. Однако, если внедрение службы IAntiforgery невозможно, используйте JavaScript для доступа к маркерам в файлах cookie.
- Маркеры доступа в дополнительном запросе к серверу обычно
same-origin. - Используйте содержимое cookie, чтобы создать заголовок со значением токена.
Если скрипт отправляет маркер в заголовке запроса X-XSRF-TOKEN, настройте службу защиты от подделки для поиска заголовка X-XSRF-TOKEN :
builder.Services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
В следующем примере добавляется защищенный конечный пункт, который записывает токен запроса в элемент cookie, доступный для считывания JavaScript.
app.UseAuthorization();
app.MapGet("antiforgery/token", (IAntiforgery forgeryService, HttpContext context) =>
{
var tokens = forgeryService.GetAndStoreTokens(context);
context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken!,
new CookieOptions { HttpOnly = false });
return Results.Ok();
}).RequireAuthorization();
В следующем примере JavaScript используется для выполнения запроса AJAX для получения маркера и выполнения другого запроса с соответствующим заголовком:
var response = await fetch("/antiforgery/token", {
method: "GET",
headers: { "Authorization": authorizationToken }
});
if (response.ok) {
// https://developer.mozilla.org/docs/web/api/document/cookie
const xsrfToken = document.cookie
.split("; ")
.find(row => row.startsWith("XSRF-TOKEN="))
.split("=")[1];
response = await fetch("/JavaScript/FetchEndpoint", {
method: "POST",
headers: { "X-XSRF-TOKEN": xsrfToken, "Authorization": authorizationToken }
});
if (response.ok) {
resultElement.innerText = await response.text();
} else {
resultElement.innerText = `Request Failed: ${response.status}`
}
} else {
resultElement.innerText = `Request Failed: ${response.status}`
}
Примечание.
Если антифальсификационный маркер указан как в заголовке запроса, так и в полезных данных формы, проверяется только маркер в заголовке.
Антифальсификация с минимальными интерфейсами API
Вызовите AddAntiforgery и UseAntiforgery(IApplicationBuilder), чтобы зарегистрировать службы защиты от подделки в DI. Маркеры антиподделки используются для предотвращения межсайтовых подделок запросов.
var builder = WebApplication.CreateBuilder();
builder.Services.AddAntiforgery();
var app = builder.Build();
app.UseAntiforgery();
app.MapGet("/", () => "Hello World!");
app.Run();
Промежуточное программное обеспечение для защиты от подделок:
- Прерывает ли выполнение оставшейся части конвейера запроса, если не.
- Задает IAntiforgeryValidationFeature в HttpContext.Features текущего запроса.
Токен антифальсификации проверяется только в том случае, если:
- Конечная точка содержит метаданные, реализующие IAntiforgeryMetadata, где
RequiresValidation=true. - Метод HTTP, связанный с конечной точкой, является соответствующим методом HTTP. Соответствующие методы — это все методы HTTP, кроме TRACE, OPTIONS, HEAD и GET.
- Запрос связан с допустимой конечной точкой.
Примечание. При ручном включении промежуточное ПО для защиты от подделки должно выполняться после промежуточного ПО для проверки подлинности и авторизации, чтобы предотвратить чтение данных формы, если пользователь не аутентифицирован.
По умолчанию минимальные API, принимаюющие данные формы, требуют проверки маркеров защиты от подделки.
Рассмотрим следующий GenerateForm метод:
public static string GenerateForm(string action,
AntiforgeryTokenSet token, bool UseToken=true)
{
string tokenInput = "";
if (UseToken)
{
tokenInput = $@"<input name=""{token.FormFieldName}""
type=""hidden"" value=""{token.RequestToken}"" />";
}
return $@"
<html><body>
<form action=""{action}"" method=""POST"" enctype=""multipart/form-data"">
{tokenInput}
<input type=""text"" name=""name"" />
<input type=""date"" name=""dueDate"" />
<input type=""checkbox"" name=""isCompleted"" />
<input type=""submit"" />
</form>
</body></html>
";
}
Предыдущий код содержит три аргумента: действие, антифальсификационный маркер и bool, указывающий, следует ли использовать маркер.
Рассмотрим следующий пример:
using Microsoft.AspNetCore.Antiforgery;
using Microsoft.AspNetCore.Mvc;
var builder = WebApplication.CreateBuilder();
builder.Services.AddAntiforgery();
var app = builder.Build();
app.UseAntiforgery();
// Pass token
app.MapGet("/", (HttpContext context, IAntiforgery antiforgery) =>
{
var token = antiforgery.GetAndStoreTokens(context);
return Results.Content(MyHtml.GenerateForm("/todo", token), "text/html");
});
// Don't pass a token, fails
app.MapGet("/SkipToken", (HttpContext context, IAntiforgery antiforgery) =>
{
var token = antiforgery.GetAndStoreTokens(context);
return Results.Content(MyHtml.GenerateForm("/todo",token, false ), "text/html");
});
// Post to /todo2. DisableAntiforgery on that endpoint so no token needed.
app.MapGet("/DisableAntiforgery", (HttpContext context, IAntiforgery antiforgery) =>
{
var token = antiforgery.GetAndStoreTokens(context);
return Results.Content(MyHtml.GenerateForm("/todo2", token, false), "text/html");
});
app.MapPost("/todo", ([FromForm] Todo todo) => Results.Ok(todo));
app.MapPost("/todo2", ([FromForm] Todo todo) => Results.Ok(todo))
.DisableAntiforgery();
app.Run();
class Todo
{
public required string Name { get; set; }
public bool IsCompleted { get; set; }
public DateTime DueDate { get; set; }
}
public static class MyHtml
{
public static string GenerateForm(string action,
AntiforgeryTokenSet token, bool UseToken=true)
{
string tokenInput = "";
if (UseToken)
{
tokenInput = $@"<input name=""{token.FormFieldName}""
type=""hidden"" value=""{token.RequestToken}"" />";
}
return $@"
<html><body>
<form action=""{action}"" method=""POST"" enctype=""multipart/form-data"">
{tokenInput}
<input type=""text"" name=""name"" />
<input type=""date"" name=""dueDate"" />
<input type=""checkbox"" name=""isCompleted"" />
<input type=""submit"" />
</form>
</body></html>
";
}
}
В приведенном выше коде данные отправляются в:
-
/todoтребует допустимого маркера защиты от подделки. -
/todo2Не нужен действительный токен защиты от подделки, так как DisableAntiforgery вызывается.
app.MapPost("/todo", ([FromForm] Todo todo) => Results.Ok(todo));
app.MapPost("/todo2", ([FromForm] Todo todo) => Results.Ok(todo))
.DisableAntiforgery();
POST-запрос к:
-
/todoиз формы, созданной конечной/точкой, успешно проходит, так как токен защиты от подделки действителен. -
/todoиз формы, созданной/SkipToken, не удается, потому что механизм защиты от подделки не включён. -
/todo2из формы, созданной конечной/DisableAntiforgery, завершается успешно, так как антифальсификационная защита не требуется.
app.MapPost("/todo", ([FromForm] Todo todo) => Results.Ok(todo));
app.MapPost("/todo2", ([FromForm] Todo todo) => Results.Ok(todo))
.DisableAntiforgery();
При отправке формы без действительного маркера антифальсификации:
- В среде разработки создается исключение.
- В производственной среде регистрируется сообщение.
файлы cookie аутентификации Windows и защиты от подделки
При использовании проверки подлинности Windows конечные точки приложений должны быть защищены от атак CSRF так же, как и для файлов cookie. Браузер неявно отправляет контекст проверки подлинности серверу и конечным точкам, которые необходимо защитить от атак CSRF.
Расширить защиту от подделок
Тип IAntiforgeryAdditionalDataProvider позволяет разработчикам расширить поведение системы защиты от CSRF путем обхода дополнительных данных в каждом токене. Метод GetAdditionalData вызывается каждый раз при создании маркера поля, а возвращаемое значение внедрено в созданный маркер. Реализующий может возвращать метку времени, nonce или любое другое значение, а затем вызывать ValidateAdditionalData для проверки этих данных при проверке этого токена. Имя пользователя клиента уже внедрено в созданные маркеры, поэтому не нужно включать эти сведения. Если в маркере содержатся дополнительные данные, но IAntiForgeryAdditionalDataProvider не настроен, то дополнительные данные не проверяются.
Дополнительные ресурсы
Межсайтовая подделка запросов (также известная как XSRF или CSRF) — это атака на веб-приложения, посредством которых вредоносное веб-приложение может влиять на взаимодействие между клиентским браузером и веб-приложением, которое доверяет этому браузеру. Эти атаки возможны, так как веб-браузеры автоматически отправляют некоторые типы маркеров проверки подлинности с каждым запросом на веб-сайт. Эта форма эксплойта также называется атакой одним щелчком или сеансовым угоном, так как атака использует прошедший аутентификацию сеанс пользователя.
Пример атаки CSRF:
Пользователь входит в
www.good-banking-site.example.comсистему с помощью проверки подлинности форм. Сервер выполняет проверку подлинности пользователя и выдает ответ, содержащий проверку подлинности cookie. Сайт уязвим к атакам, поскольку сайт доверяет любому полученному запросу с допустимой аутентификацией cookie.Пользователь посещает вредоносный сайт.
www.bad-crook-site.example.comВредоносный сайт
www.bad-crook-site.example.comсодержит HTML-форму, аналогичную следующему примеру:<h1>Congratulations! You're a Winner!</h1> <form action="https://www.good-banking-site.example.com/api/account" method="post"> <input type="hidden" name="Transaction" value="withdraw" /> <input type="hidden" name="Amount" value="1000000" /> <input type="submit" value="Click to collect your prize!" /> </form>Обратите внимание, что отправка формы
actionпроисходит на уязвимый сайт, а не на вредоносный сайт. Это "межсайтовая" часть CSRF.Пользователь выбирает кнопку отправки. Браузер выполняет запрос и автоматически включает проверку подлинности cookie для запрошенного домена
www.good-banking-site.example.com.Запрос выполняется на сервере
www.good-banking-site.example.comс контекстом проверки подлинности пользователя и может выполнять любое действие, которое разрешено выполнить пользователю, прошедшему проверку подлинности.
Помимо сценария, когда пользователь выбирает кнопку для отправки формы, вредоносный сайт может:
- Запустите скрипт, который автоматически отправляет форму.
- Отправьте отправку формы в виде запроса AJAX.
- Скрытие формы с помощью CSS.
Эти альтернативные сценарии не требуют никаких действий или входных данных от пользователя, кроме первоначального посещения вредоносного сайта.
Использование HTTPS не предотвращает атаку CSRF. Вредоносный сайт может отправлять https://www.good-banking-site.example.com/ запрос так же легко, как он может отправлять небезопасный запрос.
Некоторые атаки предназначены для конечных точек, реагирующих на запросы GET, в этом случае тег изображения можно использовать для выполнения действия. Эта форма атаки распространена на сайтах форума, которые разрешают изображения, но блокируют JavaScript. Приложения, изменяющие состояние запросов GET, в которых переменные или ресурсы изменяются, уязвимы для вредоносных атак. Запросы GET, изменяющие состояние, небезопасны. Рекомендуется никогда не изменять состояние запроса GET.
Атаки CSRF возможны для веб-приложений, использующих файлы cookie для проверки подлинности, так как:
- Браузеры хранят файлы cookie, выданные веб-приложением.
- Сохраненные файлы cookie включают файлы cookie сеанса для пользователей, прошедших аутентификацию.
- Браузеры отправляют все файлы cookie, связанные с доменом, в веб-приложение каждый запрос независимо от того, как был создан запрос к приложению в браузере.
Однако атаки CSRF не ограничиваются использованием файлов cookie. Например, Базовая и Дайджест-аутентификация также уязвимы. После входа пользователя с помощью базовой или дайджест-проверки подлинности браузер автоматически отправляет учетные данные до окончания сеанса.
В этом контексте сеанс ссылается на сеанс на стороне клиента, в течение которого пользователь проходит проверку подлинности. Это не связано с сеансами на стороне сервера или Промежуточным программным обеспечением сеансов ASP.NET Core.
Пользователи могут защищаться от уязвимостей CSRF, принимая меры предосторожности:
- Выйдите из веб-приложений после завершения работы с ними.
- Периодически очищать файлы cookie браузера.
Однако уязвимости CSRF являются основной проблемой веб-приложения, а не конечным пользователем.
Основы проверки подлинности
Аутентификация на основе Cookie является популярной формой проверки подлинности. Системы аутентификации на основе токенов становятся всё более популярными, особенно для одностраничных приложений (SPA).
Cookie-основанная аутентификация
Когда пользователь проходит аутентификацию с помощью имени пользователя и пароля, ему выдается токен, содержащий аутентификационный билет, который используется для аутентификации и авторизации. Маркер хранится как cookie, который отправляется с каждым запросом клиента. Создание и проверка этого cookie осуществляется промежуточным ПО проверки подлинности Cookie. Промежуточное ПО
Проверка подлинности на основе токенов
Когда пользователь проходит проверку подлинности, ему выдается токен (а не антифальсификационный токен). Токен содержит информацию о пользователе в виде утверждений или ссылочного токена, который указывает приложению на состояние пользователя, сохраняемое в приложении. Когда пользователь пытается получить доступ к ресурсу, требующего проверки подлинности, токен отправляется приложению с дополнительным заголовком авторизации в виде токена типа Bearer. Такой подход делает приложение бессостоя́тельным. В каждом последующем запросе маркер передается в запросе на проверку на стороне сервера. Этот маркер не шифруется; он закодирован. На сервере маркер декодируется для доступа к его информации. Чтобы отправить маркер на последующие запросы, сохраните маркер в локальном хранилище браузера. Размещение маркера в локальном хранилище браузера и его извлечение и использование в качестве маркера носителя обеспечивает защиту от атак CSRF. Тем не менее, если приложение будет уязвимо для внедрения скриптов через XSS или скомпрометированный внешний файл javascript, кибератакующий сможет извлечь любое значение из локального хранилища и отправить его себе. ASP.NET Core кодирует все выходные данные на стороне сервера из переменных по умолчанию, что снижает риск XSS. При изменении этого поведения с помощью Html.Raw или пользовательского кода с непроверенными входными данными можно увеличить риск XSS.
Не беспокойтесь об уязвимости CSRF, если маркер хранится в локальном хранилище браузера. CSRF является проблемой, когда токен хранится в cookie. Для получения дополнительной информации см. проблему GitHub SPA code sample adds two cookies.
Несколько приложений, размещенных в одном домене
Среды общего размещения уязвимы к перехвату сеанса, CSRF-атакам при входе и другим видам атак.
Хотя example1.contoso.net и example2.contoso.net являются разными узлами, существует неявная связь доверия между узлами в домене *.contoso.net . Эта неявная связь доверия позволяет потенциально ненадежным узлам влиять на файлы cookie друг друга (политики того же источника, которые управляют запросами AJAX, не обязательно применяются к файлам cookie HTTP).
Атаки, которые используют доверенные файлы cookie между приложениями, размещенными в одном домене, можно предотвратить, не предоставляя общий доступ к доменам. Если каждое приложение размещено в собственном домене, не существует неявных cookie отношений доверия для эксплойтов.
Защита от подделок в ASP.NET Core
Предупреждение
ASP.NET Core реализует антифоргерию с помощью ASP.NET Core Data Protection. Стек защиты данных должен быть настроен для работы в ферме серверов. Дополнительные сведения см. в разделе "Настройка защиты данных".
Промежуточное программное обеспечение для защиты от подделок добавляется в контейнер внедрения зависимостей, если вызывается один из следующих API:
FormTagHelper вставляет маркеры защиты от подделки в элементы HTML-форм. Следующий тег в Razor файле автоматически создает антифальсификационные токены:
<form method="post">
<!-- ... -->
</form>
Аналогичным образом IHtmlHelper.BeginForm создаёт маркеры антифальсификации по умолчанию, если метод формы не является GET.
Автоматическое создание маркеров антиподделки для элементов формы HTML происходит, когда <form> тег содержит method="post" атрибут, и выполняется любое из следующих условий:
- Атрибут действия пуст (
action=""). - Атрибут действия не предоставляется (
<form method="post">).
Автоматическое создание маркеров антифоргерии для элементов формы HTML можно отключить:
Явно отключите антифальсификационные маркеры с помощью атрибута
asp-antiforgery.<form method="post" asp-antiforgery="false"> <!-- ... --> </form>Элемент формы исключен из вспомогательных тегов, используя символ выхода из тегов !.
<!form method="post"> <!-- ... --> </!form>Удалите
FormTagHelperиз представления.FormTagHelperможно удалить из представления, добавив следующую директиву в представление Razor.@removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
Примечание.
Razor Страницы автоматически защищены от XSRF/CSRF. Дополнительные сведения см. в разделе XSRF/CSRF и Razor Pages.
Наиболее распространенный подход к защите от атак CSRF — использовать шаблон токена синхронизатора (STP). STP используется, когда пользователь запрашивает страницу с данными формы:
- Сервер отправляет маркер, связанный с удостоверением текущего пользователя клиенту.
- Клиент отправляет маркер на сервер для проверки.
- Если сервер получает маркер, который не соответствует удостоверению пользователя, прошедшего проверку подлинности, запрос отклоняется.
Токен является уникальным и непредсказуемым. Маркер также можно использовать для обеспечения правильной последовательности запросов (например, обеспечения последовательности запросов: страницы 1 > страницы 2 > страницы 3). Все формы в ASP.NET шаблонах Core MVC и Razor Pages создают маркеры защиты от подделки. Следующая пара примеров представления создает маркеры антифоргерии:
<form asp-action="Index" asp-controller="Home" method="post">
<!-- ... -->
</form>
@using (Html.BeginForm("Index", "Home"))
{
<!-- ... -->
}
Явно добавьте токен антиподделки в элемент <form> без использования вспомогателей тегов с HTML-вспомогателем @Html.AntiForgeryToken.
<form asp-action="Index" asp-controller="Home" method="post">
@Html.AntiForgeryToken()
<!-- ... -->
</form>
В каждом из предыдущих случаев ASP.NET Core добавляет скрытое поле формы, аналогичное следующему примеру:
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">
ASP.NET Core включает три фильтра для работы с маркерами защиты от подделки:
Защита от подделок с AddControllers
Вызов AddControllersне включает маркеры защиты от подделки. AddControllersWithViews должен быть вызван для включения встроенной поддержки маркеров защиты от подделки.
Несколько вкладок браузера и шаблон токена синхронизатора
С помощью шаблона токена синхронизатора только последняя загруженная страница содержит допустимый токен защиты от подделки. Использование нескольких вкладок может быть проблематичным. Например, если пользователь открывает несколько вкладок:
- Только последняя загруженная вкладка содержит допустимый маркер антифальсификации.
- Запросы, сделанные из ранее загруженных вкладок, завершаются ошибкой:
Antiforgery token validation failed. The antiforgery cookie token and request token do not match
Если это представляет проблему, рассмотрите альтернативные шаблоны защиты CSRF.
Настройка защиты от подделки с помощью AntiforgeryOptions
Настройте AntiforgeryOptions в файле приложения Program :
builder.Services.AddAntiforgery(options =>
{
// Set Cookie properties using CookieBuilder properties†.
options.FormFieldName = "AntiforgeryFieldname";
options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
options.SuppressXFrameOptionsHeader = false;
});
Установите свойства антиподделки cookie, используя свойства класса CookieBuilder, как показано в следующей таблице.
| Вариант | Описание |
|---|---|
| Cookie | Определяет параметры, используемые для создания файлов cookie антивзломной защиты. |
| FormFieldName | Имя скрытого поля формы, используемого системой защиты от подделки для отображения токенов в представлениях. |
| HeaderName | Имя заголовка, используемого антифоргерской системой. Если nullсистема рассматривает только данные формы. |
| SuppressXFrameOptionsHeader | Указывает, следует ли подавлять создание заголовка X-Frame-Options . По умолчанию заголовок создается со значением "SAMEORIGIN". По умолчанию — false. |
Некоторые браузеры не разрешают небезопасным конечным точкам устанавливать файлы cookie с флагом "безопасный" или перезаписывать файлы cookie, флаг безопасности которых установлен (дополнительные сведения см. в разделе "Нерекомендуемые изменения" файлов cookie из небезопасных источников). Так как сочетание безопасных и небезопасных конечных точек является распространённым сценарием в приложениях, ASP.NET Core ослабляет ограничение на политику безопасности для некоторых файлов cookie, таких как антифальсификация cookie, задав значение для cookieSecurePolicy и CookieSecurePolicy.None. Даже если злоумышленник украдет токен антифальсификации cookie, он также должен украсть дополнительный токен антифальсификации, который обычно отправляется через поле формы (более распространённым способом) или отдельный заголовок запроса (менее распространённым способом), а также токен аутентификации cookie. Файлы cookie, связанные с проверкой подлинности или авторизацией, используют более надежную политику, чем CookieSecurePolicy.None.
Кроме того, вы можете защитить антифоргерию в средах, отличных от разработки cookie , с помощью протокола SSL только по протоколу HTTPS со следующим AntiforgeryOptions.Cookie параметром свойства в файле приложения Program :
if (!builder.Environment.IsDevelopment())
{
builder.Services.AddAntiforgery(o =>
{
o.Cookie.SecurePolicy = CookieSecurePolicy.Always;
});
}
Дополнительные сведения см. в разделе CookieAuthenticationOptions.
Генерация маркеров защиты от подделки с помощью IAntiforgery
IAntiforgery предоставляет API для настройки функций антифоргерии.
IAntiforgery можно запросить Program.cs с помощью WebApplication.Services. В следующем примере используется промежуточное ПО (middleware) на главной странице приложения для создания маркера защиты от подделки и отправки его в ответ в виде cookie:
app.UseRouting();
app.UseAuthorization();
var antiforgery = app.Services.GetRequiredService<IAntiforgery>();
app.Use((context, next) =>
{
var requestPath = context.Request.Path.Value;
if (string.Equals(requestPath, "/", StringComparison.OrdinalIgnoreCase)
|| string.Equals(requestPath, "/index.html", StringComparison.OrdinalIgnoreCase))
{
var tokenSet = antiforgery.GetAndStoreTokens(context);
context.Response.Cookies.Append("XSRF-TOKEN", tokenSet.RequestToken!,
new CookieOptions { HttpOnly = false });
}
return next(context);
});
В предыдущем примере задается cookie, называемый XSRF-TOKEN. Клиент может прочитать это cookie и указать его значение в качестве заголовка, присоединенного к запросам AJAX. Например, Angular включает встроенную защиту XSRF, которая по умолчанию считывает cookie с именем cookieXSRF-TOKEN.
Требовать антифальсификационной проверки
Фильтр действий ValidateAntiForgeryToken можно применить к отдельному действию, контроллеру или глобально. Запросы, сделанные к действиям, к которым применяется этот фильтр, блокируются, если запрос не включает допустимый маркер антифоргерии.
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Index()
{
// ...
return RedirectToAction();
}
Атрибут ValidateAntiForgeryToken требует маркер для всех запросов к методам действия, которые он отмечает, включая запросы HTTP GET. Если атрибут ValidateAntiForgeryToken применяется ко всем контроллерам приложения, его можно переопределить с помощью атрибута IgnoreAntiforgeryToken.
Автоматическая проверка маркеров защиты от подделки только для небезопасных методов HTTP
Вместо широкого применения атрибута ValidateAntiForgeryToken и переопределения его атрибутами IgnoreAntiforgeryTokenможно использовать атрибут AutoValidateAntiforgeryToken . Этот атрибут работает идентично атрибуту ValidateAntiForgeryToken , за исключением того, что он не требует маркеров для запросов, выполненных с помощью следующих методов HTTP:
- ПОЛУЧИТЬ
- Заголовок
- ПАРАМЕТРЫ
- ТРАССИРОВКА
Рекомендуется использовать AutoValidateAntiforgeryToken широко для сценариев, отличных от API. Этот атрибут гарантирует, что действия POST защищены по умолчанию. Альтернативой является игнорирование маркеров антифоргерии по умолчанию, если ValidateAntiForgeryToken не применяется к отдельным методам действия. Скорее всего, в этом сценарии метод действия POST остается незащищенным по ошибке, оставляя приложение уязвимым к атакам CSRF. Все запросы POST должны отправлять антифорджери-токен.
API не имеют автоматического механизма для отправки той части токена, которая не является cookie. Реализация, вероятно, зависит от реализации клиентского кода. Ниже показаны некоторые примеры:
Пример уровня класса:
[AutoValidateAntiforgeryToken]
public class HomeController : Controller
Глобальный пример:
builder.Services.AddControllersWithViews(options =>
{
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
});
Переопределение глобальных атрибутов или атрибутов защиты от подделки в контроллере
Фильтр IgnoreAntiforgeryToken используется для устранения необходимости в токене защиты от подделки для данного действия (или контроллера). При применении этот фильтр переопределяет фильтры ValidateAntiForgeryToken и AutoValidateAntiforgeryToken, указанные на более высоком уровне (глобально или на контроллере).
[IgnoreAntiforgeryToken]
public IActionResult IndexOverride()
{
// ...
return RedirectToAction();
}
Обновление токенов после аутентификации
Маркеры должны обновляться после проверки подлинности пользователя, перенаправляя пользователя на страницу представления или Razor страницы.
JavaScript, AJAX и SPA
В традиционных приложениях на основе HTML маркеры защиты от подмен передаются серверу с помощью скрытых полей формы. В современных приложениях и spAs на основе JavaScript многие запросы выполняются программными средствами. Эти запросы AJAX могут использовать другие методы (например, заголовки запросов или файлы cookie) для отправки маркера.
Если файлы cookie используются для хранения маркеров проверки подлинности и проверки подлинности запросов API на сервере, CSRF является потенциальной проблемой. Если локальное хранилище используется для хранения маркера, уязвимость CSRF может быть устранена, так как значения из локального хранилища не отправляются автоматически на сервер с каждым запросом. Использование локального хранилища для хранения маркера защиты от подделки на клиенте и отправка маркера в качестве заголовка запроса рекомендуется.
JavaScript
Используя JavaScript в представлениях, маркер можно создать через службу непосредственно в представлении. Внедрите службу IAntiforgery в представление и вызовите GetAndStoreTokens.
@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Antiforgery
@{
ViewData["Title"] = "JavaScript";
var requestToken = Antiforgery.GetAndStoreTokens(Context).RequestToken;
}
<input id="RequestVerificationToken" type="hidden" value="@requestToken" />
<button id="button" class="btn btn-primary">Submit with Token</button>
<div id="result" class="mt-2"></div>
@section Scripts {
<script>
document.addEventListener("DOMContentLoaded", () => {
const resultElement = document.getElementById("result");
document.getElementById("button").addEventListener("click", async () => {
const response = await fetch("@Url.Action("FetchEndpoint")", {
method: "POST",
headers: {
RequestVerificationToken:
document.getElementById("RequestVerificationToken").value
}
});
if (response.ok) {
resultElement.innerText = await response.text();
} else {
resultElement.innerText = `Request Failed: ${response.status}`
}
});
});
</script>
}
В предыдущем примере используется JavaScript для чтения значения скрытого поля для заголовка AJAX POST.
Этот подход устраняет необходимость непосредственной настройки файлов cookie с сервера или их чтения от клиента. Однако, если внедрение службы IAntiforgery невозможно, используйте JavaScript для доступа к маркерам в файлах cookie.
- Маркеры доступа в дополнительном запросе к серверу обычно
same-origin. - Используйте содержимое cookie, чтобы создать заголовок со значением токена.
Если скрипт отправляет маркер в заголовке запроса X-XSRF-TOKEN, настройте службу защиты от подделки для поиска заголовка X-XSRF-TOKEN :
builder.Services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
В следующем примере добавляется защищенный конечный пункт, который записывает токен запроса в элемент cookie, доступный для считывания JavaScript.
app.UseAuthorization();
app.MapGet("antiforgery/token", (IAntiforgery forgeryService, HttpContext context) =>
{
var tokens = forgeryService.GetAndStoreTokens(context);
context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken!,
new CookieOptions { HttpOnly = false });
return Results.Ok();
}).RequireAuthorization();
В следующем примере JavaScript используется для выполнения запроса AJAX для получения маркера и выполнения другого запроса с соответствующим заголовком:
var response = await fetch("/antiforgery/token", {
method: "GET",
headers: { "Authorization": authorizationToken }
});
if (response.ok) {
// https://developer.mozilla.org/docs/web/api/document/cookie
const xsrfToken = document.cookie
.split("; ")
.find(row => row.startsWith("XSRF-TOKEN="))
.split("=")[1];
response = await fetch("/JavaScript/FetchEndpoint", {
method: "POST",
headers: { "X-XSRF-TOKEN": xsrfToken, "Authorization": authorizationToken }
});
if (response.ok) {
resultElement.innerText = await response.text();
} else {
resultElement.innerText = `Request Failed: ${response.status}`
}
} else {
resultElement.innerText = `Request Failed: ${response.status}`
}
Примечание.
Если антифальсификационный маркер указан как в заголовке запроса, так и в полезных данных формы, проверяется только маркер в заголовке.
Антифальсификация с минимальными интерфейсами API
Minimal APIs не поддерживает использование включенных фильтров (ValidateAntiForgeryToken, AutoValidateAntiforgeryToken, IgnoreAntiforgeryTokenоднако), IAntiforgery предоставляет необходимые API для проверки запроса.
В следующем примере создается фильтр, проверяющий антиконтрафактный маркер:
internal static class AntiForgeryExtensions
{
public static TBuilder ValidateAntiforgery<TBuilder>(this TBuilder builder) where TBuilder : IEndpointConventionBuilder
{
return builder.AddEndpointFilter(routeHandlerFilter: async (context, next) =>
{
try
{
var antiForgeryService = context.HttpContext.RequestServices.GetRequiredService<IAntiforgery>();
await antiForgeryService.ValidateRequestAsync(context.HttpContext);
}
catch (AntiforgeryValidationException)
{
return Results.BadRequest("Antiforgery token validation failed.");
}
return await next(context);
});
}
}
Затем фильтр можно применить к конечной точке:
app.MapPost("api/upload", (IFormFile name) => Results.Accepted())
.RequireAuthorization()
.ValidateAntiforgery();
файлы cookie аутентификации Windows и защиты от подделки
При использовании проверки подлинности Windows конечные точки приложений должны быть защищены от атак CSRF так же, как и для файлов cookie. Браузер неявно отправляет контекст проверки подлинности серверу и конечным точкам, которые необходимо защитить от атак CSRF.
Расширить защиту от подделок
Тип IAntiforgeryAdditionalDataProvider позволяет разработчикам расширить поведение системы защиты от CSRF путем обхода дополнительных данных в каждом токене. Метод GetAdditionalData вызывается каждый раз при создании маркера поля, а возвращаемое значение внедрено в созданный маркер. Реализующий может возвращать метку времени, nonce или любое другое значение, а затем вызывать ValidateAdditionalData для проверки этих данных при проверке этого токена. Имя пользователя клиента уже внедрено в созданные маркеры, поэтому не нужно включать эти сведения. Если в маркере содержатся дополнительные данные, но IAntiForgeryAdditionalDataProvider не настроен, то дополнительные данные не проверяются.
Дополнительные ресурсы
Межсайтовая подделка запросов (также известная как XSRF или CSRF) — это атака на веб-приложения, посредством которых вредоносное веб-приложение может влиять на взаимодействие между клиентским браузером и веб-приложением, которое доверяет этому браузеру. Эти атаки возможны, так как веб-браузеры автоматически отправляют некоторые типы маркеров проверки подлинности с каждым запросом на веб-сайт. Эта форма эксплойта также называется атакой одним щелчком или сеансовым угоном, так как атака использует прошедший аутентификацию сеанс пользователя.
Пример атаки CSRF:
Пользователь входит в
www.good-banking-site.example.comсистему с помощью проверки подлинности форм. Сервер выполняет проверку подлинности пользователя и выдает ответ, содержащий проверку подлинности cookie. Сайт уязвим к атакам, поскольку сайт доверяет любому полученному запросу с допустимой аутентификацией cookie.Пользователь посещает вредоносный сайт.
www.bad-crook-site.example.comВредоносный сайт
www.bad-crook-site.example.comсодержит HTML-форму, аналогичную следующему примеру:<h1>Congratulations! You're a Winner!</h1> <form action="https://www.good-banking-site.example.com/api/account" method="post"> <input type="hidden" name="Transaction" value="withdraw" /> <input type="hidden" name="Amount" value="1000000" /> <input type="submit" value="Click to collect your prize!" /> </form>Обратите внимание, что отправка формы
actionпроисходит на уязвимый сайт, а не на вредоносный сайт. Это "межсайтовая" часть CSRF.Пользователь выбирает кнопку отправки. Браузер выполняет запрос и автоматически включает проверку подлинности cookie для запрошенного домена
www.good-banking-site.example.com.Запрос выполняется на сервере
www.good-banking-site.example.comс контекстом проверки подлинности пользователя и может выполнять любое действие, которое разрешено выполнить пользователю, прошедшему проверку подлинности.
Помимо сценария, когда пользователь выбирает кнопку для отправки формы, вредоносный сайт может:
- Запустите скрипт, который автоматически отправляет форму.
- Отправьте отправку формы в виде запроса AJAX.
- Скрытие формы с помощью CSS.
Эти альтернативные сценарии не требуют никаких действий или входных данных от пользователя, кроме первоначального посещения вредоносного сайта.
Использование HTTPS не предотвращает атаку CSRF. Вредоносный сайт может отправлять https://www.good-banking-site.example.com/ запрос так же легко, как он может отправлять небезопасный запрос.
Некоторые атаки предназначены для конечных точек, реагирующих на запросы GET, в этом случае тег изображения можно использовать для выполнения действия. Эта форма атаки распространена на сайтах форума, которые разрешают изображения, но блокируют JavaScript. Приложения, изменяющие состояние запросов GET, в которых переменные или ресурсы изменяются, уязвимы для вредоносных атак. Запросы GET, изменяющие состояние, небезопасны. Рекомендуется никогда не изменять состояние запроса GET.
Атаки CSRF возможны для веб-приложений, использующих файлы cookie для проверки подлинности, так как:
- Браузеры хранят файлы cookie, выданные веб-приложением.
- Сохраненные файлы cookie включают файлы cookie сеанса для пользователей, прошедших аутентификацию.
- Браузеры отправляют все файлы cookie, связанные с доменом, в веб-приложение каждый запрос независимо от того, как был создан запрос к приложению в браузере.
Однако атаки CSRF не ограничиваются использованием файлов cookie. Например, Базовая и Дайджест-аутентификация также уязвимы. После входа пользователя с помощью базовой или дайджест-проверки подлинности браузер автоматически отправляет учетные данные до окончания сеанса.
В этом контексте сеанс ссылается на сеанс на стороне клиента, в течение которого пользователь проходит проверку подлинности. Это не связано с сеансами на стороне сервера или Промежуточным программным обеспечением сеансов ASP.NET Core.
Пользователи могут защищаться от уязвимостей CSRF, принимая меры предосторожности:
- Выйдите из веб-приложений после завершения работы с ними.
- Периодически очищать файлы cookie браузера.
Однако уязвимости CSRF являются основной проблемой веб-приложения, а не конечным пользователем.
Основы проверки подлинности
Аутентификация на основе Cookie является популярной формой проверки подлинности. Системы аутентификации на основе токенов становятся всё более популярными, особенно для одностраничных приложений (SPA).
Cookie-основанная аутентификация
Когда пользователь проходит аутентификацию с помощью имени пользователя и пароля, ему выдается токен, содержащий аутентификационный билет, который используется для аутентификации и авторизации. Маркер хранится как cookie, который отправляется с каждым запросом клиента. Создание и проверка этого cookie осуществляется промежуточным ПО проверки подлинности Cookie. Промежуточное ПО
Проверка подлинности на основе токенов
Когда пользователь проходит проверку подлинности, ему выдается токен (а не антифальсификационный токен). Токен содержит информацию о пользователе в виде утверждений или ссылочного токена, который указывает приложению на состояние пользователя, сохраняемое в приложении. Когда пользователь пытается получить доступ к ресурсу, требующего проверки подлинности, токен отправляется приложению с дополнительным заголовком авторизации в виде токена типа Bearer. Такой подход делает приложение бессостоя́тельным. В каждом последующем запросе маркер передается в запросе на проверку на стороне сервера. Этот маркер не шифруется; он закодирован. На сервере маркер декодируется для доступа к его информации. Чтобы отправить маркер на последующие запросы, сохраните маркер в локальном хранилище браузера. Не беспокойтесь об уязвимости CSRF, если маркер хранится в локальном хранилище браузера. CSRF является проблемой, когда токен хранится в cookie. Для получения дополнительной информации см. проблему GitHub SPA code sample adds two cookies.
Несколько приложений, размещенных в одном домене
Среды общего размещения уязвимы к перехвату сеанса, CSRF-атакам при входе и другим видам атак.
Хотя example1.contoso.net и example2.contoso.net являются разными узлами, существует неявная связь доверия между узлами в домене *.contoso.net . Эта неявная связь доверия позволяет потенциально ненадежным узлам влиять на файлы cookie друг друга (политики того же источника, которые управляют запросами AJAX, не обязательно применяются к файлам cookie HTTP).
Атаки, которые используют доверенные файлы cookie между приложениями, размещенными в одном домене, можно предотвратить, не предоставляя общий доступ к доменам. Если каждое приложение размещено в собственном домене, не существует неявных cookie отношений доверия для эксплойтов.
Защита от подделок в ASP.NET Core
Предупреждение
ASP.NET Core реализует антифоргерию с помощью ASP.NET Core Data Protection. Стек защиты данных должен быть настроен для работы в ферме серверов. Дополнительные сведения см. в разделе "Настройка защиты данных".
Промежуточное программное обеспечение для защиты от подделок добавляется в контейнер внедрения зависимостей, если вызывается один из следующих API:
FormTagHelper вставляет маркеры защиты от подделки в элементы HTML-форм. Следующий тег в Razor файле автоматически создает антифальсификационные токены:
<form method="post">
<!-- ... -->
</form>
Аналогичным образом IHtmlHelper.BeginForm создаёт маркеры антифальсификации по умолчанию, если метод формы не является GET.
Автоматическое создание маркеров антиподделки для элементов формы HTML происходит, когда <form> тег содержит method="post" атрибут, и выполняется любое из следующих условий:
- Атрибут действия пуст (
action=""). - Атрибут действия не предоставляется (
<form method="post">).
Автоматическое создание маркеров антифоргерии для элементов формы HTML можно отключить:
Явно отключите антифальсификационные маркеры с помощью атрибута
asp-antiforgery.<form method="post" asp-antiforgery="false"> <!-- ... --> </form>Элемент формы исключен из вспомогательных тегов, используя символ выхода из тегов !.
<!form method="post"> <!-- ... --> </!form>Удалите
FormTagHelperиз представления.FormTagHelperможно удалить из представления, добавив следующую директиву в представление Razor.@removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
Примечание.
Razor Страницы автоматически защищены от XSRF/CSRF. Дополнительные сведения см. в разделе XSRF/CSRF и Razor Pages.
Наиболее распространенный подход к защите от атак CSRF — использовать шаблон токена синхронизатора (STP). STP используется, когда пользователь запрашивает страницу с данными формы:
- Сервер отправляет маркер, связанный с удостоверением текущего пользователя клиенту.
- Клиент отправляет маркер на сервер для проверки.
- Если сервер получает маркер, который не соответствует удостоверению пользователя, прошедшего проверку подлинности, запрос отклоняется.
Токен является уникальным и непредсказуемым. Маркер также можно использовать для обеспечения правильной последовательности запросов (например, обеспечения последовательности запросов: страницы 1 > страницы 2 > страницы 3). Все формы в ASP.NET шаблонах Core MVC и Razor Pages создают маркеры защиты от подделки. Следующая пара примеров представления создает маркеры антифоргерии:
<form asp-action="Index" asp-controller="Home" method="post">
<!-- ... -->
</form>
@using (Html.BeginForm("Index", "Home"))
{
<!-- ... -->
}
Явно добавьте токен антиподделки в элемент <form> без использования вспомогателей тегов с HTML-вспомогателем @Html.AntiForgeryToken.
<form asp-action="Index" asp-controller="Home" method="post">
@Html.AntiForgeryToken()
<!-- ... -->
</form>
В каждом из предыдущих случаев ASP.NET Core добавляет скрытое поле формы, аналогичное следующему примеру:
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">
ASP.NET Core включает три фильтра для работы с маркерами защиты от подделки:
Защита от подделок с AddControllers
Вызов AddControllersне включает маркеры защиты от подделки. AddControllersWithViews должен быть вызван для включения встроенной поддержки маркеров защиты от подделки.
Несколько вкладок браузера и шаблон токена синхронизатора
С помощью шаблона токена синхронизатора только последняя загруженная страница содержит допустимый токен защиты от подделки. Использование нескольких вкладок может быть проблематичным. Например, если пользователь открывает несколько вкладок:
- Только последняя загруженная вкладка содержит допустимый маркер антифальсификации.
- Запросы, сделанные из ранее загруженных вкладок, завершаются ошибкой:
Antiforgery token validation failed. The antiforgery cookie token and request token do not match
Если это представляет проблему, рассмотрите альтернативные шаблоны защиты CSRF.
Настройка защиты от подделки с помощью AntiforgeryOptions
Настройте AntiforgeryOptions в файле приложения Program :
builder.Services.AddAntiforgery(options =>
{
// Set Cookie properties using CookieBuilder properties†.
options.FormFieldName = "AntiforgeryFieldname";
options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
options.SuppressXFrameOptionsHeader = false;
});
Установите свойства антиподделки cookie, используя свойства класса CookieBuilder, как показано в следующей таблице.
| Вариант | Описание |
|---|---|
| Cookie | Определяет параметры, используемые для создания файлов cookie антивзломной защиты. |
| FormFieldName | Имя скрытого поля формы, используемого системой защиты от подделки для отображения токенов в представлениях. |
| HeaderName | Имя заголовка, используемого антифоргерской системой. Если nullсистема рассматривает только данные формы. |
| SuppressXFrameOptionsHeader | Указывает, следует ли подавлять создание заголовка X-Frame-Options . По умолчанию заголовок создается со значением "SAMEORIGIN". По умолчанию — false. |
Некоторые браузеры не разрешают небезопасным конечным точкам устанавливать файлы cookie с флагом "безопасный" или перезаписывать файлы cookie, флаг безопасности которых установлен (дополнительные сведения см. в разделе "Нерекомендуемые изменения" файлов cookie из небезопасных источников). Так как сочетание безопасных и небезопасных конечных точек является распространенным сценарием в приложениях, ASP.NET Core ослабляет ограничения на политику безопасности для некоторых файлов cookie, таких как антифальсификация cookie, установив для cookie значение SecurePolicyCookieSecurePolicy.None. Даже если злоумышленник украдет компонент защиты от подделки cookie, он также должен украсть токен антифальсификации, который обычно передается через поле формы (что встречается чаще) или в отдельном заголовке запроса (что менее часто), а также компонент cookie. Файлы cookie, связанные с проверкой подлинности или авторизацией, используют более надежную политику, чем CookieSecurePolicy.None.
Кроме того, вы можете защитить от подделки в средах, отличных от среды разработки cookie, по защищенному протоколу SSL только через HTTPS, с помощью следующей настройки параметра в файле приложения Program:
if (!builder.Environment.IsDevelopment())
{
builder.Services.AddAntiforgery(o =>
{
o.Cookie.SecurePolicy = CookieSecurePolicy.Always;
});
}
Дополнительные сведения см. в разделе CookieAuthenticationOptions.
Генерация маркеров защиты от подделки с помощью IAntiforgery
IAntiforgery предоставляет API для настройки функций антифоргерии.
IAntiforgery можно запросить Program.cs с помощью WebApplication.Services. В следующем примере используется промежуточное ПО (middleware) на главной странице приложения для создания маркера защиты от подделки и отправки его в ответ в виде cookie:
app.UseRouting();
app.UseAuthorization();
var antiforgery = app.Services.GetRequiredService<IAntiforgery>();
app.Use((context, next) =>
{
var requestPath = context.Request.Path.Value;
if (string.Equals(requestPath, "/", StringComparison.OrdinalIgnoreCase)
|| string.Equals(requestPath, "/index.html", StringComparison.OrdinalIgnoreCase))
{
var tokenSet = antiforgery.GetAndStoreTokens(context);
context.Response.Cookies.Append("XSRF-TOKEN", tokenSet.RequestToken!,
new CookieOptions { HttpOnly = false });
}
return next(context);
});
В предыдущем примере задается cookie, называемый XSRF-TOKEN. Клиент может прочитать это cookie и указать его значение в качестве заголовка, присоединенного к запросам AJAX. Например, Angular включает встроенную защиту XSRF, которая по умолчанию считывает cookie с именем cookieXSRF-TOKEN.
Требовать антифальсификационной проверки
Фильтр действий ValidateAntiForgeryToken можно применить к отдельному действию, контроллеру или глобально. Запросы, сделанные к действиям, к которым применяется этот фильтр, блокируются, если запрос не включает допустимый маркер антифоргерии.
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Index()
{
// ...
return RedirectToAction();
}
Атрибут ValidateAntiForgeryToken требует маркер для всех запросов к методам действия, которые он отмечает, включая запросы HTTP GET. Если атрибут ValidateAntiForgeryToken применяется ко всем контроллерам приложения, его можно переопределить с помощью атрибута IgnoreAntiforgeryToken.
Автоматическая проверка маркеров защиты от подделки только для небезопасных методов HTTP
Вместо широкого применения атрибута ValidateAntiForgeryToken и переопределения его атрибутами IgnoreAntiforgeryTokenможно использовать атрибут AutoValidateAntiforgeryToken . Этот атрибут работает идентично атрибуту ValidateAntiForgeryToken , за исключением того, что он не требует маркеров для запросов, выполненных с помощью следующих методов HTTP:
- ПОЛУЧИТЬ
- Заголовок
- ПАРАМЕТРЫ
- ТРАССИРОВКА
Рекомендуется использовать AutoValidateAntiforgeryToken широко для сценариев, отличных от API. Этот атрибут гарантирует, что действия POST защищены по умолчанию. Альтернативой является игнорирование маркеров антифоргерии по умолчанию, если ValidateAntiForgeryToken не применяется к отдельным методам действия. Скорее всего, в этом сценарии метод действия POST остается незащищенным по ошибке, оставляя приложение уязвимым к атакам CSRF. Все запросы POST должны отправлять антифорджери-токен.
API не имеют автоматического механизма для отправки той части токена, которая не является cookie. Реализация, вероятно, зависит от реализации клиентского кода. Ниже показаны некоторые примеры:
Пример уровня класса:
[AutoValidateAntiforgeryToken]
public class HomeController : Controller
Глобальный пример:
builder.Services.AddControllersWithViews(options =>
{
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
});
Переопределение глобальных атрибутов или атрибутов защиты от подделки в контроллере
Фильтр IgnoreAntiforgeryToken используется для устранения необходимости в токене защиты от подделки для данного действия (или контроллера). При применении этот фильтр переопределяет фильтры ValidateAntiForgeryToken и AutoValidateAntiforgeryToken, указанные на более высоком уровне (глобально или на контроллере).
[IgnoreAntiforgeryToken]
public IActionResult IndexOverride()
{
// ...
return RedirectToAction();
}
Обновление токенов после аутентификации
Маркеры должны обновляться после проверки подлинности пользователя, перенаправляя пользователя на страницу представления или Razor страницы.
JavaScript, AJAX и SPA
В традиционных приложениях на основе HTML маркеры защиты от подмен передаются серверу с помощью скрытых полей формы. В современных приложениях и spAs на основе JavaScript многие запросы выполняются программными средствами. Эти запросы AJAX могут использовать другие методы (например, заголовки запросов или файлы cookie) для отправки маркера.
Если файлы cookie используются для хранения маркеров проверки подлинности и проверки подлинности запросов API на сервере, CSRF является потенциальной проблемой. Если локальное хранилище используется для хранения маркера, уязвимость CSRF может быть устранена, так как значения из локального хранилища не отправляются автоматически на сервер с каждым запросом. Использование локального хранилища для хранения маркера защиты от подделки на клиенте и отправка маркера в качестве заголовка запроса рекомендуется.
JavaScript
Используя JavaScript в представлениях, маркер можно создать через службу непосредственно в представлении. Внедрите службу IAntiforgery в представление и вызовите GetAndStoreTokens.
@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Antiforgery
@{
ViewData["Title"] = "JavaScript";
var requestToken = Antiforgery.GetAndStoreTokens(Context).RequestToken;
}
<input id="RequestVerificationToken" type="hidden" value="@requestToken" />
<button id="button" class="btn btn-primary">Submit with Token</button>
<div id="result" class="mt-2"></div>
@section Scripts {
<script>
document.addEventListener("DOMContentLoaded", () => {
const resultElement = document.getElementById("result");
document.getElementById("button").addEventListener("click", async () => {
const response = await fetch("@Url.Action("FetchEndpoint")", {
method: "POST",
headers: {
RequestVerificationToken:
document.getElementById("RequestVerificationToken").value
}
});
if (response.ok) {
resultElement.innerText = await response.text();
} else {
resultElement.innerText = `Request Failed: ${response.status}`
}
});
});
</script>
}
В предыдущем примере используется JavaScript для чтения значения скрытого поля для заголовка AJAX POST.
Этот подход устраняет необходимость непосредственной настройки файлов cookie с сервера или их чтения от клиента. Однако когда внедрение службы IAntiforgery невозможно, JavaScript также может получить доступ к токену в файлах cookie, полученных из дополнительного запроса к серверу (обычно same-origin), и использовать содержимое cookie для создания заголовка со значением токена.
Если скрипт отправляет маркер в заголовке запроса X-XSRF-TOKEN, настройте службу защиты от подделки для поиска заголовка X-XSRF-TOKEN :
builder.Services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
В следующем примере добавляется защищенная конечная точка, которая будет записывать маркер запроса в читаемый JavaScript cookie.
app.UseAuthorization();
app.MapGet("antiforgery/token", (IAntiforgery forgeryService, HttpContext context) =>
{
var tokens = forgeryService.GetAndStoreTokens(context);
context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken!,
new CookieOptions { HttpOnly = false });
return Results.Ok();
}).RequireAuthorization();
В следующем примере JavaScript используется для выполнения запроса AJAX для получения маркера и выполнения другого запроса с соответствующим заголовком:
var response = await fetch("/antiforgery/token", {
method: "GET",
headers: { "Authorization": authorizationToken }
});
if (response.ok) {
// https://developer.mozilla.org/docs/web/api/document/cookie
const xsrfToken = document.cookie
.split("; ")
.find(row => row.startsWith("XSRF-TOKEN="))
.split("=")[1];
response = await fetch("/JavaScript/FetchEndpoint", {
method: "POST",
headers: { "X-XSRF-TOKEN": xsrfToken, "Authorization": authorizationToken }
});
if (response.ok) {
resultElement.innerText = await response.text();
} else {
resultElement.innerText = `Request Failed: ${response.status}`
}
} else {
resultElement.innerText = `Request Failed: ${response.status}`
}
файлы cookie аутентификации Windows и защиты от подделки
При использовании проверки подлинности Windows конечные точки приложений должны быть защищены от атак CSRF так же, как и для файлов cookie. Браузер неявно отправляет контекст проверки подлинности серверу и поэтому конечные точки должны быть защищены от атак CSRF.
Расширить защиту от подделок
Тип IAntiforgeryAdditionalDataProvider позволяет разработчикам расширить поведение системы защиты от CSRF путем обхода дополнительных данных в каждом токене. Метод GetAdditionalData вызывается каждый раз при создании маркера поля, а возвращаемое значение внедрено в созданный маркер. Реализующий может возвращать метку времени, nonce или любое другое значение, а затем вызывать ValidateAdditionalData для проверки этих данных при проверке этого токена. Имя пользователя клиента уже внедрено в созданные маркеры, поэтому не нужно включать эти сведения. Если в маркере содержатся дополнительные данные, но IAntiForgeryAdditionalDataProvider не настроен, то дополнительные данные не проверяются.
Дополнительные ресурсы
Межсайтовая подделка запросов (также известная как XSRF или CSRF) — это атака на веб-приложения, посредством которых вредоносное веб-приложение может влиять на взаимодействие между клиентским браузером и веб-приложением, которое доверяет этому браузеру. Эти атаки возможны, так как веб-браузеры автоматически отправляют некоторые типы маркеров проверки подлинности с каждым запросом на веб-сайт. Эта форма эксплойта также называется атакой одним щелчком или сеансовым угоном, так как атака использует прошедший аутентификацию сеанс пользователя.
Пример атаки CSRF:
Пользователь входит в
www.good-banking-site.example.comсистему с помощью проверки подлинности форм. Сервер выполняет проверку подлинности пользователя и выдает ответ, содержащий проверку подлинности cookie. Сайт уязвим к атакам, поскольку сайт доверяет любому полученному запросу с допустимой аутентификацией cookie.Пользователь посещает вредоносный сайт.
www.bad-crook-site.example.comВредоносный сайт
www.bad-crook-site.example.comсодержит HTML-форму, аналогичную следующему примеру:<h1>Congratulations! You're a Winner!</h1> <form action="https://www.good-banking-site.example.com/api/account" method="post"> <input type="hidden" name="Transaction" value="withdraw" /> <input type="hidden" name="Amount" value="1000000" /> <input type="submit" value="Click to collect your prize!" /> </form>Обратите внимание, что отправка формы
actionпроисходит на уязвимый сайт, а не на вредоносный сайт. Это "межсайтовая" часть CSRF.Пользователь выбирает кнопку отправки. Браузер выполняет запрос и автоматически включает проверку подлинности cookie для запрошенного домена
www.good-banking-site.example.com.Запрос выполняется на сервере
www.good-banking-site.example.comс контекстом проверки подлинности пользователя и может выполнять любое действие, которое разрешено выполнить пользователю, прошедшему проверку подлинности.
Помимо сценария, когда пользователь выбирает кнопку для отправки формы, вредоносный сайт может:
- Запустите скрипт, который автоматически отправляет форму.
- Отправьте отправку формы в виде запроса AJAX.
- Скрытие формы с помощью CSS.
Эти альтернативные сценарии не требуют никаких действий или входных данных от пользователя, кроме первоначального посещения вредоносного сайта.
Использование HTTPS не предотвращает атаку CSRF. Вредоносный сайт может отправлять https://www.good-banking-site.example.com/ запрос так же легко, как он может отправлять небезопасный запрос.
Некоторые атаки предназначены для конечных точек, реагирующих на запросы GET, в этом случае тег изображения можно использовать для выполнения действия. Эта форма атаки распространена на сайтах форума, которые разрешают изображения, но блокируют JavaScript. Приложения, изменяющие состояние запросов GET, в которых переменные или ресурсы изменяются, уязвимы для вредоносных атак. Запросы GET, изменяющие состояние, небезопасны. Рекомендуется никогда не изменять состояние запроса GET.
Атаки CSRF возможны для веб-приложений, использующих файлы cookie для проверки подлинности, так как:
- Браузеры хранят файлы cookie, выданные веб-приложением.
- Сохраненные файлы cookie включают файлы cookie сеанса для пользователей, прошедших аутентификацию.
- Браузеры отправляют все файлы cookie, связанные с доменом, в веб-приложение каждый запрос независимо от того, как был создан запрос к приложению в браузере.
Однако атаки CSRF не ограничиваются использованием файлов cookie. Например, Базовая и Дайджест-аутентификация также уязвимы. После входа пользователя с помощью базовой или дайджест-проверки подлинности браузер автоматически отправляет учетные данные до окончания сеанса.
В этом контексте сеанс ссылается на сеанс на стороне клиента, в течение которого пользователь проходит проверку подлинности. Это не связано с сеансами на стороне сервера или Промежуточным программным обеспечением сеансов ASP.NET Core.
Пользователи могут защищаться от уязвимостей CSRF, принимая меры предосторожности:
- Выйдите из веб-приложений после завершения работы с ними.
- Периодически очищать файлы cookie браузера.
Однако уязвимости CSRF являются основной проблемой веб-приложения, а не конечным пользователем.
Основы проверки подлинности
Аутентификация на основе Cookie является популярной формой проверки подлинности. Системы аутентификации на основе токенов становятся всё более популярными, особенно для одностраничных приложений (SPA).
Cookie-основанная аутентификация
Когда пользователь проходит аутентификацию с помощью имени пользователя и пароля, ему выдается токен, содержащий аутентификационный билет, который используется для аутентификации и авторизации. Маркер хранится как cookie, который отправляется с каждым запросом клиента. Создание и проверка этого cookie осуществляется промежуточным ПО проверки подлинности Cookie. Промежуточное ПО
Проверка подлинности на основе токенов
Когда пользователь проходит проверку подлинности, ему выдается токен (а не антифальсификационный токен). Токен содержит информацию о пользователе в виде утверждений или ссылочного токена, который указывает приложению на состояние пользователя, сохраняемое в приложении. Когда пользователь пытается получить доступ к ресурсу, требующего проверки подлинности, токен отправляется приложению с дополнительным заголовком авторизации в виде токена типа Bearer. Такой подход делает приложение бессостоя́тельным. В каждом последующем запросе маркер передается в запросе на проверку на стороне сервера. Этот маркер не шифруется; он закодирован. На сервере маркер декодируется для доступа к его информации. Чтобы отправить маркер на последующие запросы, сохраните маркер в локальном хранилище браузера. Не беспокойтесь об уязвимости CSRF, если маркер хранится в локальном хранилище браузера. CSRF является проблемой, когда токен хранится в cookie. Для получения дополнительной информации см. проблему GitHub SPA code sample adds two cookies.
Несколько приложений, размещенных в одном домене
Среды общего размещения уязвимы к перехвату сеанса, CSRF-атакам при входе и другим видам атак.
Хотя example1.contoso.net и example2.contoso.net являются разными узлами, существует неявная связь доверия между узлами в домене *.contoso.net . Эта неявная связь доверия позволяет потенциально ненадежным узлам влиять на файлы cookie друг друга (политики того же источника, которые управляют запросами AJAX, не обязательно применяются к файлам cookie HTTP).
Атаки, которые используют доверенные файлы cookie между приложениями, размещенными в одном домене, можно предотвратить, не предоставляя общий доступ к доменам. Если каждое приложение размещено в собственном домене, не существует неявных cookie отношений доверия для эксплойтов.
конфигурация antiforgery в ASP.NET Core
Предупреждение
ASP.NET Core реализует антифоргерию с помощью ASP.NET Core Data Protection. Стек защиты данных должен быть настроен для работы в ферме серверов. Дополнительные сведения см. в разделе "Настройка защиты данных".
Промежуточное программное обеспечение для защиты от подделок добавляется в контейнер внедрения зависимостей, если вызывается один из следующих API:
В ASP.NET Core 2.0 или более поздней версии FormTagHelper внедряет маркеры антифоргерии в элементы формы HTML. Следующий тег в Razor файле автоматически создает антифальсификационные токены:
<form method="post">
...
</form>
Аналогичным образом IHtmlHelper.BeginForm создаёт маркеры антифальсификации по умолчанию, если метод формы не является GET.
Автоматическое создание маркеров антиподделки для элементов формы HTML происходит, когда <form> тег содержит method="post" атрибут, и выполняется любое из следующих условий:
- Атрибут действия пуст (
action=""). - Атрибут действия не предоставляется (
<form method="post">).
Автоматическое создание маркеров антифоргерии для элементов формы HTML можно отключить:
Явно отключите антифальсификационные маркеры с помощью атрибута
asp-antiforgery.<form method="post" asp-antiforgery="false"> ... </form>Элемент формы исключен из вспомогательных тегов, используя символ выхода из тегов !.
<!form method="post"> ... </!form>Удалите
FormTagHelperиз представления.FormTagHelperможно удалить из представления, добавив следующую директиву в представление Razor.@removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
Примечание.
Razor Страницы автоматически защищены от XSRF/CSRF. Дополнительные сведения см. в разделе XSRF/CSRF и Razor Pages.
Наиболее распространенный подход к защите от атак CSRF — использовать шаблон токена синхронизатора (STP). STP используется, когда пользователь запрашивает страницу с данными формы:
- Сервер отправляет маркер, связанный с удостоверением текущего пользователя клиенту.
- Клиент отправляет маркер на сервер для проверки.
- Если сервер получает маркер, который не соответствует удостоверению пользователя, прошедшего проверку подлинности, запрос отклоняется.
Токен является уникальным и непредсказуемым. Маркер также можно использовать для обеспечения правильной последовательности запросов (например, обеспечения последовательности запросов: страницы 1 > страницы 2 > страницы 3). Все формы в ASP.NET шаблонах Core MVC и Razor Pages создают маркеры защиты от подделки. Следующая пара примеров представления создает маркеры антифоргерии:
<form asp-controller="Todo" asp-action="Create" method="post">
...
</form>
@using (Html.BeginForm("Create", "Todo"))
{
...
}
Явно добавьте токен антиподделки в элемент <form> без использования вспомогателей тегов с HTML-вспомогателем @Html.AntiForgeryToken.
<form action="/" method="post">
@Html.AntiForgeryToken()
</form>
В каждом из предыдущих случаев ASP.NET Core добавляет скрытое поле формы, аналогичное следующему примеру:
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">
ASP.NET Core включает три фильтра для работы с маркерами защиты от подделки:
Параметры защиты от подделок
Настройка AntiforgeryOptions в Startup.ConfigureServices:
services.AddAntiforgery(options =>
{
options.FormFieldName = "AntiforgeryFieldname";
options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
options.SuppressXFrameOptionsHeader = false;
});
Установите свойства антиподделки cookie, используя свойства класса CookieBuilder, как показано в следующей таблице.
| Вариант | Описание |
|---|---|
| Cookie | Определяет параметры, используемые для создания файлов cookie антивзломной защиты. |
| FormFieldName | Имя скрытого поля формы, используемого системой защиты от подделки для отображения токенов в представлениях. |
| HeaderName | Имя заголовка, используемого антифоргерской системой. Если nullсистема рассматривает только данные формы. |
| SuppressXFrameOptionsHeader | Указывает, следует ли подавлять создание заголовка X-Frame-Options . По умолчанию заголовок создается со значением "SAMEORIGIN". По умолчанию — false. |
Некоторые браузеры не разрешают небезопасным конечным точкам устанавливать файлы cookie с флагом "безопасный" или перезаписывать файлы cookie, флаг безопасности которых установлен (дополнительные сведения см. в разделе "Нерекомендуемые изменения" файлов cookie из небезопасных источников). Так как сочетание безопасных и небезопасных конечных точек является распространенным сценарием в приложениях, ASP.NET Core ослабляет ограничение на безопасную политику для некоторых файлов cookie, таких как антифальсификация cookie, устанавливая cookieSecurePolicy на CookieSecurePolicy.None. Даже если злоумышленник украдет cookie антифальсификационный токен, он также должен украсть токен антифальсификации, который обычно отправляется через поле формы (более распространенное) или отдельный заголовок запроса (менее распространенный), плюс аутентификационные данные cookie. Файлы cookie, связанные с проверкой подлинности или авторизацией, используют более надежную политику, чем CookieSecurePolicy.None.
При необходимости вы можете защитить антифальсификацию в средах, отличных от среды разработки, используя SSL только через HTTPS с помощью следующей настройки свойства в классе приложения Startup :
public class Startup
{
public Startup(IConfiguration configuration, IHostEnvironment environment)
{
Configuration = configuration;
Environment = environment;
}
public IConfiguration Configuration { get; }
public IHostEnvironment Environment { get; }
public void ConfigureServices(IServiceCollection services)
{
// Other services are registered here
if (!Environment.IsDevelopment())
{
services.AddAntiforgery(o =>
{
o.Cookie.SecurePolicy = CookieSecurePolicy.Always;
});
}
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// Request processing pipeline
}
}
Дополнительные сведения см. в разделе CookieAuthenticationOptions.
Настройка функций антифальсификации с помощью IAntiforgery
IAntiforgery предоставляет API для настройки функций антифоргерии.
IAntiforgery можно запросить в Configure методе Startup класса.
В следующем примере :
- Промежуточное ПО в приложении используется для создания маркера защиты от подделки и отправки его в ответ как cookie.
- Маркер запроса отправляется как cookie доступный для чтения JavaScript с соглашением по умолчанию об именовании Angular, описанным в разделе AngularJS.
public void Configure(IApplicationBuilder app, IAntiforgery antiforgery)
{
app.Use(next => context =>
{
string path = context.Request.Path.Value;
if (string.Equals(path, "/", StringComparison.OrdinalIgnoreCase) ||
string.Equals(path, "/index.html", StringComparison.OrdinalIgnoreCase))
{
var tokens = antiforgery.GetAndStoreTokens(context);
context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken,
new CookieOptions() { HttpOnly = false });
}
return next(context);
});
}
Требовать антифальсификационной проверки
ValidateAntiForgeryToken — это фильтр действий, который можно применить к отдельному действию, контроллеру или глобально. Запросы, направленные к действиям с этим фильтром, блокируются, если не содержат действительный маркер антифальсификации.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> RemoveLogin(RemoveLoginViewModel account)
{
ManageMessageId? message = ManageMessageId.Error;
var user = await GetCurrentUserAsync();
if (user != null)
{
var result =
await _userManager.RemoveLoginAsync(
user, account.LoginProvider, account.ProviderKey);
if (result.Succeeded)
{
await _signInManager.SignInAsync(user, isPersistent: false);
message = ManageMessageId.RemoveLoginSuccess;
}
}
return RedirectToAction(nameof(ManageLogins), new { Message = message });
}
Атрибут ValidateAntiForgeryToken требует маркер для всех запросов к методам действия, которые он отмечает, включая запросы HTTP GET. Если атрибут ValidateAntiForgeryToken применяется ко всем контроллерам приложения, его можно переопределить с помощью атрибута IgnoreAntiforgeryToken.
Примечание.
ASP.NET Core не поддерживает автоматическое добавление маркеров защиты от подделки в запросы GET.
Автоматическая проверка маркеров защиты от подделки только для небезопасных методов HTTP
ASP.NET приложения Core не создают маркеры защиты от подделки для безопасных методов HTTP (GET, HEAD, OPTIONS и TRACE). Вместо широкого применения атрибута ValidateAntiForgeryToken и переопределения его атрибутами IgnoreAntiforgeryTokenможно использовать атрибут AutoValidateAntiforgeryToken . Этот атрибут работает идентично атрибуту ValidateAntiForgeryToken , за исключением того, что он не требует маркеров для запросов, выполненных с помощью следующих методов HTTP:
- ПОЛУЧИТЬ
- Заголовок
- ПАРАМЕТРЫ
- ТРАССИРОВКА
Рекомендуется использовать AutoValidateAntiforgeryToken широко для сценариев, отличных от API. Этот атрибут гарантирует, что действия POST защищены по умолчанию. Альтернативой является игнорирование маркеров антифоргерии по умолчанию, если ValidateAntiForgeryToken не применяется к отдельным методам действия. Скорее всего, в этом сценарии метод действия POST остается незащищенным по ошибке, оставляя приложение уязвимым к атакам CSRF. Все запросы POST должны отправлять антифорджери-токен.
API не имеют автоматического механизма для отправки той части токена, которая не является cookie. Реализация, вероятно, зависит от реализации клиентского кода. Ниже показаны некоторые примеры:
Пример уровня класса:
[Authorize]
[AutoValidateAntiforgeryToken]
public class ManageController : Controller
{
Глобальный пример:
services.AddControllersWithViews(options =>
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute()));
Переопределение глобальных атрибутов или атрибутов защиты от подделки в контроллере
Фильтр IgnoreAntiforgeryToken используется для устранения необходимости в токене защиты от подделки для данного действия (или контроллера). При применении этот фильтр переопределяет фильтры ValidateAntiForgeryToken и AutoValidateAntiforgeryToken, указанные на более высоком уровне (глобально или на контроллере).
[Authorize]
[AutoValidateAntiforgeryToken]
public class ManageController : Controller
{
[HttpPost]
[IgnoreAntiforgeryToken]
public async Task<IActionResult> DoSomethingSafe(SomeViewModel model)
{
// no antiforgery token required
}
}
Обновление токенов после аутентификации
Маркеры должны обновляться после проверки подлинности пользователя, перенаправляя пользователя на страницу представления или Razor страницы.
JavaScript, AJAX и SPA
В традиционных приложениях на основе HTML маркеры защиты от подмен передаются серверу с помощью скрытых полей формы. В современных приложениях и spAs на основе JavaScript многие запросы выполняются программными средствами. Эти запросы AJAX могут использовать другие методы (например, заголовки запросов или файлы cookie) для отправки маркера.
Если файлы cookie используются для хранения маркеров проверки подлинности и проверки подлинности запросов API на сервере, CSRF является потенциальной проблемой. Если локальное хранилище используется для хранения маркера, уязвимость CSRF может быть устранена, так как значения из локального хранилища не отправляются автоматически на сервер с каждым запросом. Использование локального хранилища для хранения маркера защиты от подделки на клиенте и отправка маркера в качестве заголовка запроса рекомендуется.
JavaScript
Используя JavaScript в представлениях, маркер можно создать через службу непосредственно в представлении. Внедрите службу IAntiforgery в представление и вызовите GetAndStoreTokens.
@{
ViewData["Title"] = "AJAX Demo";
}
@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf
@functions{
public string GetAntiXsrfRequestToken()
{
return Xsrf.GetAndStoreTokens(Context).RequestToken;
}
}
<input type="hidden" id="RequestVerificationToken"
name="RequestVerificationToken" value="@GetAntiXsrfRequestToken()">
<h2>@ViewData["Title"].</h2>
<h3>@ViewData["Message"]</h3>
<div class="row">
<p><input type="button" id="antiforgery" value="Antiforgery"></p>
<script>
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (xhttp.readyState == XMLHttpRequest.DONE) {
if (xhttp.status == 200) {
alert(xhttp.responseText);
} else {
alert('There was an error processing the AJAX request.');
}
}
};
document.addEventListener('DOMContentLoaded', function() {
document.getElementById("antiforgery").onclick = function () {
xhttp.open('POST', '@Url.Action("Antiforgery", "Home")', true);
xhttp.setRequestHeader("RequestVerificationToken",
document.getElementById('RequestVerificationToken').value);
xhttp.send();
}
});
</script>
</div>
Этот подход устраняет необходимость непосредственной настройки файлов cookie с сервера или их чтения от клиента.
В предыдущем примере используется JavaScript для чтения значения скрытого поля для заголовка AJAX POST.
JavaScript также может получить доступ к токенам в файлах cookie и использовать содержимое cookie для создания заголовка с токеном.
context.Response.Cookies.Append("CSRF-TOKEN", tokens.RequestToken,
new Microsoft.AspNetCore.Http.CookieOptions { HttpOnly = false });
Если скрипт запрашивает отправку маркера в заголовке с именем X-CSRF-TOKEN, настройте службу защиты от подделки для поиска заголовка X-CSRF-TOKEN :
services.AddAntiforgery(options => options.HeaderName = "X-CSRF-TOKEN");
В следующем примере используется JavaScript для выполнения запроса AJAX с соответствующим заголовком:
function getCookie(cname) {
var name = cname + "=";
var decodedCookie = decodeURIComponent(document.cookie);
var ca = decodedCookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) === ' ') {
c = c.substring(1);
}
if (c.indexOf(name) === 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
var csrfToken = getCookie("CSRF-TOKEN");
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
if (xhttp.readyState === XMLHttpRequest.DONE) {
if (xhttp.status === 204) {
alert('Todo item is created successfully.');
} else {
alert('There was an error processing the AJAX request.');
}
}
};
xhttp.open('POST', '/api/items', true);
xhttp.setRequestHeader("Content-type", "application/json");
xhttp.setRequestHeader("X-CSRF-TOKEN", csrfToken);
xhttp.send(JSON.stringify({ "name": "Learn C#" }));
AngularJS
AngularJS использует стандартный метод для решения проблемы CSRF. Если сервер отправляет cookie с именем XSRF-TOKEN, сервис AngularJS $http добавляет значение cookie в заголовок при отправке запроса на сервер. Этот процесс автоматический. Клиенту не нужно явно задавать заголовок. Имя заголовка — X-XSRF-TOKEN. Сервер должен обнаружить этот заголовок и проверить его содержимое.
Чтобы ASP.NET Core API работал с этим соглашением при запуске приложения:
- Настройте приложение для передачи токена в cookie, называемом
XSRF-TOKEN. - Настройте службу защиты от подделок для поиска заголовка с именем
X-XSRF-TOKEN, которая используется в Angular по умолчанию для отправки XSRF-токена.
public void Configure(IApplicationBuilder app, IAntiforgery antiforgery)
{
app.Use(next => context =>
{
string path = context.Request.Path.Value;
if (
string.Equals(path, "/", StringComparison.OrdinalIgnoreCase) ||
string.Equals(path, "/index.html", StringComparison.OrdinalIgnoreCase))
{
var tokens = antiforgery.GetAndStoreTokens(context);
context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken,
new CookieOptions() { HttpOnly = false });
}
return next(context);
});
}
public void ConfigureServices(IServiceCollection services)
{
services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
}
Примечание.
Если антифальсификационный маркер указан как в заголовке запроса, так и в полезных данных формы, проверяется только маркер в заголовке.
файлы cookie аутентификации Windows и защиты от подделки
При использовании проверки подлинности Windows конечные точки приложений должны быть защищены от атак CSRF так же, как и для файлов cookie. Браузер неявно отправляет контекст проверки подлинности серверу и поэтому конечные точки должны быть защищены от атак CSRF.
Расширить защиту от подделок
Тип IAntiforgeryAdditionalDataProvider позволяет разработчикам расширить поведение системы защиты от CSRF путем обхода дополнительных данных в каждом токене. Метод GetAdditionalData вызывается каждый раз при создании маркера поля, а возвращаемое значение внедрено в созданный маркер. Реализующий может возвращать метку времени, nonce или любое другое значение, а затем вызывать ValidateAdditionalData для проверки этих данных при проверке этого токена. Имя пользователя клиента уже внедрено в созданные маркеры, поэтому не нужно включать эти сведения. Если в маркере содержатся дополнительные данные, но IAntiForgeryAdditionalDataProvider не настроен, то дополнительные данные не проверяются.
Дополнительные ресурсы
ASP.NET Core