Исключение против подделки (предоставлен токен подделки, предназначенный для другого пользователя на основе утверждений) при использовании метода post, когда пользователь проходит проверку подлинности - PullRequest
0 голосов
/ 16 февраля 2020

Я использую ASP. NET Core 2.2 с AspNetCore.Authentication .

Я пытаюсь использовать Post вызов в моем cshtml Форма компонента представления _Layout:

<form asp-controller="Home" asp-action="SearchResults" method="post" enctype="multipart/form-data" asp-antiforgery="true" novalidate>

(...)

</form>

Мое намерение состоит в том, чтобы замаскировать URL-адрес с помощью свойств поиска, чтобы усложнить сканирование и удаление в Интернете. Мой метод Post обновляет поля stati c моего контроллера и перенаправляет на мой метод Index Get, где отображаются результаты поиска:

    private static SearchViewModel _searchModel;
    private static string _sortOrder;
    private static int? _pageNumber;

(...)

[HttpPost]
        [AllowAnonymous]
        public IActionResult SearchResults(SearchViewModel searchModel, string sortOrder, int? pageNumber = 1)
        {
            _searchModel = searchModel;
            _sortOrder = sortOrder;
            _pageNumber = pageNumber;

            return RedirectToAction(nameof(Index));
        }

И Get подпись метода:

[HttpGet]
        [AllowAnonymous]
        public async Task<IActionResult> Index()
{
    //refering to updated fields
}

Идея, вдохновленная этим SO-ответом .

И настройка идентичности / аутентификации Setup.cs:

public void ConfigureServices(IServiceCollection services)
        {
             services.AddIdentity<AppUser, IdentityRole>(opts => {
                opts.User.RequireUniqueEmail = true;
                opts.User.AllowedUserNameCharacters = null; //disable validation
                opts.Password.RequiredLength = 8;
                opts.Password.RequireNonAlphanumeric = false;
                opts.Password.RequireLowercase = false;
                opts.Password.RequireUppercase = false;
                opts.Password.RequireDigit = true;
            })
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();
            services.AddAntiforgery(x => x.HeaderName = "X-CSRF-TOKEN");
            .Services.ConfigureApplicationCookie(options =>
            {
                //previous cookies not valid
                options.SlidingExpiration = true;
                options.ExpireTimeSpan = TimeSpan.FromDays(1);
            });
            services.AddMvc(options =>
            {
                options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
                options.Filters.Add<AuditUserActionFilter>();
            });

            (...)
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env, IAntiforgery antiforgery)
        {
            (...)

            app.Use(next => context =>
            {
                if (context.Request.Path == "/")
                {
                    var tokens = antiforgery.GetAndStoreTokens(context);
                    context.Response.Cookies.Append("CSRF-TOKEN", tokens.RequestToken, new CookieOptions { HttpOnly = false });
                }
                return next(context);
            });
            app.UseAuthentication();
        }
    }

Я верю, что это ключ: На самом деле, когда я отправляю форму Post в качестве гостя (не аутентифицирована), все работает нормально. Но после входа в систему при отправке формы я получаю исключение:

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

Также см. Ниже мою аутентификацию пользователя процесс:

if (user != null)
                {
                    await _signInManager.SignOutAsync();

                    var result = await _signInManager.PasswordSignInAsync(user, details.Password, false, false);

                    if (result.Succeeded)
                    {
                        if (!string.IsNullOrEmpty(returnUrl) && Url.IsLocalUrl(returnUrl))
                            return Redirect(returnUrl);
                        else
                            return RedirectToAction(nameof(Account));
                    }
                    else if (result.IsLockedOut || result.IsNotAllowed)
                    {
                        ViewBag.Message = "You are not allowed to sign in.";
                        return View("Error");
                    }
                    else
                    {
                        ModelState.AddModelError(nameof(UserLoginViewModel.Password), "Incorrect password.");
                        return View("Index");
                    }
                }

Я пробовал несколько подходов: здесь и здесь безрезультатно. Но они для более старых версий ASP. NET Core. Я не уверен, как я должен обновить свои токены защиты от подделки для аутентифицированного пользователя?

Возможные причины моей проблемы: 1) неправильное понимание Post -> Get form call. 2) не понимает, как куки-файлы аутентификации работают в ASP. NET Core аутентификации. 3) неправильное понимание процесса аутентификации в целом.

PS Когда я удаляю

options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());

из:

services.AddMvc(options =>
            {
                options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
                options.Filters.Add<AuditUserActionFilter>();
            });

Я могу сделать Post звонок. Но я верю, что это не удивительно.

РЕДАКТИРОВАТЬ: По какой-то причине, когда я отправляю форму из другого представления (форма находится в компоненте представления _Layout), чем Home / Index ( там, где я отображаю результаты поиска), исключений для защиты от подделки нет.

Это потому, что действие HomeController Index равно Get? После добавления атрибута Post / Get:

[AllowAnonymous]
        [HttpGet, HttpPost]
        public async Task<IActionResult> Index()

у меня такое же исключение, как и раньше. После добавления:

[AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Index()

Я вообще не могу загрузить представление, потому что оно запрашивает токен.

Как его обойти?

1 Ответ

0 голосов
/ 25 февраля 2020

После itminus совета я понял, что мой Configure метод мой app.UseAuthentication(); должен двигаться вверх. Кроме того, после прочтения документации я понял, что после использования Add Mvc мне больше не нужен код, ссылающийся на "CSRF-TOKEN".

В конце моего запуска .cs выглядит так:

public void ConfigureServices(IServiceCollection services)
        {
             services.AddIdentity<AppUser, IdentityRole>(opts => {
                opts.User.RequireUniqueEmail = true;
                opts.User.AllowedUserNameCharacters = null; //disable validation
                opts.Password.RequiredLength = 8;
                opts.Password.RequireNonAlphanumeric = false;
                opts.Password.RequireLowercase = false;
                opts.Password.RequireUppercase = false;
                opts.Password.RequireDigit = true;
            })
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();
            .Services.ConfigureApplicationCookie(options =>
            {
                //previous cookies not valid
                options.SlidingExpiration = true;
                options.ExpireTimeSpan = TimeSpan.FromDays(1);
            });
            services.AddMvc(options =>
            {
                options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
                options.Filters.Add<AuditUserActionFilter>();
            });

            (...)
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env, IAntiforgery antiforgery)
        {
            app.UseAuthentication();

            (...)
        }
    }
...