Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC6 Decrypting a forms authentication cookie from another website

I have a webforms website that is calling into a new MVC6 website that we are working on. The user will login as they always have done on the webforms website using forms authentication and then get redirected to the new MVC6 website. I know in MVC6 that I should be using Cookie Authentication but cannot get it to decrypt the cookie. I suspect its down to changes around web.config and machinekey but am really stuck.

Here is what I have done.

I have set up cookie authentication as follows

        app.UseCookieAuthentication(options =>
        {
            options.CookieName = "MyWebformsCookie";
            options.AutomaticAuthenticate = true;
            options.AuthenticationScheme = "Cookies";
            options.TicketDataFormat = new MySecureDataFormat();
            options.DataProtectionProvider = new MyDataProtectionProvider();
            //options.CookieDomain = "localhost";
        });

The class is as follows

public class MySecureDataFormat : ISecureDataFormat<AuthenticationTicket>
{
    public string Protect(AuthenticationTicket data)
    {
        return string.Empty;
    }

    public string Protect(AuthenticationTicket data, string purpose)
    {
        return string.Empty;
    }

    public AuthenticationTicket Unprotect(string protectedText)
    {
        return null;
    }

    public AuthenticationTicket Unprotect(string protectedText, string purpose)
    {
        var ticket = FormsAuthentication.Decrypt(protectedText);
        return null;
    }
}

The cookie is being read, and the Unprotect method called, but then it errors on the FormsAuthentication.Decrypt method with error

An exception of type 'System.Web.HttpException' occurred in System.Web.dll but was not handled in user code

Additional information: Unable to validate data.

Stack = at System.Web.Configuration.MachineKeySection.EncryptOrDecryptData(Boolean fEncrypt, Byte[] buf, Byte[] modifier, Int32 start, Int32 length, Boolean useValidationSymAlgo, Boolean useLegacyMode, IVType ivType, Boolean signData) at System.Web.Security.FormsAuthentication.Decrypt(String encryptedTicket) at WebApplication.Mvc.MySecureDataFormat.Unprotect(String protectedText, String purpose) in C:\SVNCode\GlobalConnectV2\WebApplication.Mvc\Startup.cs:line 153
at Microsoft.AspNet.Authentication.Cookies.CookieAuthenticationHandler.d__9.MoveNext()

So this leads me to believe that its not reading machine key. I have this in the web.config in wwwroot folder

<configuration>
  <system.webServer>
    ...
  </system.webServer>
  <system.web>
    <machineKey compatibilityMode="Framework20SP2" validation="SHA1" decryption="AES" validationKey="mykey" decryptionKey="dec" />
  </system.web>
</configuration>

This works on earlier MVC apps but guessing something changed in MVC6. I have also tried the following but no luck

    services.ConfigureDataProtection(configure =>
    {
        configure.UseCryptographicAlgorithms(new Microsoft.AspNet.DataProtection.AuthenticatedEncryption.AuthenticatedEncryptionOptions()
        {
            EncryptionAlgorithm = Microsoft.AspNet.DataProtection.AuthenticatedEncryption.EncryptionAlgorithm.AES_256_CBC,
            ValidationAlgorithm = Microsoft.AspNet.DataProtection.AuthenticatedEncryption.ValidationAlgorithm.HMACSHA256
        });

    });

Any advice?

like image 391
Punchmeister Avatar asked Dec 14 '15 10:12

Punchmeister


People also ask

How do you decrypt cookies?

Decrypt the cookie and check the digest: Decrypt de key of the cookie: do Base64 decoding, then decrypt it using your institution's private RSA key. Decrypt the data using the decrypted AES key. Check the digest using secutix public certificate. The following example in java will show you how to proceed.

How to check form authentication cookie?

The ASPXAUTH cookie is used to determine if a user is authenticated. As far as the location of the cookie, that depends on your browser. If you are using Firefox you can view the cookie by clicking on Tools -> Options -> Privacy. Then scroll down to the domain and expand it to see the cookie and its value.

What is Aspxauth cookie?

ASPXAUTH in your browser. This is a cookie returned by Forms Authentication once the user is signed in. The value of the cookie contains an encrypted string that can be used to authenticate the user on subsequent requests.

What is the use of Formsauthentication SetAuthCookie?

The forms-authentication ticket supplies forms-authentication information to the next request made by the browser. With forms authentication, you can use the SetAuthCookie method when you want to authenticate a user but still retain control of the navigation with redirects.


1 Answers

I had no joy attempting to use FormsAuthentication.Decrypt() in an ASP.NET 5 application.

In the end I wrote a decryption routine, based on the documentation available, and also looking at reference source code that Microsoft made available for system web.

The classes required to decrypt a forms authentication cookie that uses SHA1 for validation, and AES for encryption, can be found on my GIST here: https://gist.github.com/dazinator/0cdb8e1fbf81d3ed5d44

Once you have these, you can create a custom TicketFormat as before:

public class FormsAuthCookieTicketFormat : ISecureDataFormat<AuthenticationTicket>
{

    private LegacyFormsAuthenticationTicketEncryptor _Encryptor;
    private Sha1HashProvider _HashProvider;

    public FormsAuthCookieTicketFormat(string decryptionKey, string validationKey)
    {
        _Encryptor = new LegacyFormsAuthenticationTicketEncryptor(decryptionKey);
        _HashProvider = new Sha1HashProvider(validationKey);
    }

    public string Protect(AuthenticationTicket data)
    {
        throw new NotImplementedException();            
    }

    public string Protect(AuthenticationTicket data, string purpose)
    {
        throw new NotImplementedException();
    }

    public AuthenticationTicket Unprotect(string protectedText)
    {
        throw new NotImplementedException();
    }

    public AuthenticationTicket Unprotect(string protectedText, string purpose)
    {
        var ticket = _Encryptor.DecryptCookie(protectedText, _HashProvider);

        var identity = new ClaimsIdentity("MyCookie");
        identity.AddClaim(new Claim(ClaimTypes.Name, ticket.Name));
        identity.AddClaim(new Claim(ClaimTypes.IsPersistent, ticket.IsPersistent.ToString()));
        identity.AddClaim(new Claim(ClaimTypes.Expired, ticket.Expired.ToString()));
        identity.AddClaim(new Claim(ClaimTypes.Expiration, ticket.Expiration.ToString()));
        identity.AddClaim(new Claim(ClaimTypes.CookiePath, ticket.CookiePath));
        identity.AddClaim(new Claim(ClaimTypes.Version, ticket.Version.ToString()));           

        // Add some additional properties to the authentication ticket.
        var props = new AuthenticationProperties();
        props.ExpiresUtc = ticket.Expiration.ToUniversalTime();
        props.IsPersistent = ticket.IsPersistent;

        var principal = new ClaimsPrincipal(identity);

        var authTicket = new AuthenticationTicket(principal, props, CookieDetails.AuthenticationScheme);
        return authTicket;
    }

And wire it up like so:

var formsCookieFormat = new FormsAuthCookieTicketFormat(_DecryptionKeyText, _ValidationKeyText);

        app.UseCookieAuthentication(options =>
        {
            // shortened for brevity... 
            options.TicketDataFormat = formsCookieFormat ;
            options.CookieName = "MyCookie";                
        });
like image 113
Darrell Avatar answered Oct 28 '22 05:10

Darrell