Basics of a remember-me system - php

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.

Related

Designing a Login system - What's the right way to do it?

I'm somewhat new to web development and I need to develop a user system - so users can register, login etc.
I initially stored the user data in a Session variable upon login, but felt the need to re-architecture that because I realized I would never be able to support 'remember me' functions, and decided to use cookies.
My current system is this:
User logs in: I verify username and password against stored values in DB
I set username and password to their own cookies. username cookie persists so the username field can be populated when the user revisits. Password cookie expires when user leaves.
Each time a page loads, my PHP script checks to see if the password cookie exists, which means the user is logged in.
The problem is, the third step seems somewhat insecure to me. Currently, I only check to see if the password cookie exists, but I do not compare it against the database everytime a page loads. Couldn't an unauthorized user create a password cookie and set it to some random string manually, and get through my authentication system? He would be able to impersonate any user by setting the user cookie manually as well. Should I be comparing the value of the password cookie against my database on every page load?
So, if I use session in conjunction with cookies, I imagine doing something like this:
if (!isset($_SESSION['user']))
{
authenticate_user_from_cookie();
set_session('user');
}
else
{
//user is already logged in
}
When you call session_start() it will reconnect the current request to a session ($_SESSION), or create a new session. Apache saves these sessions to disk (by default in your /tmp folder) and reconnects you to the session automagically with a cookie named PHPSESSID (this can be changed in PHP.INI), that is stored after the first time you call session_start() on the first request.
You can authenticate your user by whatever means you want, but typically you could use lookup the username + (encrypted password - e.g. sha1($password.'salt string that only you know')) pair in your database or permanent storage and then simply set $_SESSION['loggedIn'] = true or $_SESSION['user'] = 1 or whatever flag you want in the $_SESSION.
You can go as far as creating a User class (many frameworks do that), representing everything you know about the logged-in authenticated user and then ask the object $_SESSION['User']->isAuthenticated() or something like that.
If you want to not have the user reenter their password each time you can implement a Remember Me feature (special random cookie that you generated when they authenticated and stored in the database), that will set a special cookie in their browser that won't expire at the end of the session that you look when someone makes a request who isn't authenticated.
This is not php specific but if you're new, I would recommend reading the OWASP guide. OWASP is an excellent resource for secure web development info. The OWASP site will cover much more than we can here.
For a more php specific answer, they have this guide. Point 2.10 addresses your question more directly.
Just checking for a cookie's existence is by no means a way to authenticate a user or validate his identity. So yes, you should be checking on every page load, if you're sticking with the cookie based authentication. As long as there's an index / primary key on the lookup into the user table, the query will be fast to pull the user's information and check against the cookie values.
To be more specific, the cookie(s) that you're setting are just as valuable as the user's username and password, they're nearly synonymous. So, you can also save information about the user when you issue the cookie, such as IP and User-Agent, which you can also verify to try and ensure the cookies match the user.
A few more tips:
1.) Make sure you do input validation for both the password and the userid and make certain that you are validating the values on the server side as any client-side validation can easily be bypassed by malicious users. If you don't validate on the server you will be opening yourself to various types of attacks such as SQL injection and people will be able to compromise your database. Make sure you are escaping any potentially malicious strings
2.) Make sure you have login logouts, so that if people try to to put in too many wrong credentials you block their IP for a few minutes. This will discourage brute force attacks.
Make sure that this works for both bad userids as well as bad passwords as attackers can iterate over either (e.g. they can keep the password the same and try many user ids).
3.) If you are using salts, do not store the salt in the same place as the password hashes. If someone breaks into your database you don't want them to have both the hashes and the salts because it will make the hashes easy to crack using rainbow tables.
4.) Make sure you are using SSL/TLS to encrypt traffic traffic between the server and the user, otherwise an attacker can steal the cookie by sniffing the network and login as your user. (Look up Firesheep, it was a big problem for Facebook and Gmail for a little while...)
5.) Don't do any custom encryption schemes, use only trusted cryptographic libraries and algorithms to perform hashes. (e.g. PHP's sha1 is good, doing your own little rotation on password characters is not).
6.) As recommended, you should check out OWASP, it's the best resource for securing a web application.

