There have been some mention in the comments for this post for clarification on the 'remember me' cookie that is mentioned in the code. I thought I'd elaborate a bit on how I used it for this example.
As part of a project I was working on while at CDC there was a requirement for there to be 'Remember Me' functionality for the authentication system. I'm sure you've seen this elsewhere. Implementing such a thing is actually very simple, but I should've clarified that 'remember me' functionality is NOT part of the Auth component.
- When they go to log in, check to see if there is a 'remember me' cookie present.
- If there is no cookie, let the person log in as usual and if they are successfully authenticated then store that information in your 'remember me' cookie before you let them proceed to whatever areas require authorization.
Now, to drop into CakePHP for a minute the key thing that was left out of the previous blog posting is *how* you get the Auth system to accept the values in the cookie. It took a quick IM conversation with gwoo to jog my memory.
-
function beforeFilter() {
-
/**
-
* Code that does other Auth stuff goes before this...
-
*/
-
-
/**
-
* If you've checked the data against your auth model,
-
* you have to put that info into $this->data so that the
-
* Auth component can use it
-
*/
-
$this->data['User']['username'] = $cookie['username'];
-
$this->data['User']['password'] = $cookie['password'];
-
}
The password stuff is critical here. By default, the Auth component will take any password that you've entered via a form and then hash it using the default for Auth (this value is configurable, check the Auth section API to see how to do it). So, make sure that the *encrypted* password value is being placed into $this->data, and consequently stored in your cookie. In the example above 'User' is the model being authenticated against, so feel free to change it if you're using something else. Keep in mind it's probably not a good idea to put a field called 'password' in your cookie, so feel free to change it to something less obvious or come up with another method of obscuring the true contents of the cookie.
Hope that clears up the 'remember me' cookie mystery for people. Thanks again to gwoo for helping me rummage around in my brain for the details.
Tags: auth, CakePHP, cookie


Well, security by obscurity is a bad strategy
I would define an additional hash for the user and only store this hash in the cookie.
Good tip, but if data are set before call action, so unset of 'username' and 'password' is needed in the begining of each action like "edit".... :-\
Thanks a lot Chris, amazingly helpful
I suspect you'll have just made a lot of people's lives easier with this one.
@Daniel
Well, I think hashing of the user name is overkill since all that really matters is making sure they don't figure out the password. At least, that's my opinion
@nao
Um, you don't actually need to do that. Why would you have to unset that data? It won't be automatically displayed anywhere, is that what you're afraid of?
@Stephen
Glad it helps you out
@Chris: I didn't mean you should hash the user name. I meant you should define an additional field in the user table for a hash value you generate when creating a user, and to use this hash value in the cookie. So, even if someone finds the value that leads to the hash value in the cookie, it will be of no use for him. But if you stored the hashed password in the cookie, then he will have your password.
@Daniel
I understand what you're getting at. Given that the Auth component uses a one-way hash on the password, I'm okay with that level of security. A two-way hash is okay for encrypting the *hashed* password I guess...so long as they don't figure out what you're using to hash the hashed password (too much use of the word hash here...)
I -think- Daniel is right.
Auth hashes the password (assume 'pass')as follows: sha1(CAKE_SESSION_STRING .'pass')
Each sha1 hash has multiple nonhashed alternatives.
I believe there are publicly available tables which contain a possible nonhashed alternative for each hashvalue. Suppose the hash for pass is 'passhash' but you find an alternative password (for example 'alternativepass') whose sh1 hashvalue is also 'pashhash' you could enter that for loging in instead.
Not sure though, I might be missing something.
I was missing something indeed, yeah of course you can't find an equivalent nonhashed value easily because the hashed password in the database will be compared to sha1(CAKE_SESSION_STRING .'alternativepass') which will not match because of the (unknown) session string salt.
Since cake forces you to customize the session string at installation it is indeed relatively safe to store the hash in the cookie.
Hey i like Daniel's approach but enhanced a little - i add a table for these hashes that are generated on login and deleted on logout so old hashes could not be used after the user has logged out.
The overhead isn't so big.
in before filter:
* check the cookie - if it exists - check the db for the hash (and get the user id if it exists) -> login the user with the id $this->Auth->login($userId)
* if the cookie exists and the hash doesnt -> deletre the cookie
* if there isnt any cookie then dont query the db (most of the time)
That way the user can be logged from different places (its convenient) and if there is a problem or the user thinks there can be we can provide a link to delete all permanent sessions.
I used a similar approach as Chris in a project some time ago but i encrypted the user id in the cookie ( with the cookie component in 1.2) The site didnt need extra security so it was acceptable but know i used the method i described above.
Daniel, Chris, others,
Nice to see how people try to prevent reverse engineering of a password from a cookie.
However, I miss one thing in the discussion... if I have the cookie, I don't *need* the password anymore! I just offer the cookie to the server and it logs me in. Who cares about the password?
BTW, I guess most (if not all) 'Remember Me' solutions are vulnerable to 'cookie hijacking'.
am I missing something..? I don't see the point of storing a username and password in a cookie... why not store using a session and have authenticated=true and if you want more security put the ip in so if someone hijacks the session cookie they can't use it ??
@Martin: Many people use the same password for different applications. So if I can get the password then it is possible I will also get access to other applications in a worst-case scenario.
@SFI: The purpose of storing the username and password in a cookie is so that when the user comes back to the site at a later date, they can be automatically logged in.
@Chris
yep but i rather store an ID of the user (encrypted with a salt) if the cookie will be compromised i would only have to change the salt ( or the login system) and no paswords would be leaked.
@Kabturek
Well, perhaps I don't understand how the hashing of the passwords works in the Auth component, but since the hash is only one way I don't see how anyone could even figure out the password unless they know the original. I would be storing a *hashed* password in the cookie, not the plaintext one. Storing plaintext passwords in a cookie is an insane security hole.
I have some problems trying to implementing the Remember me feature.
I followed your previous tutorial and store the username as well as the hashed password in the cookie. Then, in beforeFilter(), I put these values into the $this->data array. However, seems that the password in $this->data has to be plaintext, as the Auth component will automatically hash all passwords in this array.
Did I miss anything?
Well, I think I figured that out. Just change the code in beforeFilter() to the following and it would work:
$cookie = $this->Cookie->read('User');
if ($cookie) {
$this->Auth->login($cookie);
}
Thanks Chris. It's taken me days to get this working. Nowhere does it seem to clearly say that the stored password must be hashed, nor that the easiest way to do it is by using cake to insert the user. One of your articles has pointed me in the right direction once again!
I don't know what I'm doing bad, but it doesn't work for me in Opera. When I reopen it my "session" is lost and I must relogin. In FF it works correctly.