前言
事情的起点就在于我在弄ASP .NET Core下的OAuth2.0流程,想要看看具体的Cookie信息有哪些,发现Cookie信息被加密了,检索了一番,发现了解决办法 如何解密Cookie ,然后顺便找了一下原理。
如何解密Cookie
主要代码来源:How to manually decrypt an ASP.NET Core Authentication cookie?
Startup.CongigureServices
里注册的部分代码1
2
3
4
5
6
7
8
9
10
11
12services.AddAuthentication(config =>
{
//当我们登陆后,设置Cookie
config.DefaultSignInScheme = "MyCookieScheme";
//使用作为验证是否登陆
config.DefaultAuthenticateScheme = "MyCookieScheme";
}).AddCookie("MyCookieScheme", options =>
{
//设置密钥存储位置,你也可以使用services.AddDataProtection().PersistKeysToFileSystem(new DirectoryInfo(@"C:\temp-keys2\"))
options.DataProtectionProvider = DataProtectionProvider.Create(new DirectoryInfo(@"C:\temp-keys\"));
options.Cookie.Name = "MyClientCookie"; //默认为:.AspNetCore.Cookies
});解密Cookie
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26[ ]
public IActionResult DecryptCookie()
{
//获得加密了的Cookie值,Cookie名假如注册时候没指定的话为:.AspNetCore.Cookies
string cookieValue = HttpContext.Request.Cookies["MyClientCookie"];
//使用Create方法生成DataProtectionProvider对象,密钥存储位置值与在ConfigureServices注册时一致
var provider = DataProtectionProvider.Create(new DirectoryInfo(@"C:\temp-keys\"));
//获得DataProtector对象,第二个参数的值你在注册Cookies时候设定的Scheme名,没有设定的话其默认值为:Cookies
var dataProtector = provider.CreateProtector("Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware", "MyCookieScheme", "v2");
//解密Cookie值,变为普通文本
byte[] protectedBytes = Base64UrlTextEncoder.Decode(cookieValue);
byte[] plainBytes = dataProtector.Unprotect(protectedBytes);
string plainText = Encoding.UTF8.GetString(plainBytes);
//上面的Encoding.UTF8.GetString不行的话使用下面的
//UTF8Encoding specialUtf8Encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: false);
//string plainText = specialUtf8Encoding.GetString(plainBytes);
//或解密Cookie值,转换为AuthenticationTicket对象
TicketDataFormat ticketDataFormat = new TicketDataFormat(dataProtector);
AuthenticationTicket ticket = ticketDataFormat.Unprotect(cookieValue);
return Ok(JsonConvert.SerializeObject(ticket.Properties.Items));
}
注意:
最重要的是设置保存到
C:\temp-keys\
下的私钥文件,有了这文件,你加密的Cookie能被任何人解密。当然你可以不存储到文件,还有其他办法,具体参考:ASP.NET Core 中的密钥存储提供程序
简单说说原理
默认Cookie不加密
当我们直接添加的Cookie默认是不经过加密的。
1 | HttpContext.Response.Cookies.Append("web_nmae","MyWeb"); |
认证(Authentication)使用Cookie认证方案时认证信息加密
1 | //注册 |
我们调用SignIn接口,查看Cookies,就能发现一个Cookie项,其value被加密了。
1 | key: MyClientCookie |
查看HttpContext.SignInAsync源码
然后去找源代码看,最后会发现其中的关键就是CookieAuthenticationHandler.cs
文件下的HandleSignInAsync
方法,我把其简化了贴出来
1 | protected override async Task HandleSignInAsync(ClaimsPrincipal user, AuthenticationProperties? properties) |
可以看到最后的加密的依赖就是 Data Protection
Data Protection
Data Protection 是微软提供的数据保护机制:
为了确保 Web 应用敏感数据的安全存储,该机制提供了一个简单、基于非对称加密改进的、性能良好的、开箱即用的加密 API 用于数据保护。
它不需要开发人员专门学习怎么样管理这些钥(公钥,私钥),系统回自动的选择算法和管理密钥的生命周期。理想情况下开发人员都不应该访问这些钥的原始文件。
结论
当我们 SignIn 时会把认证信息给 Data Protection 加密然后存储到 Cookie。
当我们获得其该 Cookie 进行认证时,该值又会被 Data Protection 给解密,默认该流程不需要用户设置,应用就会自动进行加解密。
关于Data Protection可扩展阅读
ASP.NET Core 数据保护(Data Protection)【上】
ASP.NET Core 数据保护(Data Protection)【中】
官方文档: