In this age we have different machines, devices and phones, but sometimes we would like to be remembered by our own name.
I have a website where one person should be able to check "remember me" on the device he is currently working on, and having this working on all of your devices in the house.
Currently I was using a remember me function which creates a hashed key, saving it in the cookie, and in the database.
However - when logging in with the same user, but on an other device, the hashed key in the database is overwritten so the remember me function on the first device is down.
I was thinking to ceate a session table to hold the different sessions, (although it might hold different sessions for one user as well)
So Question:
How can I set/generate a unique session key for a device with php.
a browser fingerprint won't do as I use same browsers on different devices.
anyone ideas?
ofcourse I need a secure solution, preventing copying the cookie to another device or changing cookie information (from your user to admin) is important.
For a start having a hash key instead of a username does not add any extra security.
Just use a cookie with the username in it. The password is there for security.
I would do the session table to store all the sessions. Store the user's ID and the session ID in a cookie, that way when the user comes back, you can check to see if they are both in the table. If they are, they don't have to log back in.
The basic idea is to store the session ids from the different devices and tie them to one user. On the database level that means you don't have a "session_id" field in your user table but a separate table with "session_id" and "user_id" columns.
Please think about the security implications of session fixation and session hijacking. For a description of a more secure "remember me" system, read these articles:
http://fishbowl.pastiche.org/2004/01/19/persistent_login_cookie_best_practice/
http://jaspan.com/improved_persistent_login_cookie_best_practice
ofcourse I need a secure solution, preventing copying the cookie to another device or changing cookie information (from your user to admin) is important.
Ultimately, this is solving the wrong problem.
The way to prevent this is to:
Use HTTPS everywhere.
Send all cookies over HTTPS, with the secure and httpOnly flags.
That's it. This is related to the problem of client authenticity. There are some techniques that can stop lazy attackers (e.g. user agent), but any of these techniques can be spoofed trivially.
Related
On a website I am developing I am currently checking if a user is logged in if it's cookies are set. The thing is I'm using these information for some request on the database and allow him to do some tasks on the website. Though, it came to my mind that if the user edit its cookies, he might be able to be someone else (editing it's username/id). So, is there a way to secure it or do I have to use sessions ?
Yes, you can use cookies. You just need to make sure that the cookie provides data you can use to authenticate the user, and not a token that means the user is authenticated.
Bad cookie:
username=foo,logged_in=true
Good cookie:
token=uifhjrjf4093jf3904j90j390kf934j8438j0493jf9034
And then compare the authentication data against a datastore on the server.
Do I have to use sessions?
Sessions are a way to store temporary about a user (who may or may not be authenticated). They are a quick and easy way to solve part of the problem and not something that should cause reactions of Do I have to? :(.
Most session libraries use cookies to store the token that links the collection of data associated with a session to the browser to which the session belongs.
What I usually do is give a random hash in a cookie, then have point it to a database table in which I store the full browser string, a time to live, a last access time, the username and the hashed password (for comparison in case the user changes passwords because he was compromised, this will invalidate every other sessions except the one that changed his password).
I've created a login system that uses cookies and stores a session ID in a database, so your login will only work with that particular session ID. I realise this has a few problems:
If you login on another device the session ID changes (no multi logins)
The session ID is really the only thing identifying the user as logged in (I'm not really sure if this is a security risk since the cookie is domain specific)
However I want to retain the persistant login that comes with cookies while still keeping stuff secure.
Effectively I want to know if there is a better way to securely log a user into a website using cookies.
First of all, keeping stuff secure and persistent logins don't go together; you will always compromise security by introducing persistent logins in some way.
Having said that, an article from Charles Miller outlines such a system:
create a (big enough) random key, preferably by using /dev/urandom or openssl_random_pseudo_bytes() and associate it with an account (in database terms: a separate table with the random key as the primary (or unique) index and the account as a foreign key); the key will be the cookie value.
when a non-logged in user presents a cookie, the key and account are looked up and the user is logged in; afterwards, the used key is replaced with a new random key (cookie is updated too).
users who are logged in via cookie alone should be asked for their password again when they access sensitive (account) information.
the user should have an option to log out from all his devices.
It's also a good practice to use a renew the session id using session_regenerate_id() whenever a user is logged in (either via a form or cookie). This prevents someone from launching a session fixation attack against someone else and possibly steal their identity.
An improvement on this design by Barry Jaspen that can also handle identify theft detection can be found here.
This is how I'm building a login system:
Login:
Check username and password supplied by user with the database.
If username and password is correct, store only user ID in session, something like:
$_SESSION['userid']=$userid;
If User has checked the option to stay logged in, then set 2 cookies, 1 with userID and other hashed string.
To check if user is logged in:
Check if Session exists, the user is logged. is it ok?
If session does not exist, check if both cookies, userID and hashed string exist.
If Both cookies exist, validate them.
As the Session is stored in the server, is it secure to store only userID ? Can a user pretend to be other user and store his userID in the session and log in as him?
Thanks.
Yes, this method is very insecure. I can sniff traffic, intercept your cookies, and your system will accept me as an authenticated user. You are making the assumption that if you get a cookie with a userid and the hashed string, then that user is the same person that originally authenticated to create the cookie. That is a poor assumption, because cookies travel in plain text (unless you encrypt them), so as long as I can grab a cookie, I can pretend be whoever sent that cookie, and your system doesn't know any better.
Edit:
If you are going to use unencrypted cookies, why not just store the session_id in a database table? That way, at least someone that gets hold of a cookie won't have a valid username. Create a sessions table, and when someone successfully authenticates add a row with their user_id and the session_id. Each time a page is loaded, check to see if the session_id in the cookie matches a row in the sessions table. If yes, you can assume the associated user_id is the authenticated user. This approach is just as secure as the one you suggested (i.e. not very), but it's less complex and doesn't give away valid usernames.
Yes it's possible and very extended, this kind of attacks are called Session fixation and in your system (as David said) anyone who sniff your traffic, or have access to the user's drive and steal his cookies, may supplant a logged user.
The best protection is, of course, SSL, but if you can't use it in your website there are other things that can prevent (but not fully protect against) this attacks:
Save info about the user in the server-side when he login, good candidates for this are the IP and the user agent, but any other data that don't change in the entire session can be valid.
You can regenerate the session ID in every request, with this if the session ID is leaked the attacker must use it before the real user do any other request, but beware because every time the session ID is regenerated (in PHP at least) the user's session data is rewited, so this can be expensive if you have a lot of users or if you save many data of every user (this means that, if you're saving the session data in a file, the file will be deleted, created, and writed again).
Well, right now I can only think in these two, it's not much but at least you will put an extra complication to the attackers.
One more thing, don't trust the user's cookies, they can be changed by the user (or the attacker) at any time, treat it like any other user input.
PD.: Sorry for my horrible english, I'm truly trying to improve it ^_^
you could add an ip that the user id should belong to (in your database), that adds a little extra security - it might not always be the best solution
Yes it is ok to check if the session exists and also check that the user id is greater than zero.
The 'remember me' function is subject to sniffing as it's not over ssl, however that is how 'remember me' functionality is done.
Assuming this is happening via SSL, my biggest concern is your first step:
Check username and password supplied by user with the database.
You should be hashing passwords, and comparing the hash of the user-supplied password against the previously hashed password stored in your database.
You also don't have to worry about storing only the user ID in the session array; the session is stored server-side and is as secure as the rest of your server.
One potential problem is that everything is being stored in cookies. If someone somehow manages to get their hands on the Session ID, then they've also got the username and hashed string.
Chris Shiflett suggests creating some kind of fingerprint from the User-Agent string, or some other regular header, and storing it in a GET variable.
One way to bump up security is to have everything sent over SSL. Any time any kind of potential information is sent or received (such as the Session ID in a cookie), make it encrypted - not just the login form.
It is mostly correct but I don't agree with the cookie-option. This way if someone gets the two cookies can move them to a different computer and still use them.
The "remain logged in" function should be restricted to that computer. A possible solution is that if the user wishes to remain logged in you set the lifetime of the session to 1 week or so. Also you have to store the user's IP address, User-Agent and possibly X-FORWARDED-FOR header, and check them on every pageload against the stored values.
I am using a PHP / MySQL login system. I would like to add a remember-me to it. What are the basic mechanics of a remember-me? Does it involve adding a new column to the table in MySQL where all of the user information is stored, etc. ?
Thanks in advance,
John
There are a few different methods for this. A secure method would be to add a field to the mysql user table and have a "remember_me" hash which is just a random hash generated.
The hash should be stored in a cookie on the users computer as well as the userid for validation purposes for however long the remembering period lasts (you should also set the remember me period in the DB as a timestamp as well for extra security). When they pull up your site, you see if that cookie isset, if it is then you just authenticate the hash to the userid. If it validates they are considered logged in. If it does not validate, then send them to a sign in page / they are not considered logged in.
This is how I setup most of my sites. The pain is that if they login from another computer, well they are now no longer validated on the computer they were using and will have to re-authenticate. But security, to me, is more important than them having to login again due to that situation.
EDIT:
See comments below for extra information regarding the sessions / security.
Does it involve adding a new column to the table in MySQL where all of the user information is stored, etc. ?
Not necessarily. A "remember me" works by storing in a cookie either the primary user credentials (his username and password, typically) or some temporary credentials that are set to expire after some time. If you use these temporary surrogate credentials, which are typically long random strings, you must add a table to your database where you store them, the username associated with them and the time where they expire.
You almost certainly do not want these credentials to be send over an unencrypted connection. You should store them in secure cookies, that is, cookies that are only sent over HTTPS (you should also set the cookie via an unencrypted connection).
If you choose to use a secure cookie but do not want to encrypt all traffic you can use two cookies:
An insecure cookie that only signals the server that you have a secure cookie with the credentials.
A secure cookie with the credentials themselves.
Then, when the user visits your site and he's not logged in, you check for the presence of the unsecure cookie. If it exists, you redirect the user to a HTTPS page. Since this is secure, the secure cookie, with the user credentials, is sent by the client. You then proceed to check the content of the cookie with that you have stored in the database and login the user.
When someone logs in with 'remember me' set, generate an identifier, and store it on a cookie.
When someone visits a page on your site, look for a cookie. If they have one, look it up in your DB, where it should be mapped to a userid. Then just run whatever login functionality, just as if they'd entered a valid username & password.
For each user, I want to allow them to choose their preferences, such as which categories to show on their profile, which tags they want to see, etc. Would cookies be better than sessions because they don't expire when users logoff?
I think the best solution is to mix cookies and database - the last one for logged in users.
Cookies are fine, because the user doesn't have to log in on your website to have some preferences saved.
But if somebody will login to your page than you got ability to save his preferences in more stable source - server database. Then these preferences are available from every computer and won't disappear after "browser cleaning".
EDIT:
Don't use sessions - they are worse than both, cookies-based and database-based solution.
Why sessions aren't a good idea? First of all they rely on cookies (session id which required for proper work of sessions system is stored in cookie called SID/SESSID/SESSIONID (in most cases)) so whenever you clean cookies you also lose your session. Moreover session are available only for few minutes (from first page load to browser close or about 20 minutes of inactivity on website) while cookies may be available for few months or even years!
So how should you do that?
There are two scenarios:
When user is not logged in:
Then when he change some preference store it just in cookie
When user is logged in:
Then when he change some preference just save it in database:
INSERT INTO preference (user_id, key, value) VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE value = ?;
That's example for MySQL but you can do this the same in others RDBMS.
And how do you get final preferences?
// That's VERY unsafe code... you HAVE TO do necessary validation (this is only an example)
$preferences = unserialize($_COOKIES['preferences']);
if (/* user is logged in */) {
$databasesPreferences = result_of_query('SELECT key, value FROM preference WHERE user_id = ?');
$preferences = array_merge($preferences, $databasesPreferences);
}
Sumary
This solution gives you the most stable way for handling user preferences for both logged-in and non-logged-in users.
Cookies can have an expiration date. If there is no sensitive data in them then they're fine to use, however if you're storing thing like user id's, etc. that will be used in queries you're best off using sessions as they're stored on the server where people can't manually get at them.
You generally have three choices of where to save user preferences:
database
cookies
session
When deciding between these, each solution offers different behaviors in terms of:
persistence
locality (tied to a browser or account)
security
If you need longer-term persistence of these value, you should put them in the database. If you want them to not require a sign in, then cookies are a better choice. There really is no one right answer-- it depends on what you're trying to accomplish.
What is the point of using cookies when the user has logged off??? User needs to be using the website in order to read from the cookie and apply the settings. Once the user has logged in, you may query the database and store the options in sessions until the user has logged off.
My recommendation is that it's best that you use sessions as they are much safer.
Cookies are nice because they can last between visits or "sessions". However they are also user editable and readable globally. Storing sensitive data like a login, password, session id, etc can lead to a malicious site hijacking the session or users information. Also a crafty user could alter the cookie to change the privilege level or user who is logged in and impersonate them.
Sessions are very secure because they are stored server side away from the prying eyes of users and other web sites. They do have the limitation that anything that's stored in them disappears once the session ends.
When I do login systems I prefer to use a sessions. You can pull the user from the database and then load various user defined settings into the session.