配置 ASP.NET Core 数据保护Configure ASP.NET Core Data Protection

本文内容

当数据保护系统已初始化时,它将基于操作环境应用默认设置这些设置通常适用于在一台计算机上运行的应用程序。在某些情况下,开发人员可能想要更改默认设置:

  • 应用程序分布在多台计算机上。
  • 出于合规性原因。

在这些情况下,数据保护系统提供了丰富的配置 API。

警告

与配置文件类似,应使用适当的权限保护数据保护密钥环。你可以选择对静态密钥加密,但这不会阻止攻击者创建新密钥。因此,应用的安全将受到影响。使用数据保护配置的存储位置应该将其访问权限限制为应用本身,这与保护配置文件的方式类似。例如,如果选择将密钥环存储在磁盘上,请使用文件系统权限。确保你的 web 应用在其下运行的标识具有对该目录的读取、写入和创建访问权限。如果使用 Azure Blob 存储,则只有 web 应用应能够在 Blob 存储中读取、写入或创建新条目等。

扩展方法AddDataProtection返回IDataProtectionBuilderIDataProtectionBuilder 公开扩展方法,你可以将这些方法链接在一起来配置数据保护选项。

本文中使用的数据保护扩展插件需要以下 NuGet 包:

ProtectKeysWithAzureKeyVaultProtectKeysWithAzureKeyVault

若要在Azure Key Vault中存储密钥,请在 Startup 类中配置ProtectKeysWithAzureKeyVault的系统:

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddDataProtection()
  4. .PersistKeysToAzureBlobStorage(new Uri("<blobUriWithSasToken>"))
  5. .ProtectKeysWithAzureKeyVault("<keyIdentifier>", "<clientId>", "<clientSecret>");
  6. }

设置密钥环存储位置(例如, PersistKeysToAzureBlobStorage)。必须设置位置,因为调用 ProtectKeysWithAzureKeyVault 实现了禁用自动数据保护设置的IXmlEncryptor ,包括密钥环存储位置。前面的示例使用 Azure Blob 存储来持久保存密钥环。有关详细信息,请参阅密钥存储提供程序: Azure 存储还可以通过PersistKeysToFileSystem将密钥环保存到本地。

keyIdentifier 是用于密钥加密的密钥保管库密钥标识符。例如,在 contosokeyvault 中名为 dataprotection 的密钥保管库中创建的密钥具有密钥标识符 https://contosokeyvault.vault.azure.net/keys/dataprotection/向应用提供对密钥保管库的解包密钥包装密钥权限。

ProtectKeysWithAzureKeyVault 重载:

PersistKeysToFileSystemPersistKeysToFileSystem

若要将密钥存储在 UNC 共享上,而不是存储在 % LOCALAPPDATA% 默认位置,请使用PersistKeysToFileSystem配置系统:

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddDataProtection()
  4. .PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"));
  5. }

警告

如果更改密钥持久性位置,系统将不再自动加密静态密钥,因为它不知道 DPAPI 是否为适当的加密机制。

ProtectKeysWithProtectKeysWith

可以通过调用ProtectKeysWith*配置 api,将系统配置为保护静态密钥。请考虑以下示例,该示例将密钥存储在 UNC 共享上,并使用特定的 x.509 证书对静态密钥进行加密:

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddDataProtection()
  4. .PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
  5. .ProtectKeysWithCertificate("thumbprint");
  6. }

在 ASP.NET Core 2.1 或更高版本中,你可以提供ProtectKeysWithCertificateX509Certificate2 ,例如从文件中加载的证书:

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddDataProtection()
  4. .PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
  5. .ProtectKeysWithCertificate(
  6. new X509Certificate2("certificate.pfx", "password"));
  7. }

有关内置密钥加密机制的更多示例和讨论,请参阅静态密钥加密

UnprotectKeysWithAnyCertificateUnprotectKeysWithAnyCertificate

在 ASP.NET Core 2.1 或更高版本中,你可以使用UnprotectKeysWithAnyCertificateX509Certificate2

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddDataProtection()
  4. .PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
  5. .ProtectKeysWithCertificate(
  6. new X509Certificate2("certificate.pfx", "password"));
  7. .UnprotectKeysWithAnyCertificate(
  8. new X509Certificate2("certificate_old_1.pfx", "password_1"),
  9. new X509Certificate2("certificate_old_2.pfx", "password_2"));
  10. }

SetDefaultKeyLifetimeSetDefaultKeyLifetime

若要将系统配置为使用14天的密钥生存期而不是默认的90天,请使用SetDefaultKeyLifetime

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddDataProtection()
  4. .SetDefaultKeyLifetime(TimeSpan.FromDays(14));
  5. }

SetApplicationNameSetApplicationName

默认情况下,数据保护系统基于其内容根路径将应用彼此隔离,即使它们共享相同的物理密钥存储库。这可防止应用了解彼此的受保护负载。

在应用之间共享受保护的负载:

  • 用相同的值在每个应用中配置 SetApplicationName
  • 在应用程序中使用相同版本的数据保护 API 堆栈。在应用的项目文件中执行以下任一操作:
  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddDataProtection()
  4. .SetApplicationName("shared app name");
  5. }

