ASP.NET Core 中的目标字符串
使用 IDataProtectionProvider
的组件必须将唯一的目标参数传递给 CreateProtector
方法。 目标参数是数据保护系统固有的安全性参数,因为即使根加密密钥相同,它也能在加密使用者之间提供隔离。
当使用者指定目标时,目标字符串与根加密密钥一起用于派生该使用者独有的加密子密钥。 这会将该使用者与应用程序中的所有其他加密使用者隔离开来:其他组件无法读取其有效负载,它也无法读取任何其他组件的有效负载。 这种隔离也可以抵御针对组件的所有攻击类别。
在上图中,IDataProtector
实例 A 和 B 无法读取彼此的有效负载,而只能读取自己的有效负载。
目标字符串不必保密。 它应该是唯一的,因为其他行为良好的组件永远不会提供相同的目标字符串。
提示
对于使用数据保护 API 的组件,使用其命名空间和类型名称是一个很好的经验法则,因为在实践中这些信息永远不会发生冲突。
由 Contoso 创作的负责创建持有者令牌的组件可能使用 Contoso.Security.BearerToken 作为其目标字符串。 甚至可能使用更好的 Contoso.Security.BearerToken.v1 作为其目标字符串。 通过追加版本号,可让将来的版本使用 Contoso.Security.BearerToken.v2 作为其目标,并且就有效负载而言,不同版本将完全相互隔离。
由于 CreateProtector
的目标参数是一个字符串数组,因此可以将上述内容指定为 [ "Contoso.Security.BearerToken", "v1" ]
。 这样可以建立目标层次结构,并为数据保护系统提供多租户方案的可能性。
警告
组件不应允许不受信任的用户输入成为目标链的唯一输入源。
以负责存储安全消息的组件 Contoso.Messaging.SecureMessage 为例。 如果安全消息传递组件要调用 CreateProtector([ username ])
,恶意用户可能会创建一个用户名为“Contoso.Security.BearerToken”的帐户,以试图让组件调用 CreateProtector([ "Contoso.Security.BearerToken" ])
,从而无意中导致安全消息传递系统创建可视为身份验证令牌的有效负载。
对于消息传递组件,CreateProtector([ "Contoso.Messaging.SecureMessage", $"User: {username}" ])
是一种更好的目标链,它可以提供适当的隔离。
IDataProtectionProvider
、IDataProtector
和目标提供的隔离及其行为如下所示:
对于给定的
IDataProtectionProvider
对象,CreateProtector
方法将创建一个IDataProtector
对象,该对象与创建它的IDataProtectionProvider
对象和传递给该方法的目标参数唯一关联。目标参数不能为 null。 (如果将用途指定为数组,这意味着该数组的长度不得为零,并且该数组的所有元素都必须为非 null。)空字符串用途在技术上是允许的,但不鼓励。
当且仅当两个目标参数以相同的顺序包含相同的字符串(使用序号比较器)时,这两个参数才是等效的。 单个目标参数等效于相应的单元素目标数组。
当且仅当从具有等效目标参数的等效
IDataProtectionProvider
对象创建两个IDataProtector
对象时,这两个对象才是等效的。对于给定的
IDataProtector
对象,当且仅当等效IDataProtector
对象符合protectedData := Protect(unprotectedData)
的条件时,对Unprotect(protectedData)
的调用才会返回原始unprotectedData
。
注意
我们没有考虑某些组件故意选择已知与另一个组件冲突的目标字符串的情况。 此类组件本质上会被认为是恶意的,而且此系统并不打算在恶意代码已经在工作进程内运行的情况下提供安全保证。