对于web,安全是一个永久的话题,所以ASP.NET Core数据保护提供了一个简单,易用的加密API,可以用来保护数据,密钥管理和轮换。
ASP.NET Core的数据保护是根据本机的一个key来生成加密码,然后再用这个key来解密,如果key不一样,解密失败。默认情况下这个key的有效期是90天,当然这个值是可以被改变的。
默认数据保护key存放的位置,C:\Users\用户\AppData\Local\ASP.NET\DataProtection-Keys,如:key-a2b3132b-444b-4cfa-8530-922b7e991cd9.xml,是一个xml文件,里面记录了这个key的一些信息,创建时间,激活时间,过期时间,和加解密数据所用的命名空间,加密方式等信息,如下:
<?xml version="1.0" encoding="utf-8"?> <key id="a2b3132b-444b-4cfa-8530-922b7e991cd9" version="1"> <creationDate>2022-02-10T13:41:14.7492868Z</creationDate> <activationDate>2022-02-10T13:41:14.7421157Z</activationDate> <expirationDate>2022-05-11T13:41:14.7421157Z</expirationDate> <descriptor deserializerType="Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60"> <descriptor> <encryption algorithm="AES_256_CBC" /> <validation algorithm="HMACSHA256" /> <encryptedSecret decryptorType="Microsoft.AspNetCore.DataProtection.XmlEncryption.DpapiXmlDecryptor, Microsoft.AspNetCore.DataProtection, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60" xmlns="http://schemas.asp.net/2015/03/dataProtection"> <encryptedKey xmlns=""> <!-- This key is encrypted with Windows DPAPI. --> <value>AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAAZeuIp6hZUGsfTgUuNoSSAAAAAACAAAAAAAQZgAAAAEAACAAAACpVhXOBzCWDrZmD13HwR6U3qHk7O2Pki1vPEBrtOJlrQAAAAAOgAAAAAIAACAAAAAPc2zwN10L4IVtN7tFsdQV0Cx7giHlNrWI6heArHHFt1ABAAACCCC8BhZwQ32ZZ67nBEi/tZS+HagViuS/xYtlUJOfzkJOmWg28KkBR2vM6Jo1Y1OY/AbIx6EhbGvZUkdL9aeGBy6A0GBS/3VC4/X8KV3sihRPhb1n924slVds0Y9p7J3p6sCLbhvh0ohhBe1pAENr1XkUnd2Ve4JQ0gVVgQ7vFJOonGGXGQ52dzmITzkJLYIqwNtksA31OmJUlJG7KJnrDEofKjQynvj9gXnOVnMpfHNk6v8v96WDlK7n9Ax3o/W238E7FtOVBKTNoIFWwyc40MR25IrkQdtMZ7HrODY1VRL9nuuexbVXq+5mt5QOyVgvZ1RK0sCwaBB3FSHwKmjskk+WpHXZpi3hjLx82F1gCpatSma01zDEDte0LZHRG9pVYgUXRwUaXX3G0uPuI2mXNpN57qIGZhCJC37cACIzJQ5NxuS+n9Rs6SjVykn78LBAAAAAkxOreUFzysrk5EeldARfOulsq/9OT2w/AFU9sRvPWgZPOieKcdAfIuNF09FgcyquX6IcNuydPn46Uy+saHia0w==</value> </encryptedKey> </encryptedSecret> </descriptor> </descriptor> </key>
使用数据保护的代码也很简单,注入DataProtection服务就可以,只需要使用服务时,通过IDataProtectionProvider创建一个数据保护对象,在创建时可以添加目标字符串参数,来防隔离不同的目标字符串加密的数据,所以key和这个目标字符串都能起到隔离作用。
using Microsoft.AspNetCore.DataProtection; var builder = WebApplication.CreateBuilder(args); //通过SetDefaultKeyLifetime更改默认值90天 builder.Services.AddDataProtection().SetDefaultKeyLifetime(TimeSpan.FromDays(10)); var app = builder.Build(); app.MapGet("/encrypt/{str}", (IDataProtectionProvider provider, ILogger<Program> logger, string str) => { var protector = provider.CreateProtector("a.b.c"); var sec = protector.Protect(str); logger.LogInformation(sec); return "加密:" + sec; }); app.MapGet("/decrypt/{sec}", (IDataProtectionProvider provider, ILogger<Program> logger, string sec) => { var protector = provider.CreateProtector("a.b.c"); var str = protector.Unprotect(sec); logger.LogInformation(str); return "解密:" + str; }); app.Run();
上面代码只是实现了单机部署,如果集群部署,比如k8s中的不同pod,生成的key分别保存在自己的pod里,那么外部访问又是随机分配的,这时就会频繁出现解密失败的情况,这就要集中管理key了,用redis或数据库都可以,这里用到的是SqlServer,首先创建存key的表,如下:
CREATE TABLE [dbo].[DataProtectionKeys1]( [ID] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY , [FriendlyName] [varchar](64) NULL, [Xml] [text] NULL )
当有key保存进来时的结果如下:
其中字段key存的值如下,与本地文件存储的是一样的。
<key id="a32def14-9156-4c5e-946c-d3aa5b1a1743" version="1"> <creationDate>2022-02-10T14:20:37.5680295Z</creationDate> <activationDate>2022-02-10T14:20:36.5853181Z</activationDate> <expirationDate>2022-05-11T14:20:36.5853181Z</expirationDate> <descriptor deserializerType="Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60"> <descriptor> <encryption algorithm="AES_256_CBC"/> <validation algorithm="HMACSHA256"/> <masterKey xmlns:p4="http://schemas.asp.net/2015/03/dataProtection" p4:requiresEncryption="true"> <!-- Warning: the key below is in an unencrypted form. --> <value>gO70+leJQM8NJopS5VmMy+qkz0j+I9diBoCnxkqGxpqdXmyTULgAhMyu+3S4SJ0vjsx8Hxc+d/ipUgDBnkuQNw==</value> </masterKey> </descriptor> </descriptor> </key>
这时,代码需要支持EF,所以引入如下NuGet包
Microsoft.AspNetCore.DataProtection
Microsoft.AspNetCore.DataProtection.EntityFrameworkCore
Microsoft.EntityFrameworkCore
Microsoft.EntityFrameworkCore.SqlServer
代码要换成EF方式持久化key,要注入EF的Context,然后注入数据保护对象时指明持久化的方式:
using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; var builder = WebApplication.CreateBuilder(args); builder.Services.AddDbContext<DataProtContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DataProtDB"))); builder.Services.AddDataProtection().PersistKeysToDbContext<DataProtContext>(); var app = builder.Build(); app.MapGet("/encrypt/{str}", (IDataProtectionProvider provider, ILogger<Program> logger, string str) => { var protector = provider.CreateProtector("a.b.c"); var sec = protector.Protect(str); logger.LogInformation(sec); return "加密:" + sec; }); app.MapGet("/decrypt/{sec}", (IDataProtectionProvider provider, ILogger<Program> logger, string sec) => { var protector = provider.CreateProtector("a.b.c"); var str = protector.Unprotect(sec); logger.LogInformation(str); return "解密:" + str; }); app.Run(); class DataProtContext : DbContext, IDataProtectionKeyContext { public DbSet<DataProtectionKey> DataProtectionKeys { get; set; } public DataProtContext(DbContextOptions<DataProtContext> options) : base(options) {} }
加密结果:
解密结果:
如果生成的加密串需要时效性,需要把生成的Protector转成TimeLimitedDataProtector来加解密,如下:
…… app.MapGet("/encrypt/{str}", (IDataProtectionProvider provider, ILogger<Program> logger, string str) => { var protector = provider.CreateProtector("a.b.c"); var sec = protector.ToTimeLimitedDataProtector().Protect(str, TimeSpan.FromSeconds(30)); logger.LogInformation(sec); return "加密:" + sec; }); app.MapGet("/decrypt/{sec}", (IDataProtectionProvider provider, ILogger<Program> logger, string sec) => { var protector = provider.CreateProtector("a.b.c"); var str = protector.ToTimeLimitedDataProtector().Unprotect(sec); logger.LogInformation(str); return "解密:" + str; }); ……
如果加密串过期提交,报错如下:
想要更快更方便的了解相关知识,可以关注微信公众号
标签:MiniAPI,key,sec,数据保护,str,provider,var,NET6,logger From: https://www.cnblogs.com/ljknlb/p/16930472.html