DisableAutomaticKeyGenerationDisableAutomaticKeyGeneration

您可能会遇到这样的情况:不希望应用程序在接近过期时自动滚动更新密钥(创建新的密钥)。这种情况的一个示例可能是在主/辅助关系中设置的应用,其中只有主应用负责密钥管理问题,辅助应用只是具有密钥环的只读视图。可以通过使用 DisableAutomaticKeyGeneration配置系统,将辅助应用配置为将密钥环视为只读:

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.AddDataProtection()
  4. .DisableAutomaticKeyGeneration();
  5. }

每应用程序隔离Per-application isolation

数据保护系统提供了 ASP.NET Core 主机,但它自动隔离了从另一个,应用程序,即使这些应用在相同的工作进程帐户下运行,并且使用相同的主密钥材料。这有点类似于 IsolateApps 的 <machineKey> 元素中的修饰符。

隔离机制的工作原理是将本地计算机上的每个应用视为唯一的租户,因此,任何给定应用的根 IDataProtector 会自动将应用 ID 包含为鉴别器。应用的唯一 ID 是应用的物理路径:

  • 对于在 IIS 中托管的应用,唯一 ID 是应用的 IIS 物理路径。如果在 web 场环境中部署了应用,则此值是稳定的,假定在 web 场中的所有计算机上配置了类似的 IIS 环境。
  • 对于在Kestrel 服务器上运行的自承载应用程序,唯一 ID 是指向磁盘上的应用程序的物理路径。

唯一标识符的设计目的是在每个应用程序和计算机本身—重置。

此隔离机制假定应用不是恶意的。恶意应用始终会影响在同一工作进程帐户下运行的任何其他应用。在应用不受信任的共享主机环境中,托管提供商应采取措施来确保应用之间的操作系统级隔离,包括分离应用程序的底层密钥存储库。

如果数据保护系统不是由 ASP.NET Core 主机提供的(例如,如果通过 DataProtectionProvider 具体类型对其进行实例化),则默认情况下禁用应用程序隔离。禁用应用隔离后,只要提供相应的用途,同一密钥材料支持的所有应用就可以共享有效负载。若要在此环境中提供应用隔离,请对配置对象调用SetApplicationName方法,并为每个应用提供唯一的名称。

用 UseCryptographicAlgorithms 更改算法Changing algorithms with UseCryptographicAlgorithms

数据保护堆栈允许您更改新生成的密钥使用的默认算法。执行此操作的最简单方法是从配置回调调用UseCryptographicAlgorithms

  1. services.AddDataProtection()
  2. .UseCryptographicAlgorithms(
  3. new AuthenticatedEncryptorConfiguration()
  4. {
  5. EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
  6. ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
  7. });
  1. services.AddDataProtection()
  2. .UseCryptographicAlgorithms(
  3. new AuthenticatedEncryptionSettings()
  4. {
  5. EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
  6. ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
  7. });

默认 EncryptionAlgorithm 为 AES-256-CBC,默认 ValidationAlgorithm 为 HMACSHA256。系统管理员可以通过计算机范围的策略设置默认策略,但对 UseCryptographicAlgorithms 的显式调用会替代默认策略。

通过调用 UseCryptographicAlgorithms,可以从预定义的内置列表中指定所需的算法。您无需担心算法的实现。在上述方案中,如果在 Windows 上运行,数据保护系统将尝试使用 AES 的 CNG 实现。否则,它会回退到托管的系统。

可以通过调用UseCustomCryptographicAlgorithms手动指定实现。

提示

更改算法不会影响密钥环中的现有密钥。它仅影响新生成的键。

指定自定义托管算法Specifying custom managed algorithms

若要指定自定义托管算法,请创建一个指向实现类型的ManagedAuthenticatedEncryptorConfiguration实例:

  1. serviceCollection.AddDataProtection()
  2. .UseCustomCryptographicAlgorithms(
  3. new ManagedAuthenticatedEncryptorConfiguration()
  4. {
  5. // A type that subclasses SymmetricAlgorithm
  6. EncryptionAlgorithmType = typeof(Aes),
  7. // Specified in bits
  8. EncryptionAlgorithmKeySize = 256,
  9. // A type that subclasses KeyedHashAlgorithm
  10. ValidationAlgorithmType = typeof(HMACSHA256)
  11. });

若要指定自定义托管算法,请创建一个指向实现类型的ManagedAuthenticatedEncryptionSettings实例:

  1. serviceCollection.AddDataProtection()
  2. .UseCustomCryptographicAlgorithms(
  3. new ManagedAuthenticatedEncryptionSettings()
  4. {
  5. // A type that subclasses SymmetricAlgorithm
  6. EncryptionAlgorithmType = typeof(Aes),
  7. // Specified in bits
  8. EncryptionAlgorithmKeySize = 256,
  9. // A type that subclasses KeyedHashAlgorithm
  10. ValidationAlgorithmType = typeof(HMACSHA256)
  11. });

