Storing in a database vs. signing tokens

Discussions of secure PHP coding. Security in software is important, so don't be afraid to ask. And when answering: be anal. Nitpick. No security vulnerability is too small.

Moderator: General Moderators

Post Reply
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Storing in a database vs. signing tokens

Post by Ambush Commander »

If I want to create a remember me system using persistent cookie tokens, there are two paths to take. The first path is storing a valid token for a user in the database, and then associating that token with when the token expires and whether or not it's limited to a few IPs. The other path is to issue all this information in a token, and digitally sign it, so it can be verified whether or not the script issued the token.

Signing the token offers the benefit of reducing load on the database server, both size-wise and connections-wise. However, it appears I will have to set up OpenSSL or GnuPG etc, and having never implemented such systems before, there may be problems. Furthermore, cookie size will be a lot larger. Furthermore, the size difference may be neglible for smaller projects.

Keeping the token in the database allows fine grained control over all tokens, and is the conventional route which isn't too hard to program. However, it also means that the system has to keep track of all tokens.

What route would you take? For a smaller project? How about a bigger one?
User avatar
nielsene
DevNet Resident
Posts: 1834
Joined: Fri Aug 16, 2002 8:57 am
Location: Watertown, MA

Post by nielsene »

Can you explain how your database token would work? You still need some form of a cookie token to identify the user, correct?

You should be able to generate reasonable strong tokens without going to a PKI system.
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Post by Ambush Commander »

When a user logs in with "remember me" set on, the system would authenticate the user, issue the session ID, and then would generate the persistent token using a combination of PHP's random functions and user variables. It will probably be fixed length. Then, it will issue a cookie with this token to the user, and then write it to the database, invalidating any previous remember me tokens set. When a valid session Id isn't found, it compares the remember me tokens and if they match, logs the user in.

I don't think I'm building a PKI system though... the only keys out there is in possession of the server: the user doesn't need any keys (can't see how it counts as an infrastructure).
User avatar
nielsene
DevNet Resident
Posts: 1834
Joined: Fri Aug 16, 2002 8:57 am
Location: Watertown, MA

Post by nielsene »

So your "remember me" wouldn't be able to remember a person from multiple computers?
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Post by Ambush Commander »

No. They would have to log in if they didn't have a valid token. I'm considering optionally allowing the user to bind the token to one IP address: if the token is presented from another IP, then it won't work and the token is invalidated. (Of course, AOL users would have to turn this feature off).
User avatar
nielsene
DevNet Resident
Posts: 1834
Joined: Fri Aug 16, 2002 8:57 am
Location: Watertown, MA

Post by nielsene »

I mentioned PKI only because you had OpenSSL/GnuPG listed. I would think you wouldn't need those unlesss you wanted a more complete PKI. Tokens can probably be adequately protected using HMACs and encryption via mcrypt routines.

I'd think that the cookie based token, is generally better than a weak cookie+DB. Of course a strong cookie+DB is also fine and offers a few extra possibilities.

I don't understand why you'd want to forbid "remember me" from multiple computers. I've had remember me for both my desktop and laptop set on many occasions, etc.
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Post by Ambush Commander »

nielsene wrote:I mentioned PKI only because you had OpenSSL/GnuPG listed. I would think you wouldn't need those unlesss you wanted a more complete PKI. Tokens can probably be adequately protected using HMACs and encryption via mcrypt routines.
Ah... I figured that using those routines would be more secure... I guess they're probably overkill. Must install mhash extension on my PHP then.
nielsene wrote:I'd think that the cookie based token, is generally better than a weak cookie+DB. Of course a strong cookie+DB is also fine and offers a few extra possibilities.
Err, could you make the distinction between "strong" and "weak" cookies? I think I understand the extra possibilities though:once you issue a cookie, it's out there, you can't get rid of it, etc.
nielsene wrote:I don't understand why you'd want to forbid "remember me" from multiple computers. I've had remember me for both my desktop and laptop set on many occasions, etc.
Oh, so that's what you meant! Well, maybe allowing that would be a good idea...
User avatar
nielsene
DevNet Resident
Posts: 1834
Joined: Fri Aug 16, 2002 8:57 am
Location: Watertown, MA

Post by nielsene »

Strong vereus weak...

I'm still a little confused on your two methods. In your OP it sounded like you had a method that uses cookies, but doesn't require a database and one method that uses the database, but doesn't require a cookie. Now it sounds like you're using the cookie in either case, just changing what information you're storing in it. Ie, the only difference is the payload of the cookie.

Code: Select all

// Minimal cookie token: 
$cookiePayload = $token
//"Coimplete" cookie token: 
$cookiePayload = $token+$expTime+$ipList
(Your OP included the notion of restricting to a small list of IPs, right?)

