API
ASP.NET Core Data Protectio
主要对普通开发人员提供了两个接口,IDataProtectionProvider
和 IDataProtector
namespace Microsoft.AspNetCore.DataProtection
{
//
// 摘要:
// An interface that can provide data protection services.
public interface IDataProtector : IDataProtectionProvider
{
byte[] Protect(byte[] plaintext);
byte[] Unprotect(byte[] protectedData);
}
}
IDataProtector
继承自IDataProtectionProvider
,并且提供了两个方法 Protect
和 Unprotect
。从命名来看,一个是加密,一个是解密
IDataProtectionProvider
namespace Microsoft.AspNetCore.DataProtection
{
public interface IDataProtectionProvider
{
IDataProtector CreateProtector(string purpose);
}
}
IDataProtectionProvider
提供了一个方法,通过传入一个 purpose
字符串生成一个IDataProtector
接口对象
CreateProtector
方法签名中的purpose
这个字符串,可以理解为一个标识,指示当前Protector
的用途
使用IDataProtector
的时候,会发现它还有一些扩展方法位于Microsoft.AspNetCore.DataProtection
命名空间下
public static class DataProtectionCommonExtensions
{
public static IDataProtector CreateProtector(this IDataProtectionProvider provider, IEnumerable<string> purposes);
public static IDataProtector CreateProtector(this IDataProtectionProvider provider, string purpose, params string[] subPurposes);
public static IDataProtector GetDataProtector(this IServiceProvider services, IEnumerable<string> purposes);
public static IDataProtector GetDataProtector(this IServiceProvider services, string purpose, params string[] subPurposes);
public static string Protect(this IDataProtector protector, string plaintext);
public static string Unprotect(this IDataProtector protector, string protectedData);
}
可以看到,CreateProtector
还提供了可以传多个purpose
的方法(IEnumerable,params string[]),为什么会有这种需求呢?
其实DataProtector是有层次结构的,再看一下IDataProtector
接口,它自身也实现了IDataProtectionProvider
接口,就是说IDataProtector
自身也可以再创建IDataProtector
。
举个例子:我们在做一个消息通讯的系统,在消息通讯的过程中,需要对用户的会话进行加密,我们使用CreateProtector(“Security.BearerToken”)加密。但是加密的时候并不能保证消息是不受信任的客户端发过来的,所以想到了CreateProtector(“username”)来进行加密,这个时候假如有一个用户的用户名叫“Security.BearerToken”,那么就和另外一个使用Security.BearerToken作为标示的 Protector 冲突了,所以可以使用CreateProtector([ “Security.BearerToken”, “User: username” ])这种方式。它相当于provider.CreateProtector(“Security.BearerToken).CreateProtector(“User: username”)
。 意思就是先创建一个Protector叫“Security.BearerToken”,然后再在purpose1下创建一个名为“User: username”的Protector。
用户密码哈希
在Microsoft.AspNetCore.Cryptography.KeyDerivation
命名空间下提供了一个KeyDerivation.Pbkdf2
方法用来对用户密码进行哈希
生命周期限制
有些时候,需要一些具有过期或者到期时间的加密字符串,比如用户在找回密码的时候,向用户的邮箱发送一封带有重置命令的一封邮件,这个重置命令就需要有一个过期时间了,超过这个过期时间后就失效,在以前可能需要向数据库存储一个时间来标记发送时间,然后再解密对比和数据库的时间差来验证
现在不用了,ASP.NET Core
默认提供了一个接口叫 ITimeLimitedDataProtector
CreateProtector(string purpose) : ITimeLimitedDataProtector This API is similar to the existing IDataProtectionProvider.CreateProtector in that it can be used to create purpose chains from a root time-limited protector.
Protect(byte[] plaintext, DateTimeOffset expiration) : byte[]
Protect(byte[] plaintext, TimeSpan lifetime) : byte[]
Protect(byte[] plaintext) : byte[]
Protect(string plaintext, DateTimeOffset expiration) : string
Protect(string plaintext, TimeSpan lifetime) : string
Protect(string plaintext) : string
ITimeLimitedDataProtector
提供了数个重载方法用来设定带有生命周期的加密方法,用户可以通过Date TimeOffset
,TimeSpan
等参数来设置时间。
有对应的加密,就有相对应的解密方法,在这里就不详细介绍了。有兴趣的可以去看一下官方文档
配置数据保护
在ASP.NET Core
运行的时候,系统会基于当前机器的运行环境默认配置一些关于Data Protection
的东西,但是有些时候可能需要对这些配置做一些改变
注册服务
通过以下方式来把Data Protection
注册到服务中
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection();
}
指定私钥存储位置
AddDataProtection
返回的是一个 IDataProtectionBuilder
接口,这个接口提供了一个扩展方法PersistKeysToFileSystem()
来存储私钥。可以通过它传入一个路径来指定私钥存储的位置
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"));
}
使用证书加密
可以传入一个共享文件夹,来存储私钥,这样在不同机器的私钥就可以保存到一个位置了。可以通过此种方式在分布式部署的时候,隔离开机器的差异化。如果觉得不安全,还可以配置一个X.509
证书来进行加密
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
.ProtectKeysWithCertificate("thumbprint");
}
调整默认保存时间
Data Protection
的默认保存时间是90天,可以通过以下方式来修改默认的保存时间
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.SetDefaultKeyLifetime(TimeSpan.FromDays(14));
}
应用程序隔离
默认情况下,即使使用相同的物理密钥库,Data Protection
也会把不同的应用程序隔离开,因为这样可以防止从一个应用程序获取另外一个应用程序的密钥。所以如果是相同的应用程序,可以设置相同的应用程序名称
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.SetApplicationName("my application");
}
禁止自动生成秘钥
有时候需要禁用应用程序生成密钥,或者是说只有一个程序用来生成或者管理密钥,其他程序只是负责读的话,那么可以这样
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.DisableAutomaticKeyGeneration();
}
修改加密算法
可以使用UseCryptographicAlgorithms
方法来修改ASP.NET Core Data Protection
的默认加密算法,如下:
services.AddDataProtection()
.UseCryptographicAlgorithms(new AuthenticatedEncryptionSettings()
{
EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
});