Предотвращение атак с подделкой межсайтовых запросов (XSRF/CSRF) в ASP.NET Core

Фийаз Хасан, Рик Андерсон (и Стив Смит

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

Пример атаки CSRF:

  1. Пользователь входит в систему www.good-banking-site.com с использованием проверки подлинности с помощью форм. Сервер проверяет подлинность пользователя и выдает ответ, который включает проверку подлинности cookie . Сайт уязвим к атакам, так как он доверяет любому запросу, который он получает с действительной проверкой подлинности cookie .

  2. Пользователь посещает вредоносный веб-узел www.bad-crook-site.com .

    Вредоносный веб-узел www.bad-crook-site.com содержит HTML-форму, аналогичную следующей:

    <h1>Congratulations! You're a Winner!</h1>
    <form action="http://good-banking-site.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, связанная с "межсайт".

  3. Пользователь нажимает кнопку Submit (отправить). Браузер выполняет запрос и автоматически включает проверку подлинности cookie для запрошенного домена www.good-banking-site.com .

  4. Запрос выполняется на www.good-banking-site.com сервере с контекстом проверки подлинности пользователя и может выполнять любое действие, которое прошедший проверку подлинности пользователь разрешает.

В дополнение к сценарию, в котором пользователь нажимает кнопку для отправки формы, вредоносный сайт может:

  • Запуск скрипта, который автоматически отправляет форму.
  • Отправка отправки формы в виде запроса AJAX.
  • Скрытие формы с помощью CSS.

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

Использование протокола HTTPS не мешает CSRF атаке. Вредоносный сайт может отправить https://www.good-banking-site.com/ запрос так же просто, как он может отправить небезопасный запрос.

Некоторые атаки направлены на конечные точки, отвечающие на запросы GET. в этом случае для выполнения действия можно использовать тег Image. Такая форма атаки является распространенной на сайтах форумов, которые допускают образы, но блокируют JavaScript. Приложения, изменяющие состояние запросов GET, которые изменяются при изменении переменных или ресурсов, уязвимы для атак злоумышленников. Запросы на получение, которые изменили состояние, являются небезопасными. Рекомендуется никогда не изменять состояние запроса GET.

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

  • Браузеры хранят cookie s, выданные веб-приложением.
  • Хранимые cookie s включают сеансы cookie s для пользователей, прошедших проверку подлинности.
  • Браузеры отправляют все объекты, cookie связанные с доменом, в веб-приложение каждый запрос, независимо от того, как запрос к приложению был создан в браузере.

Однако атаки CSRF не ограничиваются использованием эксплойтов cookie s. Например, также уязвимы обычная и краткая проверка подлинности. После того как пользователь войдет в систему с обычной или дайджест-проверкой подлинности, браузер автоматически отправляет учетные данные, пока сеанс не † завершится.

†В этом контексте сеанс относится к сеансу на стороне клиента, в течение которого пользователь прошел проверку подлинности. он не связан с сеансами на стороне сервера или по промежуточного слоя сеанса ASP.NET Core.

Пользователи могут защищаться от CSRF уязвимостей, предпринимая меры предосторожности.

  • Выйдите из веб-приложений по завершении их использования.
  • Периодически очищать браузер cookie .

Однако уязвимости CSRF являются фундаментальной проблемой с веб-приложением, а не конечным пользователем.

Основы проверки подлинности

CookieАутентификация на основе — это популярная форма проверки подлинности. Системы проверки подлинности на основе маркеров растут по популярности, особенно для одностраничных приложений (одностраничные приложения).

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

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

Когда пользователь проходит проверку подлинности, ему выдается маркер (а не маркер подделки). Маркер содержит сведения о пользователе в виде утверждений или маркер ссылки, который указывает приложению на обслуживание пользовательского состояния в приложении. Когда пользователь пытается получить доступ к ресурсу, который требует проверки подлинности, маркер отправляется в приложение с дополнительным заголовком авторизации в виде токена носителя. Это делает приложение без отслеживания состояния. В каждом последующем запросе маркер передается в запросе на проверку на стороне сервера. Этот токен не зашифрован; Он кодируется. На сервере маркер декодирован для доступа к его данным. Чтобы отправить маркер при последующих запросах, сохраните маркер в локальном хранилище браузера. Не стоит беспокоиться об уязвимости CSRF, если маркер хранится в локальном хранилище браузера. CSRF является проблемой, когда маркер хранится в cookie . дополнительные сведения см. в примере кода GitHub issue SPA добавляется две cookie s.

Несколько приложений, размещенных в одном домене

Общие среды размещения уязвимы для перехвата сеансов, входа CSRF и других атак.

Хотя example1.contoso.net и example2.contoso.net являются разными узлами, между узлами в домене есть неявные отношения доверия *.contoso.net . Это неявное отношение доверия позволяет потенциально недоверенным узлам повлиять на друг друга cookie (политики того же источника, управляющие запросами AJAX, не обязательно применяются к HTTP cookie s).

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

настройка защиты от подделки ASP.NET Core

Предупреждение

ASP.NET Core реализует подделку с помощью ASP.NET Core защиты данных. Стек защиты данных должен быть настроен для работы в ферме серверов. Дополнительные сведения см. в разделе Настройка защиты данных .

По промежуточного слоя для подделки добавляется в контейнер внедрения зависимостей при вызове одного из следующих интерфейсов API в Startup.ConfigureServices .

По промежуточного слоя для подделки добавляется в контейнер внедрения зависимостей при AddMvc вызове в Startup.ConfigureServices

в ASP.NET Core 2,0 или более поздней версии формтагхелпер вставляет маркеры для защиты от подделки в элементы HTML-форм. Следующая разметка в Razor файле автоматически создает маркеры для защиты от подделки:

<form method="post">
    ...
</form>

Аналогичным образом ихтмлхелпер. бегинформ по умолчанию создает маркеры подделки, если метод формы не получает значение.

Автоматическое создание маркеров защиты от подделки для HTML-элементов форм происходит, когда <form> тег содержит method="post" атрибут и выполняется одно из следующих условий.

  • Атрибут action пуст ( action="" ).
  • Атрибут Action не указан ( <form method="post"> ).

Автоматическое создание маркеров подделки для элементов HTML-форм можно отключить:

  • Явно отключите токены защиты от подделки с помощью asp-antiforgery атрибута:

    <form method="post" asp-antiforgery="false">
        ...
    </form>
    
  • Элемент form не участвует в вспомогательных функциях тегов с помощью символа Helper! символ согласия:

    <!form method="post">
        ...
    </!form>
    
  • Удалите FormTagHelper из представления. FormTagHelperМожно удалить из представления, добавив следующую директиву в Razor представление:

    @removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
    

Примечание

Razor Страницы автоматически защищаются от XSRF или CSRF. Дополнительные сведения см. в разделе XSRF/CSRF and Razor pages.

Наиболее распространенным подходом к защите от атак CSRF является использование шаблона токена синхронизатора (STP). STP используется, когда пользователь запрашивает страницу с данными формы:

  1. Сервер отправляет клиенту маркер, связанный с удостоверением текущего пользователя.
  2. Клиент отправляет на сервер токен, чтобы выполнить проверку.
  3. Если сервер получает маркер, который не соответствует удостоверению аутентифицированного пользователя, запрос отклоняется.

Маркер является уникальным и непредсказуемым. Маркер также можно использовать для обеспечения надлежащей последовательности последовательности запросов (например, для обеспечения последовательности запроса: страница 1 > стр. 2 > стр. 3). все формы в ASP.NET Core шаблонах MVC и Razor страниц создают маркеры защиты от подделки. В следующей паре примеров представления создаются маркеры защиты от подделки:

<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 включает три фильтра для работы с маркерами подделки:

Параметры защиты от подделки

Настройка параметров защиты от подделки в Startup.ConfigureServices :

services.AddAntiforgery(options => 
{
    // Set Cookie properties using CookieBuilder properties†.
    options.FormFieldName = "AntiforgeryFieldname";
    options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
    options.SuppressXFrameOptionsHeader = false;
});

†Задайте свойства защиты от подделки Cookie с помощью свойств класса Cookie Builder .

Параметр Описание
Cookie Определяет параметры, используемые для создания защиты от подделки cookie .
формфиелднаме Имя скрытого поля формы, используемое системой защиты от подделки для отображения маркеров подделки в представлениях.
хеадернаме Имя заголовка, используемого системой защиты от подделки. Если null значение равно, система рассматривает только данные формы.
суппрессксфрамеоптионшеадер Указывает, следует ли подавлять создание X-Frame-Options заголовка. По умолчанию заголовок создается со значением «САМЕОРИГИН». По умолчанию — false.
services.AddAntiforgery(options => 
{
    options.CookieDomain = "contoso.com";
    options.CookieName = "X-CSRF-TOKEN-COOKIENAME";
    options.CookiePath = "Path";
    options.FormFieldName = "AntiforgeryFieldname";
    options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
    options.RequireSsl = false;
    options.SuppressXFrameOptionsHeader = false;
});
Параметр Описание
Cookie Определяет параметры, используемые для создания защиты от подделки cookie .
CookieДомен Домен cookie . По умолчанию — null. Это свойство устарело и будет удалено в следующей версии. Взамен рекомендуется использовать Cookie . Поддомен.
Cookiename Имя cookie. Если значение не задано, система создает уникальное имя, начинающееся с Cookie префикса по умолчанию (". AspNetCore. подделка. "). Это свойство устарело и будет удалено в следующей версии. Взамен рекомендуется использовать Cookie . Безымян.
CookiePath Путь, заданный для cookie . Это свойство устарело и будет удалено в следующей версии. Взамен рекомендуется использовать Cookie . Путь.
формфиелднаме Имя скрытого поля формы, используемое системой защиты от подделки для отображения маркеров подделки в представлениях.
хеадернаме Имя заголовка, используемого системой защиты от подделки. Если null значение равно, система рассматривает только данные формы.
RequireSsl Указывает, требуется ли протокол HTTPS в системе защиты от подделки. Если значение равно true , то запросы, не относящиеся к HTTPS, завершаются ошибкой. По умолчанию — false. Это свойство устарело и будет удалено в следующей версии. Рекомендуемая альтернатива — задать Cookie . Секуреполици.
суппрессксфрамеоптионшеадер Указывает, следует ли подавлять создание X-Frame-Options заголовка. По умолчанию заголовок создается со значением «САМЕОРИГИН». По умолчанию — false.

Дополнительные сведения см. в разделе Cookie AuthenticationOptions.

Настройка функций защиты от подделки с помощью Иантифоржери

Иантифоржери предоставляет API для настройки функций защиты от подделки. IAntiforgery может быть запрошен в Configure методе Startup класса. в следующем примере по промежуточного слоя с домашней страницы приложения используется для создания токена подделки и его отправки в ответе в виде cookie (с использованием соглашения об именовании по умолчанию Angular, описанного далее в этом разделе):

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))
        {
            // The request token can be sent as a JavaScript-readable cookie, 
            // and Angular uses it by default.
            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 не поддерживает добавление маркеров подделки для автоматического получения запросов.

Автоматически проверять маркеры подделки для ненадежных методов HTTP

ASP.NET Core приложения не создают маркеры для защиты от подделки для безопасного метода HTTP (получение, HEAD, параметры и трассировка). Вместо широкого применения ValidateAntiForgeryToken атрибута и последующего его переопределения с атрибутами IgnoreAntiforgeryToken можно использовать атрибут аутовалидатеантифоржеритокен . Этот атрибут работает идентично с ValidateAntiForgeryToken атрибутом, за исключением того, что для запросов, выполняемых с помощью следующих методов HTTP, не требуются маркеры:

  • GET
  • HEAD
  • OPTIONS
  • TRACE

Мы рекомендуем использовать AutoValidateAntiforgeryToken широкие возможности для сценариев, не относящихся к API. Это гарантирует, что действия POST по умолчанию защищаются. Альтернативой является игнорирование маркеров подделки по умолчанию, если только ValidateAntiForgeryToken не применяется к отдельным методам действий. Более вероятно, что в этом случае метод действия POST остается незащищенным по ошибке, что оставляет приложение уязвимым для атак CSRF. Все записи должны отправить токен защиты от подделки.

Интерфейсы API не имеют автоматического механизма для отправки маркера, не являющегося cookie частью. Реализация, вероятно, зависит от реализации клиентского кода. Ниже приведены некоторые примеры.

Пример уровня класса:

[Authorize]
[AutoValidateAntiforgeryToken]
public class ManageController : Controller
{

Глобальный пример:

Обслуживание. AddMvc (Options = Параметры>. Filters. Add (New Аутовалидатеантифоржеритокенаттрибуте ()));

services.AddControllersWithViews(options =>
    options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute()));

Переопределение атрибутов или подделки глобальных или контроллеров

Фильтр игнореантифоржеритокен используется для устранения необходимости в токене подделки для данного действия (или контроллера). При применении этот фильтр переопределяет ValidateAntiForgeryToken и AutoValidateAntiforgeryToken фильтрует фильтры, указанные на более высоком уровне (глобально или на контроллере).

[Authorize]
[AutoValidateAntiforgeryToken]
public class ManageController : Controller
{
    [HttpPost]
    [IgnoreAntiforgeryToken]
    public async Task<IActionResult> DoSomethingSafe(SomeViewModel model)
    {
        // no antiforgery token required
    }
}

Обновить маркеры после проверки подлинности

Токены следует обновлять после проверки подлинности пользователя путем перенаправления пользователя на страницу представления или страницы Razor .

JavaScript, AJAX и одностраничные приложения

В традиционных приложениях на основе HTML маркеры защиты от подделки передаются на сервер с помощью скрытых полей формы. В современных приложениях на основе JavaScript и одностраничные приложения многие запросы выполняются программным образом. Эти запросы AJAX могут использовать другие методы (например, заголовки запросов или cookie s) для отправки маркера.

Если cookie s используется для хранения маркеров проверки подлинности и для проверки подлинности запросов API на сервере, CSRF является потенциальной проблемой. Если для хранения маркера используется локальное хранилище, уязвимость CSRF может быть устранена, так как значения из локального хранилища не отправляются на сервер автоматически при каждом запросе. Поэтому рекомендуемым подходом является использование локального хранилища для хранения токена защиты от подделки на клиенте и отправка маркера в качестве заголовка запроса.

JavaScript

Используя JavaScript с представлениями, маркер можно создать с помощью службы в представлении. Вставьте службу Microsoft. AspNetCore. подделка. иантифоржери в представление и вызовите жетандсторетокенс:

@{
    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 сервером или считывания их из клиента.

В предыдущем примере для чтения значения скрытого поля заголовка AJAX POST используется JavaScript.

JavaScript также может получить доступ к маркерам в cookie s и использовать 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 , то $http Служба AngularJS добавляет cookie значение в заголовок при отправке запроса на сервер. Этот процесс выполняется автоматически. Заголовок не обязательно задавать в клиенте явным образом. Имя заголовка — X-XSRF-TOKEN . Сервер должен обнаружить этот заголовок и проверить его содержимое.

для ASP.NET Core API для работы с этим соглашением при запуске приложения:

  • Настройте приложение, чтобы предоставить маркер в cookie вызываемом XSRF-TOKEN .
  • Настройте службу защиты от подделки для поиска заголовка с именем X-XSRF-TOKEN .
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))
        {
            // The request token can be sent as a JavaScript-readable cookie, 
            // and Angular uses it by default.
            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)
{
    // Angular's default header name for sending the XSRF token.
    services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
}

Просмотреть или скачать образец кода (как скачивать)

Windows проверки подлинности и подделки cookie s

при использовании Windows проверки подлинности конечные точки приложения должны быть защищены от атак CSRF так же, как и для cookie s. Браузер неявно отправляет контекст проверки подлинности на сервер, поэтому конечные точки должны быть защищены от атак CSRF.

Расширение защиты от подделки

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

Дополнительные ресурсы