Storing login information in Cookies

I want to save user's authentication information in browser cookie for persistent login. As they say, its never safe to store any secret info (such as password) in cookie, but in order to have an option such as 'Remember Password', i think there is no any other choice.
So, if a user want to remember his login info, and if i store username (Email) + Not the password, but some other unique info, such as HASHED DB ID in the cookie. Then i should check if the hashed ID stored in cookie matches with user's email which is stored in Cookie.
As I think anyone can very easily see the cookies stored in Browser (for example in Firefox, Options -> Cookies ).
So would this be as weak as for someone to read the cookie from the computer where its saved, then on other computer set cookie with that information and he would be logged in? (As the script will check the stored email and hashed id with database and it will match)?
Could this approach be bit improved without storing other information in database (such as session id etc) ?
Thanks
There is another option.
For each user, upon logging in and requesting to be remembered, create a long random string.
Store this string, along with the userId, in the cookie you give to the user.
Store a properly salted hash of the string in your db.
If the user presents a remember-me cookie, match the random string to the hashed verifier you have in your database (just as if it where a password).
If it matches -> log the user in and create a new remember-me cookie for them.
If doen't match -> request username and password.
I wrote an answer to the same question in How to improve my user login scheme - have a look there.
I would suggest using an unique key on the server to encrypt the username (in this case, email) and store it in the auth cookie. If the cookie is tampered it will fail to be decrpted and result in login failure.
If an auth cookie is copied (by manually setting the cookie or by XSS) to another computer (or another browser), then the user would be logged in as well on the new computer. You could consider adding some unique information about the computer (such as IP address) to reduce such risk.
This is an explaination about auth cookies in .NET, but I think the concept works on php as well:
http://support.microsoft.com/kb/910443
There is a good article on how to make "remember me" cookies more secure.
I have implemented the method described in the article in a PHP library: https://github.com/gbirke/rememberme, maybe you can use that as a reference.
Session fixation and cookie stealing is a real problem in the age of Firesheep. The only defense against that is securing your site with SSL and monitoring for XSS flaws.
Another way to improve your security is to remember if a user logged in with a "remember me" cookie and force him to reauthenticate when he does something "dangerous" like ordering or changing login credentials.
For more resources, see this Question: The definitive guide to form-based website authentication
you don't have so much of a choice when it comes to store user info on client side...
You can try to make some encryption using the client IP as the key.
This way even if the cookie is copied to the hacker computer and if he doesn't notice that the IP is the key of the encryption you'll have some descent protection of user's info.
Facebook is doing something this way, proof is everytime you try to log in from another connection point you have to go throught the user verification system...
So look for some reversible encryption and this should make your day ;)
You could also install a cookie with a UserID and a SessionID with a expire timestamp.
Then if you bind the cookie to IP or hostname (or preferrably both) you're quite safe from cookie stealers and other stuff.
i think there is no any other choice
Think again.
You don't need to store the password clientside in order to maintain a session. The 'remember me' operation is just the same - use a random value which is a lookup key to data held on your server.
Short of using client side certificates with pass phrases, anything else you do to complicate things will not improve security, and is more likely to expose your customer's private data.

PHP login security

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.

PHP login cookies security

