Skip to content

The antiforgery token could not be decrypted - Only for specific user #47185

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
1 task done
weirdyang opened this issue Mar 14, 2023 · 45 comments
Open
1 task done

The antiforgery token could not be decrypted - Only for specific user #47185

weirdyang opened this issue Mar 14, 2023 · 45 comments
Labels
area-dataprotection Includes: DataProtection

Comments

@weirdyang
Copy link

weirdyang commented Mar 14, 2023

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

An exception was thrown while deserializing the token.
Microsoft.AspNetCore.Antiforgery.AntiforgeryValidationException: The antiforgery token could not be decrypted.
---> System.Security.Cryptography.CryptographicException: The key {669d513e-a172-4851-b160-04b523abbc1e} was not found in the key ring.
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.UnprotectCore(Byte[] protectedData, Boolean allowOperationsOnRevokedKeys, UnprotectStatus& status)
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.DangerousUnprotect(Byte[] protectedData, Boolean ignoreRevocationErrors, Boolean& requiresMigration, Boolean& wasRevoked)
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Unprotect(Byte[] protectedData)
   at Microsoft.AspNetCore.Antiforgery.DefaultAntiforgeryTokenSerializer.Deserialize(String serializedToken)
   --- End of inner exception stack trace ---
   at Microsoft.AspNetCore.Antiforgery.DefaultAntiforgeryTokenSerializer.Deserialize(String serializedToken)
   at Microsoft.AspNetCore.Antiforgery.DefaultAntiforgery.GetCookieTokenDoesNotThrow(HttpContext httpContext)


We insert an anti-forgery token into the form using @Html.AntiForgeryToken() and validate the request using the [ValidateAntiForgeryToken], however we occasionally get the error above when one user tries to submit.

How is the key generated? Why does the user affect the generation of the token?

Expected Behavior

When user submit a form, the request token is valid and the user request is accepted.

Steps To Reproduce

  1. Create a cshtml page
  2. Include an antiforgery token in the form using @Html.AntiForgeryToken()
  3. Annotate the controller method with [ValidateAntiForgeryToken]
  4. Make a post request with the token

Exceptions (if any)

An exception was thrown while deserializing the token.
Microsoft.AspNetCore.Antiforgery.AntiforgeryValidationException: The antiforgery token could not be decrypted.

.NET Version

netcoreapp3.1

Anything else?

We have tried this with different users, different devices and different browsers.

Only this user has the issue, and it is correlated with the logs' timestamp.

I've checked the source code, and was wondering could it be due to special characters in the user name?

https://github.com/dotnet/aspnetcore/blob/main/src/Antiforgery/src/Internal/DefaultAntiforgeryTokenGenerator.cs
No response

@ghost ghost added area-dataprotection Includes: DataProtection untriaged labels Mar 14, 2023
@amcasey
Copy link
Member

amcasey commented May 19, 2023

I've checked the source code, and was wondering could it be due to special characters in the user name?

I suppose it's not impossible - are you able to share the user's name? Or maybe just the non-ASCII characters in it? Or what sort of non-ASCII characters it contains (Latin with accents? Japanese? emoji?)?

it is correlated with the logs' timestamp

I wasn't sure quite what you meant by this. I think maybe the user is seeing some sort of failure in their browser and when you look for failures in the log at the corresponding time, this is the stack you see?

Some boilerplate questions:

  1. What is your hosting environment? IIS? Kestrel? Azure? A container of some sort?
  2. Do you have multiple instances running?

@amcasey amcasey self-assigned this May 19, 2023
@NitinSinghSF
Copy link

We are having this same error running aspnet core web api 6.0 on AWS ECS

@ChadEQ
Copy link

ChadEQ commented Nov 14, 2023

I had the same issue in asp.net 7.0 on windows/IIS. One instance. And no special characters in the user name.

@weirdyang
Copy link
Author

I've checked the source code, and was wondering could it be due to special characters in the user name?

I suppose it's not impossible - are you able to share the user's name? Or maybe just the non-ASCII characters in it? Or what sort of non-ASCII characters it contains (Latin with accents? Japanese? emoji?)?

it is correlated with the logs' timestamp

I wasn't sure quite what you meant by this. I think maybe the user is seeing some sort of failure in their browser and when you look for failures in the log at the corresponding time, this is the stack you see?

