Passworded cookie
Posted: Fri Jun 12, 2009 1:14 pm
Sup folks. Just wondering what you think of my implementation of a secure cookie system. Ill place the logical steps below and would be very interested to know of any vulnerabilities or massive failures. Here is a link to the actual code for those interested: viewtopic.php?f=50&t=101595 (Also, this is my first time with PHP, so any comments on code/conventions would be nice) (halp).
There are initially two pieces of data. I will call them $cleartext and $ciphertext. $cleartext will be sent in the clear while $ciphertext will be encrypted and then sent. Before anything else takes place, the expiration date is added to the $cleartext and both of the variables are serialized. (Is there a better (smaller) way of doing this without losing all of the flexibility of serialize()?).
Now the serialized $cleartext is hashed using the sha256 algorithm and the HMAC method with a secret key kept by the server to create the $key. This provides a fairly strong key that is based on the expiration time as well as any other information the server is willing to send in the clear. Because the $key is affected by both changes in time as well as unique information (most likely usernames), keys will almost never be reused. This should help make the encrypted portion of the cookie very resilient to cryptanalysis. Also, the HMAC method of hashing provides a way of hashing a $key that is immune to collisions and cannot be generated by an attacker without knowledge of the secret key.
After the $key is generated, mcrypt is initialized and set up to use AES-256 in cfb. A initialization vector is then generated by seeding the MCRYPT_RAND function with the sha256 hash of the $key and the current time in microseconds. The $key was hashed again so that even if the attacker could somehow break the AES, he would still be unable to send messages due to the HMAC verification (later). Also, 8 bytes of random characters are created and prepended to the $ciphertext. I was concerned that an attacker having the IV and knowing that I was using serialize could guess the first few characters of plaintext and work out the key. Probably unfounded, but these random characters added to the beginning of the message should cause it to scramble sufficiently to remove that advantage. Once the data is encrypted with the hashed key, I prepend the IV.
Then the cleartext and the encrypted ciphertext are HMAC hashed (sha256) with the $key to create a hash that can be used to verify that the message has not been tampered with. Finally, the entire message is XOR'd with a simple repeating string of one character to obfuscate its meaning to the average user.
Decryption is done in reverse. As long as the server knows the secret key, the actual key can be generated easily. As far as I know, there is no faster way for an attacker to break the cookie than to brute force the secret key.
This cookie, while kind of large, can be used to securely store things on the user's system for a fairly long period of time. My thinking right now is to send cookies like so (below) to the user and check it once when they visit a site. Then I will issue a short term session cookie that they will send at all times. OFC, for a lot of sensitive data, this should be fine as it. Ex. contents of a shopping cart.
Ex. Standard login Cookie
$cleartext = username
$ciphertext = password, ip
Quick question: Is there a better way than IP address to verify that the user is still on the same computer as when the cookie was set. Right now cookie theft is what I see as the number one vulnerability and I'm trying to think of ways around it.
So yeah tell me what you think.
Thanks.
DBSights
There are initially two pieces of data. I will call them $cleartext and $ciphertext. $cleartext will be sent in the clear while $ciphertext will be encrypted and then sent. Before anything else takes place, the expiration date is added to the $cleartext and both of the variables are serialized. (Is there a better (smaller) way of doing this without losing all of the flexibility of serialize()?).
Now the serialized $cleartext is hashed using the sha256 algorithm and the HMAC method with a secret key kept by the server to create the $key. This provides a fairly strong key that is based on the expiration time as well as any other information the server is willing to send in the clear. Because the $key is affected by both changes in time as well as unique information (most likely usernames), keys will almost never be reused. This should help make the encrypted portion of the cookie very resilient to cryptanalysis. Also, the HMAC method of hashing provides a way of hashing a $key that is immune to collisions and cannot be generated by an attacker without knowledge of the secret key.
After the $key is generated, mcrypt is initialized and set up to use AES-256 in cfb. A initialization vector is then generated by seeding the MCRYPT_RAND function with the sha256 hash of the $key and the current time in microseconds. The $key was hashed again so that even if the attacker could somehow break the AES, he would still be unable to send messages due to the HMAC verification (later). Also, 8 bytes of random characters are created and prepended to the $ciphertext. I was concerned that an attacker having the IV and knowing that I was using serialize could guess the first few characters of plaintext and work out the key. Probably unfounded, but these random characters added to the beginning of the message should cause it to scramble sufficiently to remove that advantage. Once the data is encrypted with the hashed key, I prepend the IV.
Then the cleartext and the encrypted ciphertext are HMAC hashed (sha256) with the $key to create a hash that can be used to verify that the message has not been tampered with. Finally, the entire message is XOR'd with a simple repeating string of one character to obfuscate its meaning to the average user.
Decryption is done in reverse. As long as the server knows the secret key, the actual key can be generated easily. As far as I know, there is no faster way for an attacker to break the cookie than to brute force the secret key.
This cookie, while kind of large, can be used to securely store things on the user's system for a fairly long period of time. My thinking right now is to send cookies like so (below) to the user and check it once when they visit a site. Then I will issue a short term session cookie that they will send at all times. OFC, for a lot of sensitive data, this should be fine as it. Ex. contents of a shopping cart.
Ex. Standard login Cookie
$cleartext = username
$ciphertext = password, ip
Quick question: Is there a better way than IP address to verify that the user is still on the same computer as when the cookie was set. Right now cookie theft is what I see as the number one vulnerability and I'm trying to think of ways around it.
So yeah tell me what you think.
Thanks.
DBSights