In most of past questions on SO about security in 'Remember me' feature in login systems, Persistent Login Cookie Best Practice is suggested.
If I understand correctly, this approach goes like this:
If user checks to remember the password, the cookie consisting the username, followed by a separator character, and some large random number should be set. For example:
$_COOKIE["login"]; ="adam:8794383bb07608636dab808df6c9e29c"
store username and hash string in database.
if both cookies exist, and are mapped to each other in db, the login is accepted.
After authentication, remove the random number from cookie, generate a new number and store in cookie. (Do I need to update this newely generated hashed string in the database as well?)
When user is logged out, current cookie number is also invalidated.(Should I remove username and the random string from the database?)
Is it all?
As in my previous question, I was told that if someone can access the cookie, they can easily authenticate. So how does this approach solves that problem?
Many thanks.
Actually, here is what I would recommend. Sample DB Schema
Users:
user_id
username
autologin_hash
autologin_expire
Process:
User clicks remember me
Server assigns a unique token and stores it in the database and sends it as a cookie.
Server also assigns a fixed expiration date in the autologin_expire field
Check to see if the user's cookie equals the one stored with their account on the server AND it has not expired
All is good...login, delete the hash, regenerate it, and update the expiration date for the next login
You never, ever want to store usernames or passwords in cookies as they are vulnerable to theft if you are not using SSL. Using a unique hash and clearing it on each login solves these problems: 1) it prevents auth details leakage, 2) it makes a auto login valid only once (cookie cannot be stolen and used again), 3) it enforce a hard expiration date server side which helps prevent abuse, 4) and the long unique ID is hard to impossible to guess so hackers would have to actually steal the cookie to gain access.
Edit: If you want even more security, make a note to clear out the hash if the user changes their password. You don't want valid auto login hashes floating around if the user changed their password out of fear their password was revealed.
4). You do need to update the hash, otherwise the person won't be automatically logged in again.
5). You should for clean up, but if it is invalidated, your code should not process it as valid.
As for stopping other people from loggin in with that cookie, you could do...
User agent must be perfect match as well.
Once logged in, their account is marked remembered login. When it comes to changing passwords, making payments, you request their password again.

How to automatically re-login a user with a cookie

So on my application login form I've got one of those little boxes like [_]remember me
When the user checks that we set $_COOKIE['rememberMe'] with the value of the username. Now when that user comes back 3 days later, I obviously want to recognize them and re-log them in automatically. It doesn't sound safe to simply check for the existence of that cookie and then use it's value as the username to login without a password. But I'm not sure how else I would log them automatically... Is there a way this usually done?
Your cookie should have three values:
1. username
2. expiration time
3. a session code
When a user logs in, generate a session code and set an expiration time.
Store that session code and expiration time in the cookie and on your database.
Then whenever user returns to the site, and if user is not logged in:
1. check for the cookie
2. check for the cookie against the database
If all three variable matches and the expiration time is not over, log the user in.
Alternatively, if you simply encode the session code as say a md5 of ($username.$expiration_time), then you won't have to set up a database for storing and checking. Although having a database with randomly generated session code is much safer.
This is extremely unsafe. Since the cookie is the only thing you have to go by and the cookie is transferable from system to system, you would be vulnerable to cookie poisoning attacks and cookie copying attacks. If this is indeed the course you're set on, you will need to use some manner of foot-printing the user's system and storing that information in a database somewhere possibly as part of a persistent session on a session state server. This information could then be compared with the new login so if the cookie is transferred to a different system, it will not match and the automatic login will fail. As for accomplishing the login, I would recommend at a minimum to have a session state database where session information could be stored per session ID and username. If these 2 items are stored in the cookie, this information could then be used to get the information out of the database, and the foot-printing could be used as a stop-gap (although a very weak one) to prevent misuse.
The only information you need to store in a cookie is some unique hash that's going to point to the right user session in your system. Storing username or other information is redundant and unsafe considering the fact that username can be captured by an attacker and used with a combination of other information. To make the system more safe, you should implement a layer that'd check user's location by the IP address and his browser details. I suggest you should learn from what companies like Facebook and Google do with user accounts.
Place a random and uniqe hash in the cookie and store it in DB too with the current client's IP address.
If the user comes back, you can search for the hash in your DB.

Categories