Let's consider a common-known ASP.NET Core scenario. Firstly we add the middleware:
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
});
//...
}
Then serialize a principal:
await HttpContext.Authentication.SignInAsync("MyCookie", principal);
After these two calls an encrypted cookie will be stored at the client side. You can see the cookie (in my case it was chunked) in any browser devtools:
It's not a problem (and not a question) to work with cookies from application code.
My question is: how to decrypt the cookie outside the application? I guess a private key is needed for that, how to get it?
I checked the docs and found only common words:
This will create an encrypted cookie and add it to the current
response. The AuthenticationScheme specified during configuration must
also be used when calling SignInAsync.Under the covers the encryption used is ASP.NET's Data Protection
system. If you are hosting on multiple machines, load balancing or
using a web farm then you will need to configure data protection to
use the same key ring and application identifier.
So, is it possible to decrypt the authentication cookie, and if so how?
UPDATE #1:
Based on Ron C great answer and comments, I've ended up with code:
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);
}
}
Unfortunately this code always produces exception on Unprotect
method call:
CryptographicException in Microsoft.AspNetCore.DataProtection.dll:
Additional information: The payload was invalid.
I tested different variations of this code on several machines without positive result. Probably I made a mistake, but where?
UPDATE #2: My mistake was the DataProtectionProvider
hasn't been set in UseCookieAuthentication
. Thanks to @RonC again.
Best Answer
Decrypting the Authentication Cookie without needing the keys
It's worth noting that you don't need to gain access to the keys to decrypt the authentication cookie. You simply need to use the right
IDataProtector
created with the right purpose parameter, and subpurpose parameters.Based on the
CookieAuthenticationMiddleware
source code https://github.com/aspnet/Security/blob/rel/1.1.1/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAuthenticationMiddleware.cs#L4 it looks like the purpose you need to pass istypeof(CookieAuthenticationMiddleware)
. And since they are passing additional parameters to theIDataProtector
you will need to match them. So this line of code should get you anIDataProtector
that can be used to decrypt the authentication cookie:Note that
Options.AuthenticationScheme
is just "MyCookie" in this case since that's what it was set to in theConfigure
method of the startup.cs file.Here is an example action method for decrypting your authentication cookie two different ways:
This method uses an
IDataProtectionProvider
calledprovider
that is constructor injected.Decrypting the Authentication Cookie when persisting keys to a directory
If you want to share cookies between applications then you might decide to persist the data protection keys to a directory. This can be done by adding the following to the
ConfigureServices
method of the startup.cs file:BE CAREFUL though because the keys are not encrypted so it's up to you to protect them!!! Only persist the keys to a directory if you absolutely must, (or if you are just trying to understand how the system works). You will also need to specify a cookie
DataProtectionProvider
that uses those keys. This can be done with the help of theUseCookieAuthentication
configuration in theConfigure
method of the startup.cs class like so:With that configuration done. You can now decrypt the authentication cookie with the following code:
You can learn more about this latter scenario here: https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/compatibility/cookie-sharing