Anti-Fogery 令牌部署在负载均衡器后面时无法解密

Anti-Fogery token cannot be decrypted when deployed behind a load balancer

我在我的 Asp.Net Core 1.0 站点中设置了 AntiForgery 令牌,如下所示:

  services.AddAntiforgery(options =>
        {
            options.HeaderName = "X-XSRF-Token"; //Angular's default header name for sending the xsrf token
        });

app.Use(next => context =>
        {
            //2 tokens are generated.  A Cookie token, which goes in an ASP cookie called something like .AspNetCore.Antiforgery.****** and a request token.  The request token gets passed in the http request
            //headers back to the server when executing a POST and is validated agains't the cookie token.  By taking the request token and putting it in an HTTP-Only cookie called XSRF-TOKEN, Angular will 
            //automatically take the cookie and add it to an X-XSRF-Token header for each request.   The request token received in the header is then validated against the cookie token. In ConfigureServices() above, 
            //ASP's antiforgery system is setup to look for the request token in the X-XSRF-Token header.  For form posts (i.e. not posts done by Angular), the form has a token associated with it that gets passed in the POST
            // which is used in place of the header token  
            var tokens = antiforgery.GetAndStoreTokens(context);
            context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken, new CookieOptions() { HttpOnly = false });

            return next(context);
        });

        app.UseAntiForgeryValidation();

public class AntiForgeryValidation
{
    private readonly RequestDelegate _next;
    IAntiforgery _antiforgery;
    private ILogger<AntiForgeryValidation> _logger;

    public AntiForgeryValidation(RequestDelegate next, IAntiforgery antiforgery, ILoggerFactory loggerFactory)
    {
        _next = next;
        _antiforgery = antiforgery;
        _logger = loggerFactory.CreateLogger<AntiForgeryValidation>();
    }

    public async Task Invoke(HttpContext context)
    {
        //don't need to validate anti-forgery tokens for GET
        if (string.Equals("POST", context.Request.Method, StringComparison.OrdinalIgnoreCase)
            || string.Equals("PUT", context.Request.Method, StringComparison.OrdinalIgnoreCase)
            || string.Equals("DELETE", context.Request.Method, StringComparison.OrdinalIgnoreCase))
        {

            await _antiforgery.ValidateRequestAsync(context);
        }

        await _next(context);
    }
}

public static partial class MiddlewareExtensionMethods
{
    public static void UseAntiForgeryValidation(this IApplicationBuilder builder)
    {
        builder.UseMiddleware<AntiForgeryValidation>();
    }
}

在我的开发环境中,当发布到 IIS 时,效果很好。虽然我的网站前面有一个负载均衡器,当我通过负载均衡器提供的 VIP 访问它时,我的 anti-forgery 验证开始失败并出现以下错误:

{7f02de42-e781-4c27-a2e5-fce932f4b7a4} 未在密钥环中找到。取消保护操作无法继续

无法解密 application.The 防伪令牌引发了未处理的异常。

(更多日志在下方)。

我还应该指出,即使有一个负载平衡器,它后面只有 1 个 Web 服务器,所以在服务器之间拆分请求应该没有任何问题。如果有人知道为什么在通过负载均衡器访问时会发生这种情况,而不是在直接访问时(通过主机条目绕过负载均衡器),我希望得到一些帮助。

