ASP.NET Core 的密钥管理可扩展性

提示

读取密钥管理然后再阅读本部分中,因为它介绍了这些 Api 的基本概念的某些部分。

警告

实现以下接口的任何类型应该是线程安全的多个调用方。

IKey接口是加密系统中的键的基本表示形式。 在抽象意义上,"加密密钥材料"字面意义上不在此处使用术语该键。 一个键具有以下属性:

  • 激活、 创建和过期日期

  • 吊销状态

  • 密钥标识符 (GUID)

此外,IKey公开CreateEncryptor方法用于创建IAuthenticatedEncryptor实例绑定到此密钥。

此外,IKey公开CreateEncryptorInstance方法用于创建IAuthenticatedEncryptor实例绑定到此密钥。

备注

没有 API 来检索从原始的加密材料IKey实例。

IKeyManager

IKeyManager接口表示负责常规密钥存储、 检索和操作的对象。 它公开三个高级操作:

  • 创建新的密钥,并将其保存到存储。

  • 从存储中获取所有键。

  • 撤消一个或多个密钥并保存到存储吊销信息。

警告

编写IKeyManager是一个非常高级的任务,和大多数开发人员不应尝试。 相反,大多数开发人员应充分利用所提供的功能XmlKeyManager类。

XmlKeyManager

XmlKeyManager类型是内置具体实现IKeyManager 它提供了几个有用的功能,包括密钥托管和静态密钥加密。 在此系统中的密钥都表示为 XML 元素 (具体而言, XElement)。

XmlKeyManager 取决于在完成其任务的过程中的其他几个组件:

  • AlgorithmConfiguration这决定了使用新的密钥的算法。

  • IXmlRepository其中将密钥保存在存储中的控件。

  • IXmlEncryptor [可选],它允许加密静态密钥。

  • IKeyEscrowSink [可选] 提供密钥托管服务。

  • IXmlRepository其中将密钥保存在存储中的控件。

  • IXmlEncryptor [可选],它允许加密静态密钥。

  • IKeyEscrowSink [可选] 提供密钥托管服务。

下面是高级的关系图,指示如何这些组件连接在一起内XmlKeyManager

创建密钥

密钥创建 / CreateNewKey

在实现中的CreateNewKey,则AlgorithmConfiguration组件用于创建唯一IAuthenticatedEncryptorDescriptor,然后序列化为 XML。 如果存在密钥托管接收器,则原始 (未加密) 的 XML 提供到接收器进行长期存储。 未加密的 XML 然后通过运行IXmlEncryptor(如果需要) 来生成加密的 XML 文档。 此加密的文档保存到长期存储通过IXmlRepository (如果没有IXmlEncryptor是配置,未加密的文档保存在IXmlRepository。)

密钥检索

创建密钥

密钥创建 / CreateNewKey

在实现中的CreateNewKey,则IAuthenticatedEncryptorConfiguration组件用于创建唯一IAuthenticatedEncryptorDescriptor,然后序列化为 XML。 如果存在密钥托管接收器,则原始 (未加密) 的 XML 提供到接收器进行长期存储。 未加密的 XML 然后通过运行IXmlEncryptor(如果需要) 来生成加密的 XML 文档。 此加密的文档保存到长期存储通过IXmlRepository (如果没有IXmlEncryptor是配置,未加密的文档保存在IXmlRepository。)

密钥检索

密钥检索 / GetAllKeys

在实现中的GetAllKeys、 XML 文档表示密钥和吊销读取从基础IXmlRepository 如果这些文档进行加密,系统将自动解密机密。 XmlKeyManager 创建适当IAuthenticatedEncryptorDescriptorDeserializer实例进行反序列化文档回IAuthenticatedEncryptorDescriptor实例,然后将封装在单个IKey实例。 此集合的IKey实例返回给调用方。

可在特定的 XML 元素的详细信息密钥存储格式的文档

