Skip to content
This repository has been archived by the owner on Dec 14, 2018. It is now read-only.

[IgnoreAntiForgeryToken] Not working in Razor Pages #7795

Closed
ericwj opened this issue May 19, 2018 · 11 comments
Closed

[IgnoreAntiForgeryToken] Not working in Razor Pages #7795

ericwj opened this issue May 19, 2018 · 11 comments
Assignees
Labels
3 - Done breaking-change cost: S Will take up to 2 days to complete enhancement PRI: 2 - Preferred Preferably should be handled during the milestone.

Comments

@ericwj
Copy link

ericwj commented May 19, 2018

Is this a Bug or Feature request?:

Bug

Steps to reproduce (preferrably a link to a GitHub repo with a repro project):

See below

Description of the problem:

Adding [IgnoreAntiForgeryToken] in a controller works as expected, however, adding it to a Razor Pages method has no effect.

Version of Microsoft.AspNetCore.Mvc or Microsoft.AspNetCore.App or Microsoft.AspNetCore.All:

2.1.0-rc1-final

Test Script

$Body = "message=PowerShell" 
$Uri = "https://localhost:44387/Test"
(curl -UseBasicParsing -Uri $Uri -Body $Body -Method Post -ContentType "application/x-www-form-urlencoded").RawContent
$Uri = "https://localhost:44387/Contact"
(curl -UseBasicParsing -Uri $Uri -Body $Body -Method Post -ContentType "application/x-www-form-urlencoded").RawContent

Output

HTTP/1.1 200 OK
Pragma: no-cache
Transfer-Encoding: chunked
X-Frame-Options: SAMEORIGIN
X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcRXJpY1xTb3VyY2VcSXNzdWVzXElnbm9yZUFudGlGb3JnZXJ5VG9rZW5cVGVzdA==?=
Cache-Control: no-cache, no-store
Content-Type: text/html; charset=utf-8
Date: Sat, 19 May 2018 17:30:19 GMT
Set-Cookie: .AspNetCore.Antiforgery.oPQX9jHeIUM=CfDJ8Mtg_UjBP8dLpGAth2hE68d-IyvTEhGzHEtPh5gqWZyTAPQh1Q8Qe0L70AZE3ZBRurb7YCUuc_xEYjiNmCP12o6uVVZBVSMYacekaSn3BrlaCF7nwg4Ci7l736g3GrON7oJEgv7aiQmadaI4KmF7W
5I; path=/; samesite=strict; httponly
Server: Kestrel
X-Powered-By: ASP.NET


<h2>PowerShell</h2>