Some boilerplate questions:

  1. What is your hosting environment? IIS? Kestrel? Azure? A container of some sort?

  2. Do you have multiple instances running?

Hi,

It doesn't contain any special characters or ascii.

Yes, I had the user share their screen, trigger the error and check the logs to ensure it's that error preventing them from submitting a form.

No, I do not have multiple instances running.

@amcasey
Copy link
Member

amcasey commented Nov 15, 2023

@weirdyang If you're in contact with the user, it might be interesting to ask them to try again after clearing their cookies.

@weirdyang @NitinSinghSF @ChadEQ How is your key ring stored? Is it a file on disk? A blob in Azure Storage?

@amcasey
Copy link
Member

amcasey commented Nov 15, 2023

Does anyone have a log including namespace Microsoft.AspNetCore.DataProtection, ideally at the Trace level?

@weirdyang
Copy link
Author

weirdyang commented Nov 15, 2023 via email

@amcasey
Copy link
Member

amcasey commented Nov 15, 2023

@weirdyang To confirm, this happens on every form submission from this user?

@NitinSinghSF @ChadEQ Are you seeing the same? There are multiple ways this error could arise.

@amcasey
Copy link
Member

amcasey commented Nov 15, 2023

All sorts of default behaviors are overridable, e.g. with AntiforgeryOptions, but it's not immediately obvious to me how the user's name/ID could be incorporated into the anti-forgery token or the data protection key.

Edit: it's in the anti-forgery token, which might explain why the problem follows the user. Maybe something about the way the user is encoded in the token breaks deserialization so that a bad data protection key ID is retrieved?

@amcasey
Copy link
Member

amcasey commented Nov 15, 2023

I'm assuming no one has a repro project they're able to share?

@amcasey
Copy link
Member

amcasey commented Nov 15, 2023

Just for the record, I suppose I should mention that netcoreapp3.1 is out of support and wouldn't be patched if that ended up being the fix. I'm tentatively operating on the assumption that @NitinSinghSF and @ChadEQ are seeing the same exception in 6.0 and 7.0, but it would be nice if they could confirm that they're seeing the same symptoms - the problem follows particular users across devices / cookie wipes.

@ChadEQ
Copy link

ChadEQ commented Nov 15, 2023

I'm on .net 7.0. And for me, it's extremely rare, not consistent.

@amcasey
Copy link
Member

amcasey commented Nov 15, 2023

@ChadEQ Are you seeing it for particular users or do you just occasionally see that log message?

@amcasey
Copy link
Member

amcasey commented Nov 15, 2023

@weirdyang Is the username unusually long or short?

@amcasey
Copy link
Member

amcasey commented Nov 15, 2023

@weirdyang Are you working with @apetrut? #51165 appears to have an error message with the same GUID.

@weirdyang
Copy link
Author

@weirdyang Are you working with @apetrut? #51165 appears to have an error message with the same GUID.

No

The user name is not unusually long

@ChadEQ
Copy link

ChadEQ commented Nov 15, 2023

Currently only see it for one user. It seems to be the first submit (the user is logging in) for the user after an IIS app pool recycle. The user name is 3 characters, but so are all the others.

@amcasey
Copy link
Member

amcasey commented Nov 15, 2023

And is that user seeing in on multiple devices and/or after clearing cookies?

@amcasey
Copy link
Member

amcasey commented Nov 15, 2023

Also, can you please confirm you're seeing a different GUID in your error message? I'm going to get creeped out if there are three of these.

@amcasey
Copy link
Member

amcasey commented Nov 20, 2023

Serialization format for the anti-forgery token:

/* The serialized format of the anti-XSRF token is as follows:
 * Version: 1 byte integer
 * SecurityToken: 16 byte binary blob
 * IsCookieToken: 1 byte Boolean
 * [if IsCookieToken != true]
 *   +- IsClaimsBased: 1 byte Boolean
 *   |  [if IsClaimsBased = true]
 *   |    `- ClaimUid: 32 byte binary blob
 *   |  [if IsClaimsBased = false]
 *   |    `- Username: UTF-8 string with 7-bit integer length prefix
 *   `- AdditionalData: UTF-8 string with 7-bit integer length prefix
 */

