Ily*_*kov 26 security authentication cookies asp.net-core-mvc asp.net-core
让我们考虑一个常见的ASP.NET Core场景.首先我们添加中间件:
public void Configure(IApplicationBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions()
{
AuthenticationScheme = "MyCookie",
CookieName = "MyCookie",
LoginPath = new PathString("/Home/Login/"),
AccessDeniedPath = new PathString("/Home/AccessDenied/"),
AutomaticAuthenticate = true,
AutomaticChallenge = true
});
//...
}
Run Code Online (Sandbox Code Playgroud)
然后序列化一个委托人:
await HttpContext.Authentication.SignInAsync("MyCookie", principal);
Run Code Online (Sandbox Code Playgroud)
在这两次调用之后,加密的cookie将存储在客户端.你可以在任何浏览器devtools中看到cookie(在我的例子中它是分块的):
使用应用程序代码中的cookie不是问题(而不是问题).
我的问题是:如何在应用程序外解密cookie?我想这需要一个私钥,如何获得它?
我检查了文档,发现只有常用词:
这将创建一个加密的cookie并将其添加到当前响应中.调用SignInAsync时,还必须使用配置期间指定的AuthenticationScheme.
在封面下,使用的加密是ASP.NET的数据保护系统.如果您在多台计算机上进行托管,负载平衡或使用Web场,则需要配置数据保护以使用相同的密钥环和应用程序标识符.
那么,是否可以解密身份验证cookie,如果是,如何解密?
更新#1: 根据Ron C 的回答和评论,我最终得到了代码:
public class Startup
{
//constructor is omitted...
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection().PersistKeysToFileSystem(
new DirectoryInfo(@"C:\temp-keys\"));
services.AddMvc();
}
public void Configure(IApplicationBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions()
{
AuthenticationScheme = "MyCookie",
CookieName = "MyCookie",
LoginPath = new PathString("/Home/Index/"),
AccessDeniedPath = new PathString("/Home/AccessDenied/"),
AutomaticAuthenticate = true,
AutomaticChallenge = true
});
app.UseStaticFiles();
app.UseMvcWithDefaultRoute();
}
}
public class HomeController : Controller
{
public async Task<IActionResult> Index()
{
await HttpContext.Authentication.SignInAsync("MyCookie", new ClaimsPrincipal());
return View();
}
public IActionResult DecryptCookie()
{
var provider = DataProtectionProvider.Create(new DirectoryInfo(@"C:\temp-keys\"));
string cookieValue = HttpContext.Request.Cookies["MyCookie"];
var dataProtector = provider.CreateProtector(
typeof(CookieAuthenticationMiddleware).FullName, "MyCookie", "v2");
UTF8Encoding specialUtf8Encoding = new UTF8Encoding(false, true);
byte[] protectedBytes = Base64UrlTextEncoder.Decode(cookieValue);
byte[] plainBytes = dataProtector.Unprotect(protectedBytes);
string plainText = specialUtf8Encoding.GetString(plainBytes);
return Content(plainText);
}
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,此代码总是在Unprotect方法调用上产生异常
Microsoft.AspNetCore.DataProtection.dll中的CryptographicException:附加信息:有效内容无效.
我在几台机器上测试了这些代码的不同变体而没有正面结果.可能我犯了一个错误,但在哪里?
更新#2:我的错误是DataProtectionProvider尚未设置UseCookieAuthentication.再次感谢@RonC.
Ron*_*n C 28
值得注意的是,您不需要访问密钥来解密身份验证cookie.您只需使用使用IDataProtector 正确目的参数创建的权限和子目的参数.
基于CookieAuthenticationMiddleware源代码https://github.com/aspnet/Security/blob/rel/1.1.1/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAuthenticationMiddleware.cs#L4,看起来你需要传递的目的是typeof(CookieAuthenticationMiddleware).由于他们将额外的参数传递给IDataProtector你,你需要匹配它们.因此,这行代码应该IDataProtector可以用来解密身份验证cookie:
var dataProtector = provider.CreateProtector(typeof(CookieAuthenticationMiddleware).FullName, Options.AuthenticationScheme, "v2");
Run Code Online (Sandbox Code Playgroud)
请注意,Options.AuthenticationScheme在这种情况下只是"MyCookie",因为它是Configure在startup.cs文件的方法中设置的.
以下是两种不同方式解密身份验证Cookie的示例操作方法:
public IActionResult DecryptCookie() {
//Get the encrypted cookie value
string cookieValue = HttpContext.Request.Cookies["MyCookie"];
//Get a data protector to use with either approach
var dataProtector = provider.CreateProtector(typeof(CookieAuthenticationMiddleware).FullName, "MyCookie", "v2");
//Get the decrypted cookie as plain text
UTF8Encoding specialUtf8Encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true);
byte[] protectedBytes = Base64UrlTextEncoder.Decode(cookieValue);
byte[] plainBytes = dataProtector.Unprotect(protectedBytes);
string plainText = specialUtf8Encoding.GetString(plainBytes);
//Get the decrypted cookie as a Authentication Ticket
TicketDataFormat ticketDataFormat = new TicketDataFormat(dataProtector);
AuthenticationTicket ticket = ticketDataFormat.Unprotect(cookieValue);
return View();
}
Run Code Online (Sandbox Code Playgroud)
此方法使用被注入的构造函数的IDataProtectionProvider调用provider.
如果要在应用程序之间共享cookie,则可能决定将数据保护密钥保留在目录中.这可以通过将以下内容添加到ConfigureServicesstartup.cs文件的方法来完成:
services.AddDataProtection().PersistKeysToFileSystem(
new DirectoryInfo(@"C:\temp-keys\"));
Run Code Online (Sandbox Code Playgroud)
请小心,因为密钥没有加密,所以由你来保护它们!如果你绝对必须,只将密钥保存到目录中(或者如果你只是想了解系统的工作原理).您还需要指定DataProtectionProvider使用这些密钥的cookie .这可以通过startup.cs类UseCookieAuthentication的Configure方法中的配置来完成,如下所示:
app.UseCookieAuthentication(new CookieAuthenticationOptions() {
DataProtectionProvider = DataProtectionProvider.Create(new DirectoryInfo(@"C:\temp-keys\")),
AuthenticationScheme = "MyCookie",
CookieName = "MyCookie",
LoginPath = new PathString("/Home/Login"),
AccessDeniedPath = new PathString("/Home/AccessDenied"),
AutomaticAuthenticate = true,
AutomaticChallenge = true
});
Run Code Online (Sandbox Code Playgroud)
完成配置.您现在可以使用以下代码解密身份验证cookie:
public IActionResult DecryptCookie() {
ViewData["Message"] = "This is the decrypt page";
var user = HttpContext.User; //User will be set to the ClaimsPrincipal
//Get the encrypted cookie value
string cookieValue = HttpContext.Request.Cookies["MyCookie"];
var provider = DataProtectionProvider.Create(new DirectoryInfo(@"C:\temp-keys\"));
//Get a data protector to use with either approach
var dataProtector = provider.CreateProtector(typeof(CookieAuthenticationMiddleware).FullName, "MyCookie", "v2");
//Get the decrypted cookie as plain text
UTF8Encoding specialUtf8Encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true);
byte[] protectedBytes = Base64UrlTextEncoder.Decode(cookieValue);
byte[] plainBytes = dataProtector.Unprotect(protectedBytes);
string plainText = specialUtf8Encoding.GetString(plainBytes);
//Get teh decrypted cookies as a Authentication Ticket
TicketDataFormat ticketDataFormat = new TicketDataFormat(dataProtector);
AuthenticationTicket ticket = ticketDataFormat.Unprotect(cookieValue);
return View();
}
Run Code Online (Sandbox Code Playgroud)
您可以在此处了解有关后一种情况的更多信息:https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/compatibility/cookie-sharing
Ale*_*lex 25
在 ASP.NET Core 应用程序中,您可以只使用CookieAuthenticationOptions.TicketDataFormat.Unprotect(cookieValue).
在这里,我编写了一个简单的静态(!)方法:
public static AuthenticationTicket DecryptAuthCookie(HttpContext httpContext)
{
// ONE - grab the CookieAuthenticationOptions instance
var opt = httpContext.RequestServices
.GetRequiredService<IOptionsMonitor<CookieAuthenticationOptions>>()
.Get(CookieAuthenticationDefaults.AuthenticationScheme); //or use .Get("Cookies")
// TWO - Get the encrypted cookie value
var cookie = opt.CookieManager.GetRequestCookie(httpContext, opt.Cookie.Name);
// THREE - decrypt it
return opt.TicketDataFormat.Unprotect(cookie);
}
Run Code Online (Sandbox Code Playgroud)
在 .NET 5 和 .NET 6 下运行良好。
我添加这个答案以供参考,因为如果您搜索如何手动解密 ASP.NET auth cookie,每个搜索引擎都会弹出这个问题。
请参见下面的.NET Core 2帮助程序方法,以从Cookie中获取声明:
private IEnumerable<Claim> GetClaimFromCookie(HttpContext httpContext, string cookieName, string cookieSchema)
{
// Get the encrypted cookie value
var opt = httpContext.RequestServices.GetRequiredService<IOptionsMonitor<CookieAuthenticationOptions>>();
var cookie = opt.CurrentValue.CookieManager.GetRequestCookie(httpContext, cookieName);
// Decrypt if found
if (!string.IsNullOrEmpty(cookie))
{
var dataProtector = opt.CurrentValue.DataProtectionProvider.CreateProtector("Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware", cookieSchema, "v2");
var ticketDataFormat = new TicketDataFormat(dataProtector);
var ticket = ticketDataFormat.Unprotect(cookie);
return ticket.Principal.Claims;
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
正如@Cirem所指出的那样,创建保护程序的狡猾方法正是Microsoft的操作方式(请参阅此处的代码)。因此,它可能会在将来的版本中更改。
ASP.NET Core 2.2 的另一个变体:
var cookieManager = new ChunkingCookieManager();
var cookie = cookieManager.GetRequestCookie(HttpContext, ".AspNetCore.Identity.Application");
var dataProtector = dataProtectionProvider.CreateProtector("Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware", "Identity.Application", "v2");
//Get the decrypted cookie as plain text
UTF8Encoding specialUtf8Encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true);
byte[] protectedBytes = Base64UrlTextEncoder.Decode(cookie);
byte[] plainBytes = dataProtector.Unprotect(protectedBytes);
string plainText = specialUtf8Encoding.GetString(plainBytes);
//Get teh decrypted cookies as a Authentication Ticket
TicketDataFormat ticketDataFormat = new TicketDataFormat(dataProtector);
AuthenticationTicket ticket = ticketDataFormat.Unprotect(cookie);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
17835 次 |
| 最近记录: |