我已经在一些负载平衡的Linux服务器上部署了一个asp.net core应用程序。由于
ValidateAntiForgeryToken
属性失败,我在将表单发布到路由时收到错误(如果 POST 没有返回到与生成表单的计算机相同的计算机)。
对于 Windows 和 .Net classic,我知道要匹配我的
MachineKey
或 web.config
文件中的 machine.config
属性。
那么,如何在 Linux 主机上实现相同的目标,并允许一台服务器的令牌在另一台服务器上进行验证?
因此,当您致电
services.addMvc()
时,会自动添加防伪支持。您可以通过调用 services.AddAntiforgery(opts => "your options")
来更改基本配置。
在底层,令牌受到 ASP.Net Core 数据保护库(github 存储库此处)的保护。默认情况下,我认为这是在内存中,因此生成的密钥然后用于令牌保护,不会在多个/云服务器场景中共享。
解决方案
因此,要共享防伪令牌,您可以使用共享位置设置数据保护服务。数据保护库自带的默认有:
//File system
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\some\shared\directory\"));
//Registry
services.AddDataProtection()
.PersistKeysToRegistry(Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Sample\keys"));
然后有几个默认值可以提供更好的共享存储:
//redis
var redis = ConnectionMultiplexer.Connect("my-redis-url");
services.AddDataProtection()
.PersistKeysToRedis(redis, "DataProtection-Keys");
//Azure
services.AddDataProtection()
.PersistKeysToAzureBlobStorage(new Uri("blob-URI"));
感谢一位名为 CL0SeY 的 github 用户,我还从 github 找到(并使用了!)AWS S3 存储选项。
更新:Amazon 也发布了自己的使用 AWS SSM 参数存储的实现。 Github 存储库在这里。 用于测试
默认情况下,令牌的生命周期为 90 天。这可以在添加服务时设置。因此,获得简单的测试解决方案的一种方法是生成具有较长生命周期的文件系统密钥,然后将该令牌部署到服务器上的已知位置。然后从该位置设置数据保护,但告诉它永远不要生成新密钥:
//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();
在Linux上
所有这些都应该在 Linux 上托管时工作,唯一需要注意的是您不应该引用 Windows 驱动器或位置(废话)。我也不是 100% 确定如果您尝试注册表选项会发生什么...
对于使用 ASP.NET Core 的任何人来说,在使用负载均衡器时,AWS 上的防伪功能会出现问题。防伪功能作为单个实例可以正常工作,无需任何配置。 除了将密钥保存到文件系统之外,我还必须将目标组设置为使用带有服务器生成的 cookie 的粘性会话。另一种可能性是使用 Entity Core DbContext,这将允许多个应用程序共享一个密钥。