This blob of binary is then encrypted. From the stack, this is done using a KeyRingBasedDataProtector, which produces output starting with the magic header 0x09F0C9F0 and the bytes of the GUID key ID (669d513e-a172-4851-b160-04b523abbc1e in the original report), followed by the encrypted data, etc.

Finally, the encrypted payload is base64 encoded.

Reversing this to deserialize, we expect only to have to base64 decode and discard 4 bytes of magic header to access the 16 bytes of the key ID.

While user-specific data does appear in the payload, particularly in the Username or ClaimUid, these come after the key ID, so it's not clear to me how they could cause the key ID to be deserialized incorrectly.

There are some nuances around endianness, but we've said that this repros across a number of widely-used devices.

There are definitely scenarios/bugs where you could fail to find a key, but I'm having trouble thinking of a way it could affect only particular users.

@amcasey
Copy link
Member

amcasey commented Nov 20, 2023

I gather these apps are authenticated. What mechanism are people using? Claims-based? Which provider?

@ChadEQ
Copy link

ChadEQ commented Nov 20, 2023

To answer your previous questions first, but not sure if any of them where directed at me. Different key than what's reported in this issue. User hasn't tried different devices, but has tried Edge and Chrome. Interestingly but probably coincidental, it seems to be easier to reproduce using Edge than Chrome. Yes, using authentication. Cookie authentication scheme and yes using claims. But for us, the error is happening on an anonymous page, before the user has logged in, so no authentication cookie is sent, just the anti-forgery.

@amcasey
Copy link
Member

amcasey commented Nov 21, 2023

@ChadEQ Thanks! Sorry for not being clearer with tags.

I'm relieved to hear that the guid is different. 😅

Edge and Chrome are pretty similar these days, though that should at least get you a fresh cookie. Trying on a different device would be interesting, if that's an option.

The fact that this is happening before authentication is interesting - I think it will still put a blank username in the token, but that should be the same for all users. Is the user themself distinguished in some way? Are they the first to sign in every morning (e.g. because of time zones)?

@amcasey
Copy link
Member

amcasey commented Nov 21, 2023

@weirdyang @ChadEQ Are either of you able to debug the server while this is failing? We have public symbols and I can suggest breakpoints.

@apetrut
Copy link

apetrut commented Nov 21, 2023

@amcasey I had a similar issue when using same browser with 2 tabs. If tried using 2 different browsers then I didn't get that issue anymore.

@amcasey
Copy link
Member

amcasey commented Nov 21, 2023

@apetrut I think two tabs in the same browser would use the same cookie and require the same key for decryption.

@amcasey
Copy link
Member

amcasey commented Nov 21, 2023

@apetrut Any insights on the GUID collision? I'm assuming you didn't copy-paste yours from this bug.

@apetrut
Copy link

apetrut commented Nov 22, 2023

@amcasey I don't recall seeing this ticket when I opened mine.

@weirdyang This is what I've tried in order to get rid of the error and it worked for me:

services.AddAntiforgery(options =>
{
options.FormFieldName = "AntiforgeryFieldname";
options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
options.SuppressXFrameOptionsHeader = false;
});

and also:

services.AddDataProtection()
.SetApplicationName("yourAppName")
.PersistKeysToFileSystem(new DirectoryInfo(string.Format(@"{0}opt{0}app{0}sysfiles{0}", Path.DirectorySeparatorChar)))
.ProtectKeysWithCertificate(new X509Certificate2(string.Format(@"{0}certificates{0}verify-cert.pfx", Path.DirectorySeparatorChar), Configuration["ApplicationSettings:CertificatePassword"]))
.SetDefaultKeyLifetime(TimeSpan.FromDays(15));

@amcasey
Copy link
Member

amcasey commented Nov 22, 2023

It's not obvious to me how changing the anti-forgery options could help, but explicitly configuring data protection might well bypass whatever bug/surprising behavior is causing this error.

@amcasey
Copy link
Member

amcasey commented Nov 22, 2023

FYI, we're going into a long weekend here, so responses are likely to be slow until next week.

@ghost
Copy link

ghost commented Jan 26, 2024

Thanks for contacting us.

We're moving this issue to the .NET 9 Planning milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s).
If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues.
To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

@amcasey amcasey removed their assignment Jan 26, 2024
@brackert
Copy link