Now, in either case, you're going to want to "sign" the token with a keyed, HMAC. So the cookie value will be

Code: Select all

$cookieHash = HMAC($cookiePayload,$server_secret_hash_key); // for some HMAC function
$cookieValue = "$cookiePayload+$cookieHash";
Otherwise it trivial for someone to alter their cookie to some other value. This HMAC'd cookie is what I'd consider a strong token, but its needed in either of your two cases.

Now storing the $expTime and $ipList in the database or not, is a side issue. The signing is required in either. I think I'ld probably stored the expTime in the cookie. I'm less sure about the IP list, but mainly becuase I don't trust IPs.

The HMAC ensures the integrity (ie tamper-proof) of the token. You might want to also ensure confidentiality, to do so, you'd want to use a two-way encryption algorithm from mcrypt and do something like

Code: Select all

$cookieValue = encrypt($cookieValue, $server_encryption_key); // don't have the actual function name here, nor a lot of the setup
In this case the user can't "snoop" at the value of the token, nor the expTime, etc. This can help defeat a few crypto-analysis attacks on the token -- they have to find a way to decrypt the cookie in order to attack the hashing algorithm., etc However, the cookie value now looks like complete goobldy-gook which increases the chance of some paranoid users just rejecting/deleting it.
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Post by Ambush Commander »

Sorry for not being clear. You pretty much summed up my thoughts in your post. The question I'm asking really isn't that important, is it... I still have some questions though:
Otherwise it trivial for someone to alter their cookie to some other value. This HMAC'd cookie is what I'd consider a strong token, but its needed in either of your two cases.
What about a random string that is somewhat longer than PHP's session ID (message authenticated via a database)?
The HMAC ensures the integrity (ie tamper-proof) of the token. You might want to also ensure confidentiality, to do so, you'd want to use a two-way encryption algorithm from mcrypt and do something like
Is there any other reason why you'd want to ensure confidentiality? I don't see anything wrong with letting the user see the expiry time or IP list etc. The point about crypto-analysis is valid, but isn't it a bit paranoid (for instance, I sign lots of messages with my public key, but I would suppose it doesn't make it less secure)?

Could you recommend your preferred HMAC and encryption algorithms?
User avatar
nielsene
DevNet Resident
Posts: 1834
Joined: Fri Aug 16, 2002 8:57 am
Location: Watertown, MA

Post by nielsene »

Ambush Commander wrote:
Otherwise it trivial for someone to alter their cookie to some other value. This HMAC'd cookie is what I'd consider a strong token, but its needed in either of your two cases.
What about a random string that is somewhat longer than PHP's session ID (message authenticated via a database)?
Even if you have a large random search space, without the HMAC style tamper-proofing people could get lucky. The HMAC raises their "luckiness requirement" by several orders of magnitude. Now if you do logging/traffic monitoring and can detect a bute-force attack underway, then you've lessened that risk. (Though you'd still want to have that same monitoring/logging in either case, for better security)
The HMAC ensures the integrity (ie tamper-proof) of the token. You might want to also ensure confidentiality, to do so, you'd want to use a two-way encryption algorithm from mcrypt and do something like
Is there any other reason why you'd want to ensure confidentiality? I don't see anything wrong with letting the user see the expiry time or IP list etc. The point about crypto-analysis is valid, but isn't it a bit paranoid (for instance, I sign lots of messages with my public key, but I would suppose it doesn't make it less secure)?

Could you recommend your preferred HMAC and encryption algorithms?
Confidentiality can also be useful to help defend against sniffers .. Lets say someone wants to hijacck a paticular user's credentials (aka a directed attack). If the entire payload of the cookie is encrypted, the snooping can't tell which cookie is passing through the wire (unless he already knows the identity of the recipient/transmitter of the packet). For instance, the attacker wants to get an "admin's" credentials, and not a regular users.

If you've built your secure token out of good components, then the crypto-analysis bit is less importantt. However, people almost always end up taking shortcuts..... Even when they don't you can get burned if your server gets changed and some of the behavoir changes -- I had an annoying "upgrade" once that caused crypt($passwd,$md5Salt) to stop using MD5 and revert to 3DES. Had I been using crypt to generatee the hashed portion of my cookie tokens, it would have been rather obvious to an attacker that they were vulnerable to an some of the normal 3DES attack vectors (including the shortened searchspace).

As to recommending crytpo-alogirmths, I can't right now. I've been using a home-grown implementation of HMAC built on MD5, because I had a few legaqcy systems on servers without the needed extensions. Now I've managed to get all of those legacy installs over to more sanely admin'd hosts and I'm planning to switch everything over soon... I'ld much prefer to be running off "stock" alogrithms, but I haven't had the chance to dig into them again.
Post Reply