如何手动解密ASP.NET Core身份验证Cookie? [英] How to manually decrypt an ASP.NET Core Authentication cookie?

查看:91
本文介绍了如何手动解密ASP.NET Core身份验证Cookie?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

让我们考虑一个众所周知的ASP.NET Core方案.首先,我们添加中间件:

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
    });
    //...
}

然后序列化主体:

await HttpContext.Authentication.SignInAsync("MyCookie", principal);

这两个调用之后,加密的cookie将存储在客户端.您可以在任何浏览器devtools中看到cookie(在我的情况下是分块的):

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:

使用应用程序代码中的cookie没问题(也不是问题).

It's not a problem (and not a question) to work with cookies from application code.

我的问题是:如何在应用程序外部解密cookie ?我想为此需要一个私钥,如何获取它?

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:

这将创建一个加密的cookie并将其添加到当前 回复.配置期间指定的AuthenticationScheme必须 调用SignInAsync时也可以使用.

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.

幕后使用的加密是ASP.NET的数据保护 系统.如果您托管在多台计算机上,请进行负载平衡或 使用Web场,则需要将数据保护配置为 使用相同的钥匙圈和应用程序标识符.

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.

那么,是否可以解密身份验证cookie,如果可以,如何解密?

So, is it possible to decrypt the authentication cookie, and if so how?

更新#1: 基于罗恩C 很好的回答和评论,我最终得到了代码:

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);
    }
}

不幸的是,这段代码总是在Unprotect方法调用上产生异常:

Unfortunately this code always produces exception on Unprotect method call:

Microsoft.AspNetCore.DataProtection.dll中的

CryptographicException: 附加信息:有效负载无效.

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?

更新#2:我的错误是在UseCookieAuthentication中未设置DataProtectionProvider.再次感谢@RonC.

UPDATE #2: My mistake was the DataProtectionProvider hasn't been set in UseCookieAuthentication. Thanks to @RonC again.

推荐答案

解密身份验证Cookie,而无需密钥

值得注意的是,您不需要访问密钥即可解密身份验证cookie.您只需要使用通过正确的用途参数和子用途参数创建的正确的IDataProtector.

基于CookieAuthenticationMiddleware源代码

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 is typeof(CookieAuthenticationMiddleware). And since they are passing additional parameters to the IDataProtector you will need to match them. So this line of code should get you an IDataProtector that can be used to decrypt the authentication cookie:

var dataProtector = provider.CreateProtector(typeof(CookieAuthenticationMiddleware).FullName, Options.AuthenticationScheme, "v2");

请注意,在这种情况下,Options.AuthenticationScheme只是"MyCookie",因为这是在startup.cs文件的Configure方法中设置的.

Note thatOptions.AuthenticationScheme is just "MyCookie" in this case since that's what it was set to in the Configure method of the startup.cs file.

以下是用于以两种不同方式解密身份验证cookie的示例操作方法:

Here is an example action method for decrypting your authentication cookie two different ways:

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();
}

此方法使用称为providerIDataProtectionProvider,该IDataProtectionProvider是构造函数注入的.


This method uses an IDataProtectionProvider called provider that is constructor injected.


如果要在应用程序之间共享cookie,则可以决定将数据保护密钥保留在目录中.这可以通过将以下内容添加到startup.cs文件的ConfigureServices方法中来完成:

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:

services.AddDataProtection().PersistKeysToFileSystem(
        new DirectoryInfo(@"C:\temp-keys\")); 

请小心,因为密钥未加密,因此您有责任保护它们!!!仅在绝对必要时(或如果您只是想了解系统的工作方式),才将键保留在目录中.您还 需要指定使用这些键的cookie DataProtectionProvider.可以借助startup.cs类的Configure方法中的UseCookieAuthentication配置来完成,如下所示:

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 the UseCookieAuthentication configuration in the Configure method of the startup.cs class like so:

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
    });

完成该配置.现在,您可以使用以下代码解密身份验证Cookie:

With that configuration done. You can now decrypt the authentication cookie with the following code:

 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();
    }

您可以在此处了解有关后一种情况的更多信息: https://docs.microsoft.com/zh-CN/aspnet/core/security/data-protection/compatibility/cookie共享

You can learn more about this latter scenario here: https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/compatibility/cookie-sharing

这篇关于如何手动解密ASP.NET Core身份验证Cookie?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