Должен ли каждый вызов API иметь уникальный токен AddAntiForgery? - PullRequest
0 голосов
/ 13 июня 2018

Я знаю, что использование вызова Html.AddAntiForgeryToken в FORM будет работать.Но для случаев, когда Формы не существует, где / как должен быть получен токен противодействия?

И должен ли каждый токен быть уникальным?Или веб-приложение может использовать один и тот же токен защиты от подделки на протяжении всего сеанса?

1 Ответ

0 голосов
/ 13 июня 2018

Значение AntiForgeryToken относится скорее к странице, чем к form.Если вы разместите несколько форм (конечно, не вложенных !!!) на одной странице с @Html.AntiForgeryToken(), тогда все значения будут одинаковыми.Когда страница перезагружается (после GET или POST), значение изменяется.
Внутренне веб-сервер устанавливает HttpOnly Cookie (имя определено в AntiForgeryConfig классе) и сравнивает полученное значение с этим cookie.значение.
Что если вы сделаете вызов API (AJAX) с этой страницы?Конечно, вы можете сделать столько звонков, сколько пожелаете.
Что делать, если на странице нет form?Вам нужно добавить фальшивку form.Примерно так.

@{
    var attr = new Dictionary<string, object>();
    attr.Add("id", "anti-forgery"); //sic!
}
@using (Html.BeginForm("", "fake-form", FormMethod.Post, attr))
{
    @Html.AntiForgeryToken()
}

А затем настройте все ваши AJAX-вызовы сразу.

<script>
    'use strict';
    $(document).ready(function () {
        $.ajaxSetup({
            dataType: 'json',
            method: 'POST',
            contentType: 'application/json',
            headers: antiForgery({}) //put antiforgerytoken into ajax request header
        });
        function antiForgery(data) {
            data.__RequestVerificationToken = $('#anti-forgery input[name=__RequestVerificationToken]').val();
            return data;
        }

    });

</script>

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

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class ValidateJsonAntiForgeryTokenAttribute : FilterAttribute, IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationContext filterContext)
    {
        if (filterContext == null)
        {
            throw new ArgumentNullException("filterContext");
        }

        var httpContext = filterContext.HttpContext;
        var cookie = httpContext.Request.Cookies[AntiForgeryConfig.CookieName];
        AntiForgery.Validate(cookie != null ? cookie.Value : null, httpContext.Request.Headers["__RequestVerificationToken"]);
    }
}

И теперь вы только украшаете свои методы контроллера этим атрибутом.

[HttpPost]
[ValidateJsonAntiForgeryToken] //this one
public async Task<JsonResult> ProcessRq(MyModel model)
{
    //do work
}

Если вы создаете службу чистого API (RESTfull), то естьпохожий подход.Сначала клиентское приложение должно запросить и получить какой-нибудь токен аутентификации и добавить его ко всем следующим запросам (во время сеанса).

...