I had a quick question about cookie security that I wanted to run by the stackoverflow community before I got too far into implementing it. This will be my first time implementing user sign-in on a site and I wanted to be extremely cautious about security so-as not to have to worry about accounts being compromised down the line.
Here's my hypothetical security solution:
- User signs up for site (through either email registration, login with Facebook, etc.) and is assigned a User ID number. This number is public and can be used to access the profile of the user, refer to them in posts, and so on.
- At registration, the user is also assigned a randomly generated ROWID as their information is stored in a database (hosted on Google Fusion Tables). This ROWID number is kept hidden from the user and is never revealed.
- The User ID is encrypted against the ROWID number and this number is stored in a cookie on the user's computer. It isn't ever visible to other users and, in theory, this could only be viewed by the user.
This solution would allow for a "secret" key (the ROWID number), a "consumer" key (saved in the cookie), and a public reference ID (the User ID). All of these are, of course, rolled up into a database where the site can quickly access them. Does this sound like a plan that would provide the proper level of security or is there something else that I should consider?
For additional protection against cookie theft through something like XSS, you might want to consider issuing unique cookies per IP address, and then making sure that the cookies are only useable from that IP address.
If you're storing your cookies in the database, things can get complicated, as you now have multiple cookies mapping to the same user.
Here's how to avoid those problems:
Set-Cookie: userName=Alice; authCode=eeba95a4...
Where: authCode=HMAC(ROWID, userName + ipAddr)
When you receive this cookie, look up the user in the database, recompute/verify the authCode in the cookie, using ROWID and ip address of the request. No need to store cookies in the database.
For extra crypto points, throw a salt parameter into the mix:
Set-Cookie: userName=Alice; salt=59843...; authCode=eeba9...
Where: authCode=HMAC(ROWID, userName + ipAddr + salt)
Salt value is generated randomly for every cookie you produce. There's no need to keep it a secret.
This is a good question, and since you have no answers yet I will give it a go. As far as I can see (I'm not a cryptographic expert) this seems reasonable, at least in theory.
I see one problem, that is if a malicious user get the consumer key (and this is not protected in any way) he could try to brute force the ROWID since he already know the User ID. So at least some kind of salt should be added to the User ID before encrypting. Also the "consumer" key ccokie should be passed as secure only, making sure it never travels on an unencrypted connection.
But it all depends on what you are planing to use the different keys for.