Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I handle ValidateAntiForgeryToken across linux servers

I have deployed an asp.net core app on some load balanced linux servers. I getting an error when POSTing a form to a route due to a failing ValidateAntiForgeryToken attribute (if a POST does not go back to the same machine as the one that generated my form).

With Windows and .Net classic I know to match MachineKey attributes in my web.config or machine.config files.

So, how do I achieve the same on linux hosts and allow a token from one server to be validated on another?

like image 333
Simon C Avatar asked May 09 '17 03:05

Simon C


People also ask

How do you handle anti-forgery token error?

The common “possible solutions” to anti-forgery token/cookie related issues are disabling output caching and enabling heuristic checks.

How does ValidateAntiForgeryToken work?

The basic purpose of ValidateAntiForgeryToken attribute is to prevent cross-site request forgery attacks. A cross-site request forgery is an attack in which a harmful script element, malicious command, or code is sent from the browser of a trusted user.

What is ValidateAntiForgeryToken ASP NET core?

HttpPost: The HttpPost attribute which signifies that the method will accept Http Post requests. ValidateAntiForgeryToken: The ValidateAntiForgeryToken attribute is used to prevent cross-site request forgery attacks.

What is the use of AntiForgeryToken in MVC?

AntiForgeryToken() Generates a hidden form field (anti-forgery token) that is validated when the form is submitted.


1 Answers

So Antiforgery support is added automatically when you call services.addMvc(). You can alter the basic configuration by calling services.AddAntiforgery(opts => "your options").

Under the hood, the token is protected by ASP.Net Core Data Protection library (github repo here). By default I think this is in memory, so keys generated, and then used for token protection, are not shared on a mulitple / cloud server scenario.

Solution

So to share antiforgery tokens, you can set up the Data Protection service with a shared location. The default ones that come with the data protection library are:

//File system
services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(@"\\some\shared\directory\"));

//Registry
services.AddDataProtection()
   .PersistKeysToRegistry(Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Sample\keys"));

Then there are a couple of defaults for better shared storage included:

//redis
var redis = ConnectionMultiplexer.Connect("my-redis-url");
services.AddDataProtection()
    .PersistKeysToRedis(redis, "DataProtection-Keys");

//Azure
services.AddDataProtection()
    .PersistKeysToAzureBlobStorage(new Uri("blob-URI"));

I have also found (and used!) an option for AWS S3 storage from github thanks to a github user named CL0SeY.

Update: Amazon released their own implementation for using AWS SSM parameter store as well. Github repo here. For testing

By default, tokens have a lifetime of 90 days. This can be set when you add the service. So one way to get a simple solution for testing is to generate a key to filesystem with a long lifetime, then deploy that token to a known location on your servers. Then set up data protection from that location, but tell it to never generate new keys:

//generate a test key with this in a test app or whatever: 
services.AddDataProtection()
       .PersistKeysToFileSystem(new DirectoryInfo(@"c:\temp\"))
       .SetDefaultKeyLifetime(TimeSpan.MaxValue);


// then use that key in your app:
services.AddDataProtection()
       .PersistKeysToFileSystem(new DirectoryInfo(@"\some\allowed\directory"))
       .DisableAutomaticKeyGeneration();

On linux

All of this should work on when hosted on linux with the only caveat being that you shouldn't reference windows drives or locations (duh). I am not 100% sure what would happen if you tried the registry option either...

like image 169
Simon C Avatar answered Sep 18 '22 14:09

Simon C