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

Межсайтовая подделка запроса (CSRF) — это атака, при которой вредоносный сайт отправляет запрос на уязвимый сайт, на котором пользователь в данный момент авторизован.

Ниже приведен пример атаки CSRF:

  1. Пользователь входит в www.example.com систему с помощью проверки подлинности форм.

  2. Сервер выполняет проверку подлинности пользователя. Ответ с сервера включает файл cookie проверки подлинности.

  3. Без выхода из системы пользователь посещает вредоносный веб-сайт. Этот вредоносный сайт содержит следующую HTML-форму:

    <h1>You Are a Winner!</h1>
      <form action="http://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 Me"/>
    </form>
    

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

  4. Пользователь нажимает кнопку "Отправить". Браузер включает файл cookie проверки подлинности с запросом.

  5. Запрос выполняется на сервере с контекстом проверки подлинности пользователя и может делать все, что разрешено пользователю, прошедшему проверку подлинности.

Хотя в этом примере пользователю требуется щелкнуть кнопку формы, вредоносные страницы могут так же легко запустить скрипт, который отправляет форму автоматически. Кроме того, использование SSL не предотвращает атаку CSRF, так как вредоносный сайт может отправить запрос https://.

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

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

Чтобы предотвратить атаки CSRF, ASP.NET MVC использует маркеры защиты от подделки, также называемые маркерами проверки запросов.

  1. Клиент запрашивает HTML-страницу, содержащую форму.
  2. Сервер включает два токена в ответе. Один маркер отправляется в виде файла cookie. Другой помещается в скрытое поле формы. Маркеры создаются случайным образом, чтобы злоумышленник не угадал значения.
  3. Когда клиент отправляет форму, он должен отправить оба маркера обратно на сервер. Клиент отправляет куки-токен в виде cookie и отправляет токен формы внутри данных формы. (Клиент браузера автоматически делает это, когда пользователь отправляет форму.)
  4. Если запрос не содержит оба маркера, сервер запрещает запрос.

Ниже приведен пример HTML-формы со скрытым маркером формы:

<form action="/Home/Test" method="post">
    <input name="__RequestVerificationToken" type="hidden"   
           value="6fGBtLZmVBZ59oUad1Fr33BuPxANKY9q3Srr5y[...]" />    
    <input type="submit" value="Submit" />
</form>

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

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

Необходимо требовать маркеры защиты от подделки для любых незащищенных методов (POST, PUT, DELETE). Кроме того, убедитесь, что безопасные методы (GET, HEAD) не имеют побочных эффектов. Кроме того, если вы включите поддержку между доменами, например CORS или JSONP, то даже безопасные методы, такие как GET, потенциально уязвимы для атак CSRF, что позволяет злоумышленнику читать потенциально конфиденциальные данные.

Маркеры защиты от подделки в ASP.NET MVC

Чтобы добавить маркеры защиты от подделки на страницу Razor, используйте вспомогательный метод HtmlHelper.AntiForgeryToken :

@using (Html.BeginForm("Manage", "Account")) {
    @Html.AntiForgeryToken()
}

Этот метод добавляет скрытое поле формы и задает маркер cookie.

Защита от CSRF и AJAX

Маркер формы может быть проблемой для запросов AJAX, так как запрос AJAX может отправлять данные JSON, а не ДАННЫЕ ФОРМЫ HTML. Одним из решений является отправка маркеров в пользовательском заголовке HTTP. Следующий код использует синтаксис Razor для создания маркеров, а затем добавляет маркеры в запрос AJAX. Токены создаются на сервере с помощью вызова AntiForgery.GetTokens.

<script>
    @functions{
        public string TokenHeaderValue()
        {
            string cookieToken, formToken;
            AntiForgery.GetTokens(null, out cookieToken, out formToken);
            return cookieToken + ":" + formToken;                
        }
    }

    $.ajax("api/values", {
        type: "post",
        contentType: "application/json",
        data: {  }, // JSON data goes here
        dataType: "json",
        headers: {
            'RequestVerificationToken': '@TokenHeaderValue()'
        }
    });
</script>

При обработке запроса извлеките маркеры из заголовка запроса. Затем вызовите метод AntiForgery.Validate , чтобы проверить маркеры. Метод Validate вызывает исключение, если маркеры недопустимы.

void ValidateRequestHeader(HttpRequestMessage request)
{
    string cookieToken = "";
    string formToken = "";

    IEnumerable<string> tokenHeaders;
    if (request.Headers.TryGetValues("RequestVerificationToken", out tokenHeaders))
    {
        string[] tokens = tokenHeaders.First().Split(':');
        if (tokens.Length == 2)
        {
            cookieToken = tokens[0].Trim();
            formToken = tokens[1].Trim();
        }
    }
    AntiForgery.Validate(cookieToken, formToken);
}