I didn't read this entire thread, so I apologize if someone already suggested this...

One possible cause: If you are using IIS, make sure the application pool (Advanced Settings) has 'Load User Profile' set to True.

@Sajad-dev720
Copy link

Hi!
I get the same error for every user, but not in Mozilla and Mozilla Developer Edition, only in MS Edge and Chrome. The error I get in the logs is as follows:
Microsoft.AspNetCore.Antiforgery.AntiforgeryValidationException: The antiforgery token could not be decrypted. ---> System.Security.Cryptography.CryptographicException: The key {946d4fa4-6290-4104-a4d6-d0eb9dfa3006} was not found in the key ring. For more information go to http://aka.ms/dataprotectionwarning at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.UnprotectCore(Byte[] protectedData, Boolean allowOperationsOnRevokedKeys, UnprotectStatus& status) at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Unprotect(Byte[] protectedData) at Microsoft.AspNetCore.Antiforgery.DefaultAntiforgeryTokenSerializer.Deserialize(String serializedToken) --- End of inner exception stack trace --- at Microsoft.AspNetCore.Antiforgery.DefaultAntiforgeryTokenSerializer.Deserialize(String serializedToken) at Microsoft.AspNetCore.Antiforgery.DefaultAntiforgery.GetCookieTokenDoesNotThrow(HttpContext httpContext)

A point to be considered is, it rarely happens on our production server, but it happens every time on our test server, where we set the same PasswordHash for all users. Now as far as I could trace it, the authentication is done successfully, but afterwards, when redirecting to a protected endpoint, this error happens and the user is unable to log in.

I didn't read this entire thread, so I apologize if someone already suggested this...

One possible cause: If you are using IIS, make sure the application pool (Advanced Settings) has 'Load User Profile' set to True.

I also did that and the result was the same.

@enkelmedia
Copy link

enkelmedia commented Mar 13, 2024

I have the same error, especially in development - the error is logged on each startup even after cleaning cookies in the browser. Also using Chrome.

EDIT:
In our case we had the right setup, storing keys on disk etc. but the application that we where running (Umbraco CMS) did some shady stuff with custom anti-forgery tokens and did not consider the configuration that we added during startup.

@joepietrzak
Copy link

same issue here, just tapping in so I get notified if/when there's a resolution

@amcasey
Copy link
Member

amcasey commented Mar 28, 2024

@enkelmedia @joepietrzak I just want to confirm: there are lots of reasons you might see key not found errors - what's special about this thread is that the error somehow follows a particular user, even across devices, but other users are unaffected. Is that's what you're seeing?

@enkelmedia
Copy link

@amcasey It seems like that, one solution we work on works on my colleges computer but I get this issue. The issue is also not present on test, stage or prod machines.

To be fair - i did not try to clone the solution into a clean folder - might be worth trying.

@VahidN
Copy link

VahidN commented Apr 22, 2024

If you are running your app on a web farm or cloud environment, you should persist the data protection key, otherwise it will be different on each machine. more info
The same thing will happen if you recycle the application's pool on IIS. The old key will be disappeared. more info

@boukenka
Copy link

boukenka commented Aug 6, 2024

Any update? Facing the same issue.

@scharada
Copy link

same issue here ...

@madjar4-cssmb
Copy link

madjar4-cssmb commented Aug 30, 2024

I have a case that is not user specific. I will report it here, as I am not fully certain that it is an issue or expected behaviour. It might help with this.

Context:

  • a blazor .NET 8 Web App. App & Routes configured for interactive server.
  • the entrypoint is anonymous, no auth cookie required.
  • the application is hosted on IIS, on a path (example: my.website.com/ThisIsTheBasePathOfTheApp)
    • The base path is configured with /ThisIsTheBasePathOfTheApp/.

Simply navigating to my.website.com/ThisIsTheBasePathOfTheApp works no problem.
Now, if we navigate to it after we change the casing of a single letter, I get a familiar error exception. For example, if we go to my.website.com/thisIsTheBasePathOfTheApp (first t is lowercase).

Exception: The antiforgery token could not be decrypted.

Source: Microsoft.AspNetCore.Antiforgery
StackTrace:

  • at Microsoft.AspNetCore.Antiforgery.DefaultAntiforgeryTokenSerializer.Deserialize(String serializedToken)
  • at Microsoft.AspNetCore.Antiforgery.DefaultAntiforgery.GetCookieTokenDoesNotThrow(HttpContext httpContext)