IXmlRepository

IXmlRepository接口表示可以持久保存到 XML 并从后备存储中检索 XML 的类型。 它公开两个 Api:

  • GetAllElements :IReadOnlyCollection<XElement>

  • StoreElement(XElement element, string friendlyName)

实现IXmlRepository无需分析通过其传递的 XML。 它们应视为不透明的 XML 文档,让较高的层担心如何生成和分析文档。

有四种内置的具体类型实现IXmlRepository:

请参阅密钥存储提供程序文档有关详细信息。

注册的自定义IXmlRepository适合使用不同的后备存储 (例如,Azure 表存储) 时。

若要更改默认存储库应用程序范围,请注册自定义IXmlRepository实例:

services.Configure<KeyManagementOptions>(options => options.XmlRepository = new MyCustomXmlRepository());
services.AddSingleton<IXmlRepository>(new MyCustomXmlRepository());

IXmlEncryptor

IXmlEncryptor接口表示可以加密纯文本 XML 元素的类型。 它公开一个 API:

  • Encrypt(XElement plaintextElement):EncryptedXmlInfo

如果一个序列化IAuthenticatedEncryptorDescriptor包含任何元素标记为"需要加密",然后XmlKeyManager将通过已配置运行这些元素IXmlEncryptorEncrypt方法,并将保存到加密的元素而不是为纯文本元素IXmlRepository 输出Encrypt方法是EncryptedXmlInfo对象。 此对象是包含两个结果到加密的包装XElement表示的类型和IXmlDecryptor这可用于解密的相应元素。

有四种内置的具体类型实现IXmlEncryptor:

请参阅rest 文档在密钥加密有关详细信息。

若要更改默认在静态密钥加密机制整个应用程序范围,请注册自定义IXmlEncryptor实例:

services.Configure<KeyManagementOptions>(options => options.XmlEncryptor = new MyCustomXmlEncryptor());
services.AddSingleton<IXmlEncryptor>(new MyCustomXmlEncryptor());

IXmlDecryptor

IXmlDecryptor接口表示一种类型,知道如何解密XElement的已加密通过IXmlEncryptor 它公开一个 API:

  • Decrypt(XElement encryptedElement) :XElement

Decrypt方法撤消由执行的加密IXmlEncryptor.Encrypt 通常情况下,每个具体IXmlEncryptor实现都将具有相应的具体IXmlDecryptor实现。

类型实现IXmlDecryptor应具有以下两个公共构造函数之一:

  • .ctor(IServiceProvider)
  • .ctor()

备注

IServiceProvider传递给构造函数可能为 null。

IKeyEscrowSink

IKeyEscrowSink接口表示可执行托管的敏感信息的类型。 回想一下,序列化的描述符可能包含敏感信息 (如加密材料),这是什么导致了引入IXmlEncryptor键入第一个位置中。 但是,意外的发生,并且密钥环可以删除或损坏。

托管接口提供了允许访问原始序列化的 XML,通过配置的任何转换前一个紧急应急IXmlEncryptor 该接口公开单个 API:

  • 应用商店 (Guid keyId、 XElement 元素)

这就需要通过IKeyEscrowSink实现来处理提供的元素以安全的方式与业务策略保持一致。 一个可能的实现可能是托管接收器使用的是已知的公司 X.509 证书的 XML 元素进行加密的证书的私钥已托管;CertificateXmlEncryptor可以帮助解决这个问题类型。 IKeyEscrowSink实现程序还负责适当地保留提供的元素。

默认情况下没有托管启用了机制,但服务器管理员可以全局配置此 它还可以配置以编程方式通过IDataProtectionBuilder.AddKeyEscrowSink方法,如下面的示例中所示。 AddKeyEscrowSink方法重载镜像IServiceCollection.AddSingletonIServiceCollection.AddInstance重载,为IKeyEscrowSink实例都应是单一实例。 如果多个IKeyEscrowSink注册实例,每个将调用在密钥生成过程,因此密钥可同时托管多个机制。

