0

When a user logs in with their email/password combo and gets authenticated to our website, the backend sends the web browser an encrypted cookie based off of their memberId with us. While this encrypted cookie has not expired, the web browser transmits it to the backend, where we can decrypt it and figure out the memberId it is associated with.

We are now in the process of using a more secure encryption/decryption algorithm and now realizing we can't only change the encryption/decryption algorithm, but we may also need to ensure backwards compatibility with the old encryption/decryption algorithm in case there are users of our website that still have cookies in their web browser that were encrypted using the old algorithm.

I have an idea about how do handle this, and I'm hoping to get some feedback from this community. Here is what I think the backend decrypt function should do:

decrypt(cookie) {

   // check if cookie was encrypted using old encryption
   if ( cookie.name == "old_cookie")

      memberId = decryptOld(cookie.value)) // decrypts the value using old scheme
      cookie.name = "new_cookie" // so we know next encrypt will use new scheme

   // cookie was encrypted using new encryption
   else{
      memberId = decryptNew(cookie.value) // decrypts the value using new scheme
   }   

  return memberID;
}

This is what I think the encrypt() function on the backend will look like:

encrypt(cookie) {

   // check if cookie has old name 
   if ( cookie.name == "old_cookie")
      cookie.name = "new_cookie" // so we know next encrypt will use new scheme
      encMemberId = encryptNew(cookie.value)) // encrypts the value using new scheme
      

   // cookie using new name
   else{
      encMemberId = encryptNew(cookie.value) // decrypts the value using new scheme
   }   

  return encMemberID;
}

This way, I am essentially trying to be backwards compatible and allowing for cookies using the old encryption scheme to migrate to using the new encryption scheme. Does this make sense to everyone? Or am I missing something here?

0

1 Answer 1

1

Broadly, the approach makes sense. You should delete (set to expire in the past) any "old_cookie" you receive at the same time you set the new one to move users over as quickly as possible to the newer and (hopefully) more secure system. You should also set a reminder to remove the code that handles the old cookies once there shouldn't be any left, since it increases attack surface on your app/service. You can choose a date to retire the old cookie format that is not too far in the future - maybe a few months after the new one debuts, even if the old cookie doesn't expire for a longer time (e.g. a year) - since anybody who hasn't used the site for months will probably not be shocked to be asked to sign in again, and anybody who did use it will have automatically received the new cookie.


With that said, a few MAJOR caveats about this design:

  1. Why are you encrypting the token (the value you put in the cookie)? Is there anything in it that's secret? If it's just the user's ID in your database, or even just their email address or something, why do you care if they can see that value?
  2. How are you protecting the tokens against modification? Encryption, by itself, does not do that; you need a signature or message authentication code (MAC). There exist "authenticated encryption" schemes that combine encryption with generating a MAC at the same time and using the same key - an integrated "encrypt and MAC" solution such that you can verify authenticity and integrity of the ciphertext at decryption time - but most encryption doesn't do this and a lot of it is vulnerable to trivial bit-flipping attacks which would allow a legitimate user to change their session to that of somebody else.
  3. How are you handling session management? Are you always storing the tokens on the server as well as the client and checking them against the server's list? Or are tokens only stored in cookies, and trusted if they decrypted successfully? In the latter case, do you have any way to revoke tokens (e.g. a list that only holds revoked ones, not active ones, so it's at least shorter) or are they valid until they expire? Given that you seem to have them quite long-lived, irrevocable tokens are a disaster waiting to happen, even if the tokens themselves are secure. For that matter, do the tokens store their own expiration, or are you relying on the browser to expire them for you?
  4. Beyond why you're encrypting or if/how you're ensuring token integrity, what ciphers are you using and how are you using them? Cryptography is hard, and naive attempts usually yield far, far less security than developers expect. The most obviously critical such failing here would be failure to authenticate the ciphertext (see #2) but there are tons of other things one could get wrong.

Finally, consider how secure your site needs to be. How sensitive are the data it contains or the actions it enables? What promises have you made, or regulations are you subject to? Are you aiming for actually high security, or merely having any meaningful security at all? Because if you want more than trivial security, and any of the concerns I've raised above were a surprise to you or you don't know how to address them, you REALLY shouldn't be rolling your own session management solution. (Or probably any other part of your authentication or authorization system, for that matter.)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .