Correct me if I'm wrong please:
Sessions will last a finite amount of time (refreshed from the server every 15 or so minutes until the browser is closed) - more secure/short term
Cookies on the other hand can last until the browser closes or to some specific time in the future - least secure/long term
Given this, how do allow a user to close his/her computer, come back a few days later and open a site and still be logged in using cookies and still somehow being secure?
How does someone like, amazon for instance do this?
EDIT:
To be more clear, here is an example:
if (!isset($_SESSION['id']))
{
$_SESSION['id'] = $_COOKIE['id'];
$_SESSION['email'] = $_COOKIE['email'];
}
this is obviously bad, what is a better way?
First of all, "session" is more of a concept rather than a concrete implementation.
For PHP I believe the default way that session data is stored on the file system and it is associated with a session id that is usually stored in a cookie (although it can also be sent via query string parameter:http://stackoverflow.com/a/455099/23822).
It's also possible to store session in a database. Doing so allows you full control over how session data is stored and when it expires so you can have sessions that last as long as you want them to. You just need to make sure the session cookie also shares the same expiration time as the data in the database.
As to your question of in a comment about "What's stopping someone from grabbing the cookie data and falsifying a login using the token?" Theoretically that can happen, but the session ID stored in the cookie should be random so it would be highly unlikely that it would be guessed (an attacker would have a much easier time guessing the user's password). In fact the same thing is already possible with any kind of session.
Sessions expire mostly because keeping them open on the server is inefficient. You need a cookie (or some other mechanism, but cookies are usual) to associate them with a browser anyway.
Amazon handles security by having three levels of "being logged in".
Level 1: Basic functionality just works.
Level 2: You must reenter your password to access some things (e.g. order history)
Level 3: You must reenter payment information to access some things (e.g. adding a new delivery address)
For the cookies I use the method described here:
http://fishbowl.pastiche.org/2004/01/19/persistent_login_cookie_best_practice/
and here: http://jaspan.com/improved_persistent_login_cookie_best_practice
You store a session-based security token inside the user's cookie data, and store that same token in the user's db table. At session creation, you check if this username/token pair can login to your website according to the previously stored data, and then invalidate the token.
Related
This question already has answers here:
Creating a secure login using sessions and cookies in PHP
(5 answers)
Closed 9 years ago.
I would like to know what would be a proper way to create a login procedure.
Up to this point I thought it would be a good way to create a $_SESSION['login'] and even a $_COOKIE['login'] that both have the same content which is a kind of a timestamp plus an encrypted form of the password.
The logic behind that idea is to check if both exist and to compare their contents. If both exist and is the content equal you get access to the protected pages.
I do know that a Cookie is a kind of a Session. A Cookie will be stored on the users client site and the a Session as well but will last only as long as the browser will be open. I thought it would be possible to extend the lifetime of a Session even when the browser will be closed and the Session destroyed.
This should ensure that the SESSION could not be hacked and the COOKIE be stolen what makes it impossible for a hacker to get access to a profile of an User.
Am I right with that thoughts or how do you people did it?
Thanks alot.
First off you need to understand the difference between sessions and cookies.
Sessions and cookies are both key=>value stores. But where they're stored has great impact on their security properties.
Cookies are stored on the client machine. They are unsafe. A user can modify the value of a cookie, forget a cookie, send more cookies etc. Cookies can be stored for a very long period of time (months, years). Since the client stores the cookie you don't need to worry too much about space constraints. Just keep in mind that all the cookies are sent with every request.
Things you store in cookies are typically fairly inconsequential things like some preference settings or "I've already seen your popup asking me about questionnaire".
Session data is stored on the server, only the server can read from it and write to it. The user never sees what is in the session. Session data typically expires quickly, let's say anywhere between 30 minutes and 24 hours.
But how do you know which session belongs to which visitor? Well, you use a session identifier cookie. This is the only cookie you need for authentication. In PHP this cookie is PHPSESSID and it's created and used automatically when you call session_start();. The session cookie is a cookie with a random value that is hard to 'guess', which makes it secure.
The user will keep the session cookie. You can find the associated session data (automatically using $_SESSION). In the session data you can store whether the user is logged in, if so as which user, you can even store the rights a user has (like a mini-cache). You can treat this as an untamperable key=>value store, just make sure not to store too much in there (the limits depend on the storage mechanism).
Sessions are stored in a specific place; where depends on your webserver and OS. In PHP you can specify your own session storage handler by calling session_set_save_handler. This allows you to, for instance, keep your session data in a database.
If the value of the session identifier cookie is somehow exposed an attacker can hijack the session. It can be exposed by using an unsecured connection on a wifi access point (like in a bar). To counter this use HTTPS; cookies sent over HTTPS are encrypted and safe from this kind of man-in-the-middle attack. This is what the Firesheep plugin did (in 2010)
I am programming a PHP site that allows users to register, and both registered and unregistered users can enter their respective usernames and passwords (for example smith8h4ft - j9hsbnuio) for school site.
Then, my PHP script sends some $_POST variables, downloads and parses the marks page, making an array called:
marksDB = Array("subject" => Array("A", "B", "A", "C"), ...), and writes it reformatted.
My question is:
How should I keep the username and passwords safe?
For unregistered users, I currently forget username and password and put the marksDB into $_SESSION. When user is inactive for e.g. 30 minutes, marksDB is deleted. How safe are these data in $_SESSION ? And how about users that log in, view page once, and never view it again, so the script doesn't delete the marksDB from session? Is the session deleted automatically (gc.maxlifetime)?
And what about registered users? I want to have everything safe, but I don't want to annoy user with password prompts every 30 minutes of inactivity. Is it safe to encrypt credentials like described here, but without the third user-set password? Or have I to ask the user for his password every time?
EDIT:
Thanks for quick replies,
#Justin ᚅᚔᚈᚄᚒᚔ : I doubt they have some API, but I can ask them, just for case
#Abid Hussain: Thanks for very useful links. (Thanks both for answers too).
I will throw users' credentials away and have only parsed markDB, which I will probably throw away too (after logout or inactivity) - it is cheap to retrieve marks again when needed.
If the school site doesn't expose an API for this (for example, using OAuth like the StackExchange sites do), then your options are limited.
Generally speaking, it is never a good idea to keep a user's plaintext credentials for longer than is absolutely necessary. There are security implications for any possible way you can imagine to try to do it (session hijacking, stolen keys, decryption, etc).
A better approach might be to make the marks download process strictly user-initiated. Give them a button that says "retrieve my marks", and go through the authentication process there, download the marks, and throw away their credentials. Each time they "sync", they should have to authenticate. Unless the marks change on a frequent periodic basis, there should be no reason you can't download all the information you need at once and then cache it securely on the server for later usage.
session files will be deleted by the garbage collector after a certain time, but a good rule of thumb for storing in _SESSION is only store data that you would output on the screen, i.e. the password is probably not something you want to store in the session. Session files can be read from the server and it's possible for some nefarious user to hijack the session and see things they are not supposed to see or even somehow see a var_dump($_SESSION).
If you want to allow registered users longer sessions you can have periodic page refreshes with JS (not necessarily refreshing the page .. just an asynchronous request will do) or perhaps even increase the session time with ini_set if allowed. It's not necessarily safer to ask for passwords repeatedly .. it depends on how vulnerable the password is when you are asking.
Another solution is to have the infamous "Remember Me" cookie keep the users logged in.
Passwords are not for decrypting. Encrypt for secrecy. Hash for authentication.
Everything in the session is server side, so it's not accessible by others. However, sessions can be 'hijacked' as explained here.
You could increase the length of the session in your PHP.ini or use periodic AJAX calls on the background to keep the session alive. The sessions are deleted when they are expired by the server.
Encrypting a password so it can be decrypted is usually frowned upon unless there is no alternative. With encrypting, not only you, but also everyone else with access to your database and/or source code can retrieve the passwords.
See URL
http://phpsec.org/projects/guide/4.html
http://www.sitepoint.com/blogs/2004/03/03/notes-on-php-session-security/
http://talks.php.net/show/phpworks2004-php-session-security
http://segfaultlabs.com/files/pdf/php-session-security.pdf
safest way to create sessions in php
Also Read it
Sessions are significantly safer than, say, cookies. But it is still possible to steal a session and thus the hacker will have total access to whatever is in that session. Some ways to avoid this are IP Checking (which works pretty well, but is very low fi and thus not reliable on its own), and using a nonce. Typically with a nonce, you have a per-page "token" so that each page checks that the last page's nonce matches what it has stored.
In either security check, there is a loss of usability. If you do IP checking and the user is behind a intranet firewall (or any other situation that causes this) which doesn't hold a steady IP for that user, they will have to re-authenticate every time they lose their IP. With a nonce, you get the always fun "Clicking back will cause this page to break" situation.
But with a cookie, a hacker can steal the session simply by using fairly simple XSS techniques. If you store the user's session ID as a cookie, they are vulnerable to this as well. So even though the session is only penetrable to someone who can do a server-level hack (which requires much more sophisticated methods and usually some amount of privilege, if your server is secure), you are still going to need some extra level of verification upon each script request. You should not use cookies and AJAX together, as this makes it a tad easier to totally go to town if that cookie is stolen, as your ajax requests may not get the security checks on each request. For example, if the page uses a nonce, but the page is never reloaded, the script may only be checking for that match. And if the cookie is holding the authentication method, I can now go to town doing my evilness using the stolen cookie and the AJAX hole.
The session file is server side so it should be invisible to clients. But they still can trick your program into using another session if they know the session ID.
For the registered users you can store the password in a DB or a file after you have encrypted it with a key that only you know (maybe a new one generated randomly and stored for each user)
I am just starting to learn to program in PHP and have ran into a slightly confusing area, Sessions and Cookies.
I understand the server-side and client-side storage differences but i cant see how they differentiate and in what circumstances would each be appropriate for?
Also, i have seen people say that the cookie could be used to store a session id, How would this be done and why would this be advantageous?
Thanks for any feedback.
First of all, let's bust the longstanding myth (or at least I think it's an existing myth) that a session cookie is something different than a regular cookie. It is not. A session cookie is just a regular cookie. Only the properties of the session cookie that are set (or rather not set) are typically different. But the mechanism is exactly the same.
A cookie is set by sending a http response header to the browser:
Set-Cookie: name=value[; possible expiration-date][; other possible properties]
What typically distinguishes a session-cookie from a regular cookie is that no expiration date is set (or the expiration date is set to a date in the past). Which means the browser will dispose the cookie after closing the browser. But a 'regular' cookie can do this just as well. Thus thereby making it a 'session cookie' so to speak.
Now that we have that out of the way; the mechanism by which cookies are typically utilized by applications to make them act as even more of a session cookie, besides above mentioned properties, is that the value of the cookie only holds a uniquely identifiable value of some sort. Perhaps an md5 of maybe a sha1 hash.
Each time the browser requests a resource on the server it sends along this cookie (unless it has expired) with a http request header like this:
Cookie: name=value
The session mechanisms in the backend (being PHP in your case) linked the unique id of the cookie with data that has been stored in a file in the servers filesystem, or perhaps in a database. This way, each time the cookie is received it is able to retrieve this data and link it to the request.
The advantage of this, is that sensitive information 1) can be hidden from not having to travel over the net, and 2) doesn't end up in the users browser cookie cache, by keeping it at the server.
So, basically you want to send non-sensitive, and non-application-vital information in a regular cookie (think of: layout preferences, a non-persistant playlist such as on YouTube perhaps, etc.), and use a session to store sensitive information.
edit:
Sorry, ignore the "or the expiration date is set to a date in the past", as it was false. This will cause the cookie to immediately be invalidated by the browser, and thus not be sent along with requests anymore.
The advantage of using cookies over sessions is that cookies are persistent.
In other words, when the user visits your site weeks later, their session has more than likely expired. However, if they have a cookie that can uniquely identify them to your script, then you can automatically log them in and reestablish the session.
...what circumstances would each be appropriate for?
The answer looks something like this:
Session data should contain information that does not need to be persistent or is only needed for a short period of time. For example, if you are presenting a multiple-page form to the user, it makes sense to take advantage of sessions.
Cookies should be used to store an ID or hash that uniquely identifies not only the user, but also the browser / device they are logged in with. Keep in mind that cookie data is out of your control and can only be manipulated / removed by HTTP requests made by the user (or under certain circumstances, by a script on a page).
Also, i have seen people say that the cookie could be used to store a session id...
I'm assuming what was meant by that is storing a unique value in a cookie that identifies the user / browser / device that they are using. Implementing something like this would look like:
Let the user log in as they would normally.
Generate a unique hash (SHA-1 is your best bet) and store that in a cookie. You also store the hash in a database linked to that user.
...
The user returns after their session has expired and visits a page.
Your script sees the cookie and looks up the user that the hash belongs to.
The user is logged in.
Both cookies and sessions are used to keep user-specific information in order to track a user. A lot of times you can use either one, but they have some differences.
A cookie is a text file kept on the user's machine. Every time the users visits your site he hands over the cookie letting you know who he is. The advantage of this is that the information is kept on somebody else's machine so you don't have to worry about it. As such you can leave it there until the cows come home. When/if the user comes back he'll bring the information with him. The downside is that the information is out of your control because the user can easily edit the cookie you gave him. This makes any information in a cookie untrustworthy and has to be checked every time the user gives it to you.
A session is like a cookie except you keep the information on your server. The advantage is that you can trust a session to keep data exactly like it was when you put it in. The downside is that you have to store that information which means that eventually you'll need to discard it lest your webserver fills up with information that will never be used.
Now this is where it gets a bit tricky. You see while the mechanism of a session is as I described above, the actual implementation can vary depending on PHP's settings. The session data can be kept in individual text files or in a database on your server. Also you need some way of recognizing which session corresponds to which user. The usual (but not only) way to do this is with cookies. What happens is that the actual data stays on your server and is linked to a unique session id. That session id number is put on a cookie and given to the user so you can later look up his data when he comes back.
The above process is performed automatically by PHP when you use the session functions; you do not need to implement it by hand. If for whatever reason you need to change how sessions are implemented you can do so by changing the session parameters in php.ini.
I know about all the issues with session fixation and hijacking. My question is really basic: I want to create an authentication system with PHP. For that, after the login, I would just store the user id in the session.
But: I've seen some people do weird things like generating a GUID for each user and session and storing that instead of just the user id in the session. Why?
The content of a session cannot be obtained by a client - or can it?
You're correct. The client just sees a randomly generated session id token. There are ways this token can be misused (hijacked, etc.), but having a GUID on top adds nothing. In contrast, options like session.cookie_httponly (JavaScript can't see session cookie) session.cookie_secure (Cookie can only be transmitted over HTTPS) protect against certain attack scenarios.
The short answer is that $_SESSION is safe and you do not need to worry about its contents being leaked to a user or attacker.
The content of the session is not normally be accessible to the user. You should be able to store the user's primary key and you'll be fine. There are cases where the session can be leaked, on a normal linux system the session folder is in /tmp, however this could be changed in your php.ini to the web root (/var/www/tmp) and then could be accessible. The only other way is if the user is able to get access to the $_SESSION super global by hijacking a call to eval() or by the variable being printed normally.
If you are running on a shared host and using an old version of PHP and/or your server is misconfigured it might be possible for another user on this system to read or even modify a session file stored in /tmp/. I don't know of a single application that takes this attack into consideration. If this is a problem you can store the information in a session table in the database.
Sometimes, for added security, developers may assign a long string to the user's session in order to make hijacking even more difficult. By setting a cookie with this new string at the time of session creation, the app can check for the correct string on subsequent requests to better ensure it is the person who actually logged in.
It's just adding one more thing a wannabe hijacker would have to guess. However, it can be a false sense of security as it does little to protect the session if sniffing is involved because the new cookie is sent right along with the php session cookie. Also, session id's are very hard to guess as it is (as I'm sure you know, just don't place it in the url but, rather, in the cookie).
Session info is stored on the harddrive so it's not obtainable by clients without application intervention.
I've never seen GUIDs being used for sessions, but there are a couple of additional methods I have seen that do add a little more security.
Storing the user's IP - if you need to force a session change based on locations (sometimes geoIP stuff will do this)
Storing the user's HTTP_USER_AGENT header string. Can provide a bit of security against hijacking if the hijacker happens to be using a different browser.
There's a great article on session hijacking countermeasures on Wikipedia, actually.
That being said, I would imagine that anyone storing a GUID as part of a session to use in session security might be failing to see a better solution (such as session regeneration). I can see other uses for a GUID to be stored (maybe it's part of a random generator for a game), but not for use with session security.
When a user logins I get him/her's ID and save it in a session var. What I wonder is, is this the way to go? Or should I use cookies? so it automatically login and so on.
session_start();
ifcorrectlogin {
$_SESSION['id'] = mysql_result($loginQuery, 0, 'user_id');
}
how do you authenticate your users?
//Newbie
Yes, this is the way to go. The session itself is already backed by a cookie to remove you any programming efforts around that. The session (actually, the cookie) will live as long as the user has the browser instance open or until the session times out at the server side because the user didn't visit the site for a certain time (usually around 30 minutes).
On login, just put the obtained User in the $_SESSION. On every request on the restricted pages you just check if the logged-in User is available in the $_SESSION and handle the request accordingly, i.e. continue with it or redirect to a login or error page. On logout, just remove the User from the $_SESSION.
If you want to add a Remember me on this computer option, then you'll need to add another cookie yourself which lives longer than the session. You only need to ensure that you generate a long, unique and hard-to-guess value for the cookie, otherwise it's too easy to hack. Look how PHP did it by checking the cookie with the name phpsessionid in your webbrowser.
Cookies can be manipulated very easily. Manage login/logout with Sessions. If you want, you can store the users emailaddress/username in a cookie, and fill the username box for them the next time they visit after the present session has expired.
I would try to find a session engine so you don't have to deal with the misc. security issues that bite you in the ass if you do the slightest thing wrong. I use django which has a session engine built in. I'm not aware of the other offerings in the field although I would assume most frameworks would have one.
The way they did it in django was by placing a cryptographic hash in the user's cookies that gets updated every page view and saving all other session information in a database on your server to prevent user tampering and security issues.
As BalusC mentions, the session_-functions in php are the way to go, your basic idea is sound. But there are still many different realisations, some of them have their pitfalls.
For example, as Jonathan Samson explains, using cookies can result in security holes.
My PHP is a bit rusty, but I remember that the session_-functions can also use session IDs that are encoded in URLs. (There was also an option to have this automatically added to all local links (as GET) and form targets (as POST). But that was not without risks, either.) One way to prevent session hijacking by copying the SID is to remember the IP address and compare it for any request that comes with a valid session ID to to IP that sent this request.
As you can see, the underlying method is only the start, there are many more things to consider. The recommendation by SapphireSun is therefore something to be considered: By using a well tested library, you can gain a good level of security, without using valuable development time for developing your own session system. I would recommend this approach for any system that you want to deploy in the real world.
OTOH, if you want to learn about PHP sessions and security issues, you should definitely do it yourself, if only to understand how not to do it ;-)