2

So, basically I am trying to log a user in with a cookie and do not query DB to improve performance.

Here is a brief idea:

  1. Transmit everything via SSL
  2. Set a Global secret key A and secret key B
  3. Generate a random verification string on registration and password change
  4. Encrypt the verification string with A, store it in cookie
  5. Encrypt the verification string with B, store it in cookie
  6. When user tries to login, I decrypt each string with A and B, compare if they match

I am wondering if it is a good idea if it is:

How can I actually do the encryption in Java, using bouncycastle ASE-256, Digest or whatever?

How much does this encryption/decryption process affect the performance, when compared with authentication by storing a session variable in a super fast DB like Redis?

If it is not: What should I do?

Brendan Long
  • 2,878
  • 1
  • 19
  • 27
Matthew Yang
  • 123
  • 4

3 Answers3

3

It sounds like you're trying to store an authenticatable message with a client. For that, you want to use an [HMAC]. Some of the downsides of this solution were recently discussed in the question Password reset links: random value or authenticated message?.

I personally lean toward databases in great part because you'll need to store something to be authenticated against at some point and database checks allow you to expire tokens. Once you pass an authenticated message, you can't kill it early unless you check a revocation list... database access again.

Jeff Ferland
  • 38,090
  • 9
  • 93
  • 171
0

The problem is revocation. Once you've handed out the cookie, it is infinitely reusable until they change password. If their client is compromised, the cookie could leak and it would be valid until the next password change. One possible enhancement would be to use a key on the server to encrypt a timestamp and include that with the cookie. This could then be used to limit the time validity of a cookie, though revocation due to logout would still not be possible without a DB.

AJ Henderson
  • 41,816
  • 5
  • 63
  • 110
0

This seems to be way more complicated than necessary. What's the point of the two different keys? What's the point of the verification string? Why encryption instead of just verification (the user ID most likely isn't a secret)?

I think you can simplify your system down to this:

  1. When a user logs in, generate a MAC using the user's ID, a timestamp, and your secret key and send them the user ID, timestamp and MAC as a cookie.
  2. On every request, recompute the MAC (using the user's ID and timestamp from the cookie, and the secret key stored on the web server). Deny any request where the computed MAC doesn't match or the timestamp is too old.

Java has a built-in Mac class, and there's examples of people using it on Stack Overflow.

You should know that this weakens security:

  • If someone gets your secret key, they can log in as anyone and you won't notice.
  • If someone steals your user's cookie, they can log in as that user until the cookie becomes too old (normal cookies have this problem).
  • You have no way of revoking access, even if you know that a user's cookies have been stolen (normal cookies don't have this problem).

As for speed:

  • Hashing is (in general) extremely fast.
  • Database access is slower, but still so fast that your solution is probably unnecessary.
Brendan Long
  • 2,878
  • 1
  • 19
  • 27
  • Thanks. I just performed a test and decryption is on average 30 times after than Redis. But considering they both take so little time after all, I guess I can keep using Redis then. – Matthew Yang Mar 05 '13 at 19:58
  • Encryption is not authentication. For most non-authenticated encryption modes, attackers can modify a ciphertext in ways that predictably manipulate the plaintext inside. You want to compute an HMAC or some other digital signature on the cookie rather than encrypting it. This will prevent an attacker from being able to modify the value. – Stephen Touset Mar 05 '13 at 23:39
  • Furthermore, you should store the synthetic database ID and not the username. Usernames might be changeable; database IDs are forever. – Stephen Touset Mar 05 '13 at 23:40
  • @StephenTouset Good point. I've updated my answer. – Brendan Long Mar 06 '13 at 00:17
  • @MatthewYang You might want to see the updated answer if you're still considering doing this. My main point remains the same though -- Using Redis is easier and more secure, and the speed difference doesn't matter. – Brendan Long Mar 06 '13 at 00:19