日志 2016-11-01 15:28:01.3761|22|TRACE|Microsoft.Extensions.Logging.LoggingExtensions.PerformingUnprotectOperationToKeyWithPurposes|对密钥 {4441518f-1b1d-49a8-b06a-29724cb692ae} 执行解除保护操作('C:\temp\wizard','Microsoft.AspNetCore.Antiforgery.AntiforgeryToken.v1'). 2016-11-01 15:28:01.4074|22|TRACE|Microsoft.Extensions.Logging.LoggingExtensions.PerformingProtectOperationToKeyWithPurposes|对密钥 {4441518f-1b1d-49a8-b06a-29724cb692ae} 执行保护操作('C:\temp\wizard','Microsoft.AspNetCore.Antiforgery.AntiforgeryToken.v1'). 2016-11-01 15:28:01.4074|22|DEBUG|Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgery.GetAndStoreTokens|防伪 cookie 令牌被重复使用。 2016-11-01 15:28:01.4230|22|TRACE|Microsoft.Extensions.Logging.LoggingExtensions.PerformingUnprotectOperationToKeyWithPurposes|对密钥 {7f02de42-e781-4c27-a2e5-fce932f4b7a4} 执行解除保护操作('C:\temp\wizard','Microsoft.AspNetCore.Antiforgery.AntiforgeryToken.v1'). 2016-11-01 15:28:01.4230|22|TRACE|Microsoft.Extensions.Logging.LoggingExtensions.KeyWasNotFoundInTheKeyRingUnprotectOperationCannotProceed|在密钥环中找不到密钥 {7f02de42-e781-4c27-a2e5-fce932f4b7a4}。取消保护操作无法继续。 2016-11-01 15:28:01.4230|22|错误|Microsoft.AspNetCore.Server.Kestrel.Internal.Http.Frame`1.RequestProcessingAsync|连接 ID“0HL02KLA3LKUJ”:application.The 防伪令牌引发了未处理的异常不被解密。 2016-11-01 15:28:01.4230|22|INFO|Microsoft.AspNetCore.Hosting.Internal.HostingLoggerExtensions.RequestFinished|请求在 44.7391 毫秒内完成 200 2016-11-01 15:28:01.4230|22|DEBUG|Microsoft.AspNetCore.Server.Kestrel.Internal.Http.Connection.Microsoft.AspNetCore.Server.Kestrel.Internal.Http.IConnectionControl.End|连接 ID“0HL02KLA3LKUJ”完成保持活动响应。

更新

我添加了

 services.AddDataProtection()
            .PersistKeysToFileSystem(new DirectoryInfo(@"c:\temp\"));

一个密钥保存到 c:\temp\ 但我仍然遇到问题。更新的日志如下。密钥:{f5087f37-37e3-4e52-b40b-77e32a285f3e}被写入c:\temp并被选为默认密钥,但是应用程序仍然存在一些神秘密钥{4441518f-1b1d-49a8-b06a-29724cb692ae}试图用于解密无法找到的 anti-fogery 令牌。

2016-11-02 07:19:28.7357|1|DEBUG|Microsoft.AspNetCore.Hosting.Internal.HostingLoggerExtensions.Starting|托管开始 2016-11-02 07:19:28.8450|1|DEBUG|Microsoft.AspNetCore.Hosting.Internal.HostingLoggerExtensions.Started|托管开始 2016-11-02 07:19:29.0326|7|DEBUG|Microsoft.AspNetCore.Server.Kestrel.Internal.Http.Connection.Start|连接 ID“0HL035D0UCHEL”已启动。 2016-11-02 07:19:29.1107|3|INFO|Microsoft.AspNetCore.Hosting.Internal.HostingLoggerExtensions.RequestStarting|请求开始 HTTP/1.1 POST http://apidev.brewster.ca/ application/x-www-form-urlencoded 218 2016-11-02 07:19:29.1263|3|DEBUG|Microsoft.AspNetCore.HttpOverrides.ForwardedHeadersMiddleware.ApplyForwarders|X-Forwarded-For 和 X-Forwarded-Proto 之间的参数计数不匹配。 2016-11-02 07:19:29.1732|3|TRACE|Microsoft.Extensions.Logging.LoggingExtensions.PerformingUnprotectOperationToKeyWithPurposes|对密钥 {4441518f-1b1d-49a8-b06a-29724cb692ae} 执行解除保护操作('C:\webpublish\wizard','Microsoft.AspNetCore.Antiforgery.AntiforgeryToken.v1'). 2016-11-02 07:19:29.1888|3|DEBUG|Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository.ReadElementFromFile|从文件 'c:\temp\key-f5087f37-37e3-4e52-b40b-77e32a285f3e.xml' 中读取数据。 2016-11-02 07:19:29.1888|3|DEBUG|Microsoft.Extensions.Logging.LoggingExtensions.FoundKey|找到密钥 {f5087f37-37e3-4e52-b40b-77e32a285f3e}。 2016-11-02 07:19:29.2200|3|DEBUG|Microsoft.Extensions.Logging.LoggingExtensions.ConsideringKeyWithExpirationDateAsDefaultKey|考虑过期日期为 2017-01-31 14:11:02Z 的密钥 {f5087f37-37e3-4e52-b40b-77e32a285f3e} 作为默认键。 2016 年 11 月 2 日 07:19:29.2357|3|DEBUG|Microsoft.Extensions.Logging.LoggingExtensions.OpeningCNGAlgorithmFromProviderWithChainingModeCBC|从供应商“”打开 CNG 算法 'AES',采用链接模式 CBC。 2016-11-02 07:19:29.2513|3|DEBUG|Microsoft.Extensions.Logging.LoggingExtensions.OpeningCNGAlgorithmFromProviderWithHMAC|使用 HMAC 从提供程序“”打开 CNG 算法 'SHA256'。 2016-11-02 07:19:29.2670|3|DEBUG|Microsoft.Extensions.Logging.LoggingExtensions.UsingKeyAsDefaultKey|使用密钥 {f5087f37-37e3-4e52-b40b-77e32a285f3e} 作为默认密钥。 2016-11-02 07:19:29.2670|3|TRACE|Microsoft.Extensions.Logging.LoggingExtensions.KeyWasNotFoundInTheKeyRingUnprotectOperationCannotProceed|在密钥环中找不到密钥 {4441518f-1b1d-49a8-b06a-29724cb692ae}。取消保护操作无法继续。 2016-11-02 07:19:29.2670|3|错误|Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgery.GetCookieTokenDoesNotThrow|反序列化 token.The 防伪令牌时抛出异常无法解密。 2016-11-02 07:19:29.2982|3|TRACE|Microsoft.Extensions.Logging.LoggingExtensions.PerformingProtectOperationToKeyWithPurposes|对密钥 {f5087f37-37e3-4e52-b40b-77e32a285f3e} 执行保护操作('C:\webpublish\wizard','Microsoft.AspNetCore.Antiforgery.AntiforgeryToken.v1'). 2016-11-02 07:19:29.2982|3|TRACE|Microsoft.Extensions.Logging.LoggingExtensions.PerformingProtectOperationToKeyWithPurposes|对密钥 {f5087f37-37e3-4e52-b40b-77e32a285f3e} 执行保护操作('C:\webpublish\wizard','Microsoft.AspNetCore.Antiforgery.AntiforgeryToken.v1'). 2016-11-02 07:19:29.3138|3|DEBUG|Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgery.GetAndStoreTokens|创建了一个新的防伪 cookie 令牌。 2016-11-02 07:19:29.3296|3|DEBUG|VTR.Common.Utilities.Middleware.AntiForgeryValidation.Invoke|AntiForgeryCookie:[.AspNetCore.Antiforgery.2mRY6wjt_Lw, CfDJ8I9RQUQdG6hJsGopcky2kq4ayXKUx4xErDElnyDij0J31qSLHyt3oKyqJ1ocoRHYoIkK7WSpze9SVEzOan0LQTFs3SwwtvMUw_e6EUPvaPxWjH_1_pQ5DiT8hu7TM8UNWjjFT_XSkNZz-uBVHdh2CmY] 2016-11-02 07:19:29.3296|3|DEBUG|VTR.Common.Utilities.Middleware.AntiForgeryValidation.Invoke|XSRF cookie:CfDJ8I9RQUQdG6hJsGopcky2kq45_O5j5bzBP5QyxbzIKXaSbb8K04mez2Czsa_OdCYn84bvSz2v8M-nkN_O6yorN8qfyy4mV3HdGJV3BQgWSHSFrziJfQonBKmiF4fsrmpHVX7jA6iugirWL8yNJPO35xY 2016-11-02 07:19:29.3607|3|DEBUG|VTR.Common.Utilities.Middleware.AntiForgeryValidation.Invoke|Form Token: CfDJ8ELeAn-B5ydMouX86TL0t6R3a1YFIaw2K3Wf6xpsbQPGztGb2uACGCdnofeFKd-woGFkwTjWQEC4Qag1E2A2RCxtvry4DJAvPSZnbKZGMd248exLwt9CX1bhWsYj8Cs6N9MvEQ38gqEXmEArDXFYMM0 2016-11-02 07:19:29.3607|3|DEBUG|VTR.Common.Utilities.Middleware.AntiForgeryValidation.Invoke|Header 代币: 2016-11-02 07:19:29.3768|3|TRACE|Microsoft.Extensions.Logging.LoggingExtensions.PerformingUnprotectOperationToKeyWithPurposes|对密钥 {7f02de42-e781-4c27-a2e5-fce932f4b7a4} 执行解除保护操作('C:\webpublish\wizard','Microsoft.AspNetCore.Antiforgery.AntiforgeryToken.v1'). 2016-11-02 07:19:29.3768|3|TRACE|Microsoft.Extensions.Logging.LoggingExtensions.KeyWasNotFoundInTheKeyRingUnprotectOperationCannotProceed|密钥 {7f02de42-e781-4c27-a2e5-fce932f4b74} 未在密钥环中找到。取消保护操作无法继续。 2016-11-02 07:19:29.3768|3|错误|Microsoft.AspNetCore.Server.Kestrel.Internal.Http.Frame`1.RequestProcessingAsync|连接 ID“0HL035D0UCHEL”:application.The 防伪令牌引发了未处理的异常不被解密。 2016-11-02 07:19:29.3768|3|INFO|Microsoft.AspNetCore.Hosting.Internal.HostingLoggerExtensions.RequestFinished|请求在 286.4265 毫秒内完成 200 2016-11-02 07:19:29.4233|3|DEBUG|Microsoft.AspNetCore.Server.Kestrel.Internal.Http.Connection.Microsoft.AspNetCore.Server.Kestrel.Internal.Http.IConnectionControl.End|连接 ID“0HL035D0UCHEL”完成保持活动响应。

此问题是由负载平衡器上的缓存问题引起的。刷新缓存后,丢失密钥的问题就消失了