通常,*类型属性必须指向system.security.cryptography.symmetricalgorithmKeyedHashAlgorithm的具体实例实例(通过公共无参数的 ctor)实现,尽管系统特别适用于一些值(如 typeof(Aes))以方便使用。

备注

System.security.cryptography.symmetricalgorithm 必须具有≥128位的密钥长度和≥64位的块大小,并且必须支持 PKCS #7 填充的 CBC 模式加密。KeyedHashAlgorithm 的摘要大小必须为 > = 128 位,并且它必须支持长度等于哈希算法摘要长度的键。KeyedHashAlgorithm 不一定是 HMAC。

指定自定义 Windows CNG 算法Specifying custom Windows CNG algorithms

若要通过 HMAC 验证使用 CBC 模式加密指定自定义 Windows CNG 算法,请创建包含算法信息的CngCbcAuthenticatedEncryptorConfiguration实例:

  1. services.AddDataProtection()
  2. .UseCustomCryptographicAlgorithms(
  3. new CngCbcAuthenticatedEncryptorConfiguration()
  4. {
  5. // Passed to BCryptOpenAlgorithmProvider
  6. EncryptionAlgorithm = "AES",
  7. EncryptionAlgorithmProvider = null,
  8. // Specified in bits
  9. EncryptionAlgorithmKeySize = 256,
  10. // Passed to BCryptOpenAlgorithmProvider
  11. HashAlgorithm = "SHA256",
  12. HashAlgorithmProvider = null
  13. });

若要通过 HMAC 验证使用 CBC 模式加密指定自定义 Windows CNG 算法,请创建包含算法信息的CngCbcAuthenticatedEncryptionSettings实例:

  1. services.AddDataProtection()
  2. .UseCustomCryptographicAlgorithms(
  3. new CngCbcAuthenticatedEncryptionSettings()
  4. {
  5. // Passed to BCryptOpenAlgorithmProvider
  6. EncryptionAlgorithm = "AES",
  7. EncryptionAlgorithmProvider = null,
  8. // Specified in bits
  9. EncryptionAlgorithmKeySize = 256,
  10. // Passed to BCryptOpenAlgorithmProvider
  11. HashAlgorithm = "SHA256",
  12. HashAlgorithmProvider = null
  13. });

备注

对称块加密算法的密钥长度必须为 > = 128 位,块大小为 > = 64 位,并且它必须支持 PKCS #7 填充的 CBC 模式加密。哈希算法的摘要大小必须为 > = 128 位,并且必须支持使用 BCRYPTALG处理HMAC标志标志打开。*提供程序属性可以设置为 null,以将默认提供程序用于指定的算法。有关详细信息,请参阅BCryptOpenAlgorithmProvider.aspx)文档。

若要使用 Galois/Counter 模式加密和验证来指定自定义 Windows CNG 算法,请创建包含算法信息的CngGcmAuthenticatedEncryptorConfiguration实例:

  1. services.AddDataProtection()
  2. .UseCustomCryptographicAlgorithms(
  3. new CngGcmAuthenticatedEncryptorConfiguration()
  4. {
  5. // Passed to BCryptOpenAlgorithmProvider
  6. EncryptionAlgorithm = "AES",
  7. EncryptionAlgorithmProvider = null,
  8. // Specified in bits
  9. EncryptionAlgorithmKeySize = 256
  10. });

若要使用 Galois/Counter 模式加密和验证来指定自定义 Windows CNG 算法,请创建包含算法信息的CngGcmAuthenticatedEncryptionSettings实例:

  1. services.AddDataProtection()
  2. .UseCustomCryptographicAlgorithms(
  3. new CngGcmAuthenticatedEncryptionSettings()
  4. {
  5. // Passed to BCryptOpenAlgorithmProvider
  6. EncryptionAlgorithm = "AES",
  7. EncryptionAlgorithmProvider = null,
  8. // Specified in bits
  9. EncryptionAlgorithmKeySize = 256
  10. });

备注

对称块密码算法的密钥长度必须为 > = 128 位,块大小正好为128位,并且必须支持 GCM 加密。可以将EncryptionAlgorithmProvider属性设置为 null,以将默认提供程序用于指定的算法。有关详细信息,请参阅BCryptOpenAlgorithmProvider.aspx)文档。

指定其他自定义算法Specifying other custom algorithms

尽管不是作为第一类 API 公开的,但数据保护系统的扩展能力足以允许指定几乎任何类型的算法。例如,可以保留硬件安全模块(HSM)中包含的所有密钥,并提供核心加密和解密例程的自定义实现。有关详细信息,请参阅核心加密扩展性中的IAuthenticatedEncryptor

在 Docker 容器中托管时保持密钥Persisting keys when hosting in a Docker container

Docker容器中托管时,应在以下任一项中维护密钥:

  • 一个文件夹,它是在容器的生存期之外保留的 Docker 卷,如共享卷或主机装入的卷。
  • 外部提供程序,如Azure Key VaultRedis

通过 Redis 保持密钥Persisting keys with Redis

只应使用支持Redis 数据暂留的 Redis 版本来存储密钥。Azure Blob 存储是持久性的,可用于存储密钥。有关详细信息,请参阅此 GitHub 问题

其他资源Additional resources