间歇性修改数据保护密钥集合导致 401 错误

Data Protection keys collection is intermittently modified causing 401 errors

我有两个共享身份验证 cookie 的站点:

主站点的 cookie 通过并用于验证 SignalR 协商请求。

我最近部署了一些从 ASP.NET Framework 到 .NET5 的大规模更改。此更改的一部分意味着使用新的数据保护密钥,以便可以解密两个应用程序上的授权票证(以前,ASP.NET 框架版本只需要两个应用程序上的机器密钥匹配,这可以在 web.config).

这是数据保护代码的样子,用于主站点和聊天站点:

public void ConfigureServices(IServiceCollection services)
{
    services.AddCustomDataProtection(_configuration);
    ...
}

public static IServiceCollection AddCustomDataProtection(this IServiceCollection services, IConfiguration configuration)
{
    var siteSettings = configuration
        .GetSection(SiteSettings.SectionName)
        .Get<SiteSettings>();

    var dataProtection = services.AddDataProtection()
        .SetApplicationName(siteSettings.SiteName);

    var dataProtectionSettings = configuration
        .GetSection(DataProtectionSettings.SectionName)
        .Get<DataProtectionSettings>();

    if (!string.IsNullOrWhiteSpace(dataProtectionSettings.KeyVaultIdentifier))
    {
        dataProtection
            .PersistKeysToAzureBlobStorage(
                configuration.GetConnectionString("StorageConnectionString"),
                dataProtectionSettings.KeyStoreContainerName,
                dataProtectionSettings.KeyStoreBlobName)
            .ProtectKeysWithAzureKeyVault(
                new Uri(dataProtectionSettings.KeyVaultIdentifier),
                new DefaultAzureCredential());
    }

    return services;
}

自部署以来,我们遇到了一些奇怪的问题,即存储在 Azure 存储中的数据保护密钥 blob 全天都在修改。发生这种情况似乎没有任何韵律或原因。

根据我的理解,数据保护密钥默认情况下每 90 天左右刷新一次,但是这种情况每天发生 1-2 次。应用程序中的代码从不直接与 Key Vault 密钥或数据保护密钥 blob 交互(仅通过下面发布的代码)并且我添加了显示正确设置的日志 are通过数据保护扩展方法。

另一方面,我一直遇到间歇性问题,当主站点向聊天站点发送协商请求时,它收到 401 错误,表明 cookie/auth 票证无效或其他原因无法解密。当通过重新启动主站点、注销然后再次登录来修改密钥时,我可以重现此问题。我认为这两个问题是相关的。

我对这种行为的暗中解释是,也许主站点正确地获取了数据保护密钥的更改,但聊天站点没有。然后,聊天站点无法解密使用它无权访问的密钥加密的授权票证。重新启动聊天站点可以解决问题,大概是因为数据保护密钥在启动时重新加载。

所以我主要担心两个问题:

  1. 为什么要修改数据保护密钥 blob?
  2. 如果确实有新密钥被添加到数据保护密钥集合中,为什么聊天站点不选择新密钥?

问题最终是主站点和聊天站点都将数据保护密钥存储在 Azure 存储中的同一个 blob 中。这导致了我在修改 blob 时看到的奇怪行为,进而导致了我遇到的应用程序错误。

我认为将密钥存储在同一位置会很好,因为我当时阅读了与 SetApplicationName() 方法相关的文档,导致密钥彼此隔离。不幸的是,这种隔离并没有扩展到实际的物理数据保护密钥,而是扩展到存储在其中的有效负载。 The documentation surrounding app isolation 已经更新,现在更加详细。