没有 API 中读取数据从IKeyEscrowSink实例。 这与托管机制的设计从理论上讲是一致: 它可用于使密钥材料的受信任的颁发机构,并且由于应用程序本身不是受信任的颁发机构,它不应该有权访问其自身托管的材料。

下面的示例代码演示如何创建并注册IKeyEscrowSink密钥托管,以便只有"CONTOSODomain 管理员"的成员可以恢复它们。

备注

若要运行此示例,必须是到已加入域的 Windows 8 / Windows Server 2012 计算机和域控制器必须是 Windows Server 2012 或更高版本。

using System;
using System.IO;
using System.Xml.Linq;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.DataProtection.KeyManagement;
using Microsoft.AspNetCore.DataProtection.XmlEncryption;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

public class Program
{
    public static void Main(string[] args)
    {
        var serviceCollection = new ServiceCollection();
        serviceCollection.AddDataProtection()
            .PersistKeysToFileSystem(new DirectoryInfo(@"c:\temp-keys"))
            .ProtectKeysWithDpapi()
            .AddKeyEscrowSink(sp => new MyKeyEscrowSink(sp));
        var services = serviceCollection.BuildServiceProvider();

        // get a reference to the key manager and force a new key to be generated
        Console.WriteLine("Generating new key...");
        var keyManager = services.GetService<IKeyManager>();
        keyManager.CreateNewKey(
            activationDate: DateTimeOffset.Now,
            expirationDate: DateTimeOffset.Now.AddDays(7));
    }

    // A key escrow sink where keys are escrowed such that they
    // can be read by members of the CONTOSO\Domain Admins group.
    private class MyKeyEscrowSink : IKeyEscrowSink
    {
        private readonly IXmlEncryptor _escrowEncryptor;

        public MyKeyEscrowSink(IServiceProvider services)
        {
            // Assuming I'm on a machine that's a member of the CONTOSO
            // domain, I can use the Domain Admins SID to generate an
            // encrypted payload that only they can read. Sample SID from
            // https://technet.microsoft.com/library/cc778824(v=ws.10).aspx.
            _escrowEncryptor = new DpapiNGXmlEncryptor(
                "SID=S-1-5-21-1004336348-1177238915-682003330-512",
                DpapiNGProtectionDescriptorFlags.None,
                new LoggerFactory());
        }

        public void Store(Guid keyId, XElement element)
        {
            // Encrypt the key element to the escrow encryptor.
            var encryptedXmlInfo = _escrowEncryptor.Encrypt(element);

            // A real implementation would save the escrowed key to a
            // write-only file share or some other stable storage, but
            // in this sample we'll just write it out to the console.
            Console.WriteLine($"Escrowing key {keyId}");
            Console.WriteLine(encryptedXmlInfo.EncryptedElement);

            // Note: We cannot read the escrowed key material ourselves.
            // We need to get a member of CONTOSO\Domain Admins to read
            // it for us in the event we need to recover it.
        }
    }
}

/*
 * SAMPLE OUTPUT
 *
 * Generating new key...
 * Escrowing key 38e74534-c1b8-4b43-aea1-79e856a822e5
 * <encryptedKey>
 *   <!-- This key is encrypted with Windows DPAPI-NG. -->
 *   <!-- Rule: SID=S-1-5-21-1004336348-1177238915-682003330-512 -->
 *   <value>MIIIfAYJKoZIhvcNAQcDoIIIbTCCCGkCAQ...T5rA4g==</value>
 * </encryptedKey>
 */

上一篇:在 ASP.NET Core 中的核心加密可扩展性

下一篇:杂项 ASP.NET Core 数据保护 Api

关注微信小程序
程序员编程王-随时随地学编程

扫描二维码
程序员编程王

扫一扫关注最新编程教程