When a user logs into my site it creates 2 cookies, one with a session ID (that relates to the user ID on the backend) and a remember me cookie that lasts for 3 months.
The remember me cookie is constructed as:
userid:timeout:hash
Where the hash is a HMAC SHA256 hash of userid:timeout to prevent tampering.
If the session ID does not exist (user closes their browser and opens it again so the cookie is gone, or the session ID does not exist in memcached) it looks at the remember cookie and re-generates a new session cookie, providing it has not timed out and the hash is correct.
However I don't see the point of having a session cookie at all, as the session ID just points to a user ID in the backend. I can use the remember me cookie instead to retrieve the current user.
So I am thinking of scrapping the session cookie completely, and would be interested in hearing some thoughts on this. Does this approach sound relatively secure? Could I make it any better?
Thanks in advance!
Yes, it is indeed secure enough for most cases, but why including user specific data in the cookie when you can avoid it? Also, there's a small disadvantage with this:
What happens if an user manages to steal a cookie from another user, you'd have to change the whole way the cookies are generated or that user will always have access, therefore resetting everyone's cookies. Imagine now that it's your cookie that gets stolen...
This is my solution for that: create another row in the user table called 'userhash'. When an user logs in, you generate a random hash without taking any of his input, just random, and store it both in the table and in the cookie. Then you only have to store userhash:timeout in the cookie. You check that against the database to see if it exists, if it does, that's your user. When the user logs out, the cookie and the row in the database gets deleted. For obvious reasons, you'd have to check that the cookie exists before comparing (there will be many empty).
Note: This method would only allow one registered cookie at once, so no laptop + desktop. This is good, since stealing is made more difficult as it only lasts as long as the real user doesn't log in, and bad because it only allows 1 computer. But you see the idea and how you could use this method but having several computers logged in... facebook-like.
PD, it'd be nice if you said how secure your app must be actually...
PD2, in case you haven't think about it yet, there are other more serious security concerns (SSL to say one).
Related
I am trying to understand security when it comes to session cookies in php. I've been reading a lot about it, but I still lack the specifics. I need the basics, someone to show examples.
For example: Do I place session_regenerate_id() before every session cookie? What more shall I think about. I am asking about specifics in code - examples if possible.
Thank you very much.
I am using 4 session cookies after logging in.
SESSION "site_logged_in" = true
SESSION "site_user_nr" = the number of the user to access user_table_nr
SESSION "site_user_id" = the user's id to use when changing data in tables
SESSION "site_user_name" = the name of the user to display on page
When I check if the user has access, I check if all 4 cookies are set, and if site_logged_in is set to true.
Are there better ways? Do I have the completely wrong idea about this? Can users easily be hacked?
In fact you need to have only one session in your website. When you call session_start() session is being created on server and user automatically gets session cookie. Think like session is a some sort of container that placed on the server, you can put whatever you want in that container. However session cookie is just a key to access that container on the server.
It means that you can safely put some data in the $_SESSION and only the user that have cookie with matching session id can read it.
About users being hacked. Yes they can be hacked as long as you don't use HTTPS connection, because cookies and all other data is being transferred in clear text, so if someone intercept users cookie he can access the data stored in the session.
Always use a security token for logging users. This security token could be generated by using crypt(). After logging users in, change the security token periodically until they log out. Also keep the server backup of all the session variables including the security token (in a database). This would also help you to track user login history.
One more personal suggestion: Never use any data from the database as session variables without encrypting it with any of the hashing functions or functions like crypt().
The session information is stored server-side. What you should check is that they're logged in, and that they exists/can log in (in case of deletions/bans).
As you're checking they exist/can log in, you can pull the other information from the database such as name, nr and so on. All you really need is a key called 'logged_in_user' or something that stores the ID of the logged in user. As Alex Amiryan said, the cookie can be copied, so you might also want to store the IP address of the last accessing view in the session, so you can try to ensure security.
What is the best way to securely authenticate a user ?
So far I was thinking of:
Generate a random $SALT for each successful login and store $logged = md5($hashed_password.$SALT) into database; delete on logout.
Store $logged into a cookie (If user checked "remember me"). Set $_SESSION['user'] = $logged;
On a visit: Check if $_SESSION['user'] is set; if not, check for cookie, if data doesn't match, redirect to login page.
What are the risks ?
The only issue I can see with your existing framework (which I like otherwise) is that there is the possibility of collision for $logged.
It is not mathematically impossible for two valid user log-ins to result in the same hash. So I would just make sure to start storing the User id or some other unique information in the Cookie as well.
You may also want to keep a timestamp of when the $logged was put in the DB, so that you can run cleaning queries where they are older than x days/weeks.
The first step is a bit overkill, as this is what $_SESSION['foo'] basically does client-side for the lifetime of the session. I'd just store a salted and hashed password for each user to begin with, salting with the date or other pseudo-random factors.
Setting the cookie might prove useless if the user clears their cookies, or the session expires. This will leave the user logged in (according to your database) when in reality they're not.
I'd stick to just $_SESSION['foo'] and cookies and leave the database out of the login process.
First No need of doing
Store $logged into a cookie (If user checked "remember me")
Starting the session should be the first thing you should do place session_start() on top of your index.php (file which gets executed) . This way a cookie name "phpsessid" gets created on user browser by default independent of weather user is logged in or not . value of this cookie is unique by which you can identify the user after he logs in. So you dont need to create any other cookie for this purpose.
In first point you have mentioned It create random SALT string when user logged in and clear it when user log out.
Main problem is you have to check SALT string is exist or not in each redirection of page. So it create heavy traffic in Database server.
Yes this is very useful for checkout user already logged in or not.
But in case of power failure in client machine after log in when Salt string remain in database after long time.
In second point to user authentication in cookie it is not secure. Client can easily show authentication cookie in browser
In third point to store authentication in session it means create session variable on server side and store it in file on server side. It is very secure then store it in cookie.
The best way to authentication is combine point number 1 and 3 which you mention.
You can check user already logged in form other pc or not?
You can easily clear SALT string if session is not exist.
You can easily manage Login in case of pc power failure
One problem I can see - your solution sounds annoying for people who load your site in multiple browsers at the same time.
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.
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.
I'm making a forum for learning mostly but hopefully it will have a couple of users some day.
What im wondering is should you use sessions or cookies for user authentication?
A cookie is a short piece of arbitrary data that the server sends through a header; the client stores it locally and sends it back on the next request. This mechanism can be used to maintain state from one request to the next even though HTTP itself is a stateless protocol. Cookies have two disadvantages: They offer only very limited amount of space (4 kB), and because they are sent back and forth in plain, a malicious client can fiddle with the contents before sending it back to the server, effectively making cookie data untrusted.
A session is a file on the server, identified by a unique ID which is sent back and forth between client and server so that the server can identify the client. The most popular way of sending the session ID is through the cookie mechanism, but it is also possible to pass the session ID through the URL (this is why you often see links that contain the URL parameter 'phpsessid'). This solves the two problems with cookies mentioned above: A file on the server can be as large as required, and the client cannot access the data other than through your own scripts.
Authentication is typically solved using cookie-based sessions; once authenticated, a new session is created, and the user ID is stored in it, and when logging out, the session is cleared and a new session ID is generated. Alternatively, you could store username and password in the session, and check them on every request.
Use a session.
A session is identified by a cookie, true, but not the same as storing user auth info in the client cookie, which is bad for security. A session cookie stores a guid or a hash in the cookie, then identifies the session (either database or file system based, depending on your server's php settings) based on that.
I recommend you store the primary key from your user table, not any other info, then look up the user info every time - this allows you to change their validation status, or security level on the fly while they are logged in; otherwise they will have to log out and back in before your administrative changes take effect for them - IE. you can't boot them.
Also, don't store the username/password, because that requires a less efficient query than by the indexed primary key (even if they are indexed as well).
They are essentially the same, working hand-in-hand. When you create a session..say through PHP, a cookie is created to store the session id too. On the other hand, you would create another cookie if you want to implement a "Remember Me" option to prevent your users from logging in every time.
I'm not a PHP expert, but Session and Cookie are related. In other programming languages you have the option of creating "Cookie based session" or "Cookie-less session". I'm not sure about PHP though so maybe you are referring to different concepts.
I feel using session is much more safe and easy then using cookies. The reasons are as follows:
1) In cookie we can only store a single piece of information, whereas in a session we can store as many information as we want.
2) Being stored on hard disk of user, cookies can be played with. Being a person interested in hacking, I have done that and gathered useful information about the user. Sessions cannot be used for such a thing.
If its a small amount of data (just one variable), I would use a cookie. Here is the code...
setcookie("cookie name", "cookie value or variable name", time+ 3600, "\");
this code sets a cookie that is readable for any of your webpages. It also will delete its self in one hour.
You can also see if the cookie exists like this (to see if it has deleted its self).
if (isset($_COOKIE['cookiename']))
{
}
to collect a value from a cookie...
$value = $_COOKIE['cookiename']; //makes a variable for this cookie for your program