ASP.NET Core 中的目标层次结构和多租户

由于 IDataProtector 也是隐含的 IDataProtectionProvider,因此可以将目标链接在一起。 从这个意义上来说,provider.CreateProtector([ "purpose1", "purpose2" ]) 等效于 provider.CreateProtector("purpose1").CreateProtector("purpose2")

这允许通过数据保护系统建立一些有趣的层次结构关系。 在之前的 Contoso.Messaging.SecureMessage 示例中,SecureMessage 组件可以预先调用一次 provider.CreateProtector("Contoso.Messaging.SecureMessage"),并将结果缓存到专用 _myProvider 字段中。 将来可以通过调用 _myProvider.CreateProtector("User: username") 来创建保护程序,这些保护程序将用于保护各个消息。

这也可以反过来。 以托管多个租户的单个逻辑应用程序(CMS 看起来很合理)为例,每个租户都可以配置有自己的身份验证和状态管理系统。 伞形应用程序具有一个主提供程序,它调用 provider.CreateProtector("Tenant 1")provider.CreateProtector("Tenant 2"),以在数据保护系统中为每个租户提供其自己的隔离片区。 然后,租户可以根据自己的需要派生各自的保护程序,但无论怎么努力,它们都无法创建与系统中的任何其他租户发生冲突的保护程序。 其图形表示如下。

Multi tenancy purposes

警告

这假定伞形应用程序控制单个租户可用的 API,并且租户不能在服务器上执行任意代码。 如果租户可以执行任意代码,则可以执行专用反射来打破隔离保证,或者可以直接读取主密钥材料并派生所需的任何子密钥。

数据保护系统实际上在其默认的开箱即用配置中使用了某种多租户功能。 默认情况下,主密钥材料存储在工作进程帐户的用户配置文件文件夹(或注册表,用于 IIS 应用程序池标识)中。 但实际上,使用单个帐户运行多个应用程序的情况相当普遍,因此所有这些应用程序最终都会共享主密钥材料。 为了解决此问题,数据保护系统会自动插入每个应用程序唯一的标识符作为整个目标链中的第一个元素。 此隐式目标通过有效地将每个应用程序视为系统中的唯一租户,将各个应用程序相互隔离,并且保护程序创建过程看起来与上图相同。