<form method="post">
    <input type="text" id="Message" name="Message" value="PowerShell" />
    <input type="submit" value="OK"/>
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8Mtg_UjBP8dLpGAth2hE68cI5gq5FINEiYp098QnwwxvNGW9QT3-PsHlwEiVC1L_D1dWzfISgD1HSv3Qz-2uNfbvdMrcw_dcwDgYBnOpT6NVFhExpUd-3Rbb2WjEYHz8X4F1i2f
4XluCTCnW7h7vPWw" /></form>
curl : The remote server returned an error: (400) Bad Request.
At line:6 char:2
+ (curl -UseBasicParsing -Uri $Uri -Body $Body -Method Post -ContentTyp ...
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand
@ericwj
Copy link
Author

ericwj commented May 19, 2018

Dups #5863 but this keeps popping up, #6306, and I found more old issues and I followed the steps to work around it and expected it to be fixed (#5552) but now I read Order = 1000 isn't good enough but 1001 will fix it? Shouldn't this just work without having to fiddle with magic numbers?

Since this is a known issue I will not share my repro.

@mkArtakMSFT
Copy link
Member

Thanks for contacting us, @ericwj.
@dougbu, can you please look into this? We may be missing a test for this scenario. If so, we should make sure we add some to avoid this issue going forward.

@mkArtakMSFT
Copy link
Member

/cc @rynowak

@rynowak
Copy link
Member

rynowak commented May 20, 2018

Did you try putting the filter attribute on the class? This is one of the things that's confusing about pages and we have plans to add an analyzer.

@ericwj
Copy link
Author

ericwj commented May 21, 2018

Heck that works. But why is that necessary? Wouldn't it be better to

  1. not require Order = and
  2. go with the intuition that it works if it is slapped on a handler?

That saves writing the analyzer, too.

It still fails if applied to the class without Order = 2000.

I feel Razor pages is a bit rigid in more places, such as only understanding conventions for handler names for example. I like to name methods so I can use nameof to create links...

@pranavkm
Copy link
Contributor

There's a couple of interaction issues here that sort of culminate in this behavior

  • Both AutoValidateAntiforgeryTokenAttribute and IgnoreAntiforgeryTokenAttribute have the same filter order of 1000. If they are applied at the same scope, then their resulting order is undefined. The current implementation is basically to preserve the order in which they appear in the list.
  • AutoValidateAntiforgeryPageApplicationModelProvider appends AutoValidateAntiforgeryTokenAttribute to the filter list. Consequently, it's always ends up later in the list compared to a filter that's defined on a page model.
  • ValidateAntiforgeryTokenAuthorizationFilter picks the filter furthest away in the list of filters. If you don't mess around with the filter order, the auto one ends up being it.

The behavior is non-intuitive and it's not entirely obvious why a higher filter order should cause things to work. A couple of possible solutions to consider:

  • We continue relying on Order to work for us and change the value for IgnoreAntiforgeryTokenAttribute to 1001. Kinda hard to put this behind a compat flag.
  • Have the AutoValidateAntiforgeryPageApplicationModelProvider not insert the filter if it sees IgnoreAntiforgeryTokenAttribute has already been applied to the model. Should be easy to hide this behind a compat-switch.
  • Change the implementation of ValidateAntiforgeryTokenAuthorizationFilter to no-op if it sees any IgnoreAntiforgeryTokenAttribute. Essentially how IAllowAnonymousFilter works. Should be easy to hide this behind a compat flag. Kinda like this the best since the two concepts seem pretty analogous.
  • Do nothing and recommend setting an order. You really shouldn't be turning off anti-forgery :trollface:

@dougbu
Copy link
Member

dougbu commented May 31, 2018

Change the implementation of ValidateAntiforgeryTokenAuthorizationFilter to no-op if it sees any IgnoreAntiforgeryTokenAttribute.

👍

@pranavkm pranavkm removed this from the Discussions milestone May 31, 2018
@ericwj
Copy link
Author

ericwj commented May 31, 2018

You really shouldn't be turning off anti-forgery

We are not stupid - most of us, I only speak for myself - so there should be a way to make AntiForgery just go away. There is also this nice feature called authorization which can help. Or alternatively a way to have a blank class and no HttpContext or ActionContext or whatever and just get a token.

Just like I would like to point some factory at my web app without any context and get an IUrlHelper which knows about the pages etc. But alas there is this decision...

@mkArtakMSFT
Copy link
Member

The following suggestion is most appealing:

Change the implementation of ValidateAntiforgeryTokenAuthorizationFilter to no-op if it sees any IgnoreAntiforgeryTokenAttribute. Essentially how IAllowAnonymousFilter works. Should be easy to

@pranavkm
Copy link
Contributor

Change the implementation of ValidateAntiforgeryTokenAuthorizationFilter to no-op if it sees any IgnoreAntiforgeryTokenAttribute. Essentially how IAllowAnonymousFilter works.

This is a no-go. We specifically rely on ordering to ensure that IgnoreAntiforgeryTokenAttribute can be overloaded. See ca6c76c. I'm going with option B, which is pretty simple. @rynowak considers this a bug and consequently does not require a compat flag.

@pranavkm
Copy link
Contributor

For 2.2.0, we'll honour IgnoreAntiforgeryTokenAttribute applied to a Razor Page model without the need to specify an order. They will not be supported per handler method but we should start producing build warnings if you attempt to do so (See #7684).

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
3 - Done breaking-change cost: S Will take up to 2 days to complete enhancement PRI: 2 - Preferred Preferably should be handled during the milestone.
Projects
None yet
Development

No branches or pull requests

5 participants