InnerException: The key {597fc0e8-bbce-4963-b068-0f809a667142} was not found in the key ring. For more information go to https://aka.ms/aspnet/dataprotectionwarning

Source: Microsoft.AspNetCore.DataProtection
StackTrace:

  • at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.UnprotectCore(Byte[] protectedData, Boolean allowOperationsOnRevokedKeys, UnprotectStatus& status)
  • at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Unprotect(Byte[] protectedData)
  • at Microsoft.AspNetCore.Antiforgery.DefaultAntiforgeryTokenSerializer.Deserialize(String serializedToken)

Edit:

I suppose this is more related with #5405, but I cannot be certain.

@varunmydala
Copy link

varunmydala commented Oct 22, 2024

I face same issue in my local IIS. It is fine in Staging and production envs.
.NET code web app running on .NET 6.

@madjar4-cssmb
Copy link

As a workaround, a middleware "standardizing" the request path has been added in our app right after UsePathBase. It basically does the following:

// context is the HttpContext.
var basePath = context.Request.PathBase;
if (basePath.StartsWithSegments(_basePathWithoutSlash, StringComparison.InvariantCultureIgnoreCase)
               && !basePath.StartsWithSegments(_basePathWithoutSlash, StringComparison.Ordinal))
{
    // Redirect to _basePathWithoutSlash + context.Request.Path
}
// carry on

@SolarOsQuiere
Copy link

SolarOsQuiere commented Oct 29, 2024

Same issue:

Blazor Net8 : Rendermode Auto (with server and client components)

Deployed Windows Server 2019 on 2 nodes.

When the app is deployed first time i get the exception, in the logs:

Microsoft.AspNetCore.Antiforgery.AntiforgeryValidationException: The antiforgery token could not be decrypted.
 ---> System.Security.Cryptography.CryptographicException: The key {d8ffbea2-4fff-4fd2-ade3-f0fb72b71a12} was not found in the key ring. For more information go to https://aka.ms/aspnet/dataprotectionwarning
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.UnprotectCore(Byte[] protectedData, Boolean allowOperationsOnRevokedKeys, UnprotectStatus& status)
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Unprotect(Byte[] protectedData)
   at Microsoft.AspNetCore.Antiforgery.DefaultAntiforgeryTokenSerializer.Deserialize(String serializedToken)
   --- End of inner exception stack trace ---
   at Microsoft.AspNetCore.Antiforgery.DefaultAntiforgeryTokenSerializer.Deserialize(String serializedToken)
   at Microsoft.AspNetCore.Antiforgery.DefaultAntiforgery.GetCookieTokenDoesNotThrow(HttpContext httpContext)

But somehow the app its up with no problems

Tried following the code recommended in the guides:

public static IServiceCollection ConfiguracionAntiforgeryToken(
    this IServiceCollection services,
    WebApplicationBuilder config
)
{
    var keysFolder = Path.Combine(config.Environment.ContentRootPath, "Keys");
    Directory.CreateDirectory(keysFolder);
    config
        .Services.AddDataProtection()
        .UseCryptographicAlgorithms(
            new AuthenticatedEncryptorConfiguration
            {
                EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
                ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
            }
        )
        .PersistKeysToFileSystem(new DirectoryInfo(keysFolder))
        .SetApplicationName("MyWebsite")
        .SetDefaultKeyLifetime(TimeSpan.FromDays(90));
    return services;
}

But nothing changes, i get the error only when the app is deployed for the first time

Update: i think its related with this : #46124

@omuleanu
Copy link

omuleanu commented Dec 24, 2024

I'm not using the ValidateAntiForgeryToken attribute anywhere in my app (asp.net core 8), and I'm getting sometimes this error.

DefaultAntiforgeryTokenSerializer.cs in AntiforgeryToken DefaultAntiforgeryTokenSerializer.Deserialize(string serializedToken) at line 69

// if we reached this point, something went wrong deserializing
throw new AntiforgeryValidationException(Resources.AntiforgeryToken_DeserializationFailed, innerException); 

it starts here:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-dataprotection Includes: DataProtection
Projects
None yet
Development

No branches or pull requests