linuxasp.net-core.net-coreantiforgerytoken

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?


Solution

  • 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...