I would like to know if i can prevent session id cookie malformation. Let's say I have a cookie with key SESS and value of md73i54kj98ti0uf8dftps2fa3 which is a valid session id and corresponding file sess_md73i54kj98ti0uf8dftps2fa3 exists in my session storage folder. If I modify value for key SESS cookie to be for example foo it will create new file in sessions folder with name sess_foo. How can I check that provided cookie sess id value is invalid so that I can call session_regenerate_id for example to set valid id and create appropriate file.
Also, I am wondering if someone hypothetically renames cookie sess id to real session of another user will he get control? are there ways around this?
Thank you.
Update 1: First problem can be solved with session.use-strict-mode ini directive. http://php.net/manual/en/session.configuration.php#ini.session.use-strict-mode
Though it requires some extra steps when using with custom session handler. (my case).
But still what if changed session id matches real session id of other user? Should I use some kind of fingerprinting (user-agent + ip) or encrypt session data with combined key of (user-agent + ip)?
For new session files being created, you already have the solution which is session.use-strict-mode.
But what about guessing another session id? You are totally right, if you can guess another valid id, you will be using that session, effectively impersonating its owner. After login, the session id is the only secret used by the user, equivalent to the userid+password for the session.
Why is this not a problem then? Because you can't reasonably guess another valid session id. Session ids are (should be) cryptographically random, and so long that you can't just guess one (more precisely, they have a lot of entropy). Standard solutions, like the one in PHP and most other programming languages or frameworks provide a reasonable level of security, but you should not implement your own session management (id generation, verification, etc.), unless you really know what you are doing and are aware of the security aspects.
In your example, the session id seems to consist of 26 lowercase letters and numbers. There are 26 different letters and 10 numbers, so the number of possible session ids are (26+10)^26 = 2.9 * 10^40. Say you can try one billion (10^9) ids every second, and your server has one million sessions at once (neither of this is realistic in any way). It would still take around 10^25 seconds (~ 3*10^17 years) to correctly guess a valid session id. Note that this is way more then the age of the universe. :)
Of course, for the reason above (session id = username+password for the session), you must protect the session id as much as you can, for example by only storing it in an httpOnly cookie, and never sending it in the URL, or clear text (but always using https, with the secure flag for the cookie, and HSTS headers sent, etc).
Related
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.
I'm not exactly sure how the $_SESSION work in PHP. I assume it is a cookie on the browser matched up with an unique key on the server. Is it possible to fake that and by pass logins that only uses sessions to identify the user.
If $_SESSION doesn't work like that, can someone potentially fake cookies and bypass logins?
Yes.
The only thing identifying a user is a pseudo-random value being sent along with each request.
If an attacker can guess the right values to send, he can pose as somebody else.
There are different ways to make this harder:
make session ids longer (more entropy, harder to guess)
check additional information like the user agent (essentially more entropy)
obviously: use a good random number generator
expire sessions sooner to give a smaller set of valid session ids at any one time
renew session ids often, even for valid ids
use SSL to encrypt all communication to avoid outright cookie hijacking
Sessions in PHP by default store the data in a file on the server (/tmp/) and store an identifier cookie usually PHPSESSID (it will be a hexadecimal number, e.g. f00f8c6e83cf2b9fe5a30878de8c3741).
If you have someone else's identifier, then you could in theory use their session.
However, most sites check to ensure the user agent is consistent and also regenerate the session identiifer every handful of requests, to mitigate this.
As for guessing a session, it's possible, but extremely unlikely. It'd be easier to guess credit card numbers (smaller pool of characters (0-9 over 0-9a-f) and a checksum to validate it). Though of course you'd also need the expiry and security code.
Properly implemented, session ids are very long and random enough to make guessing unfeasible (though if you were able to guess a particular user's session id then yes you would be acting as that user). However you can sniff and hijack sessions -- this is what firesheep does: http://en.wikipedia.org/wiki/Firesheep
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.
I've been interested in how sessions work internally, but I have little knowledge of C (and am unsure where to look in the PHP source for this).
This is what I understand of sessions at the moment:
When you start a session the user gets assigned a session id which is stored in a cookie.
When session data is saved (via $_SESSION) it is stored on the filesystem, with the relevant session id and an expiry time.
Is this correct? Also what is the method in which session id are created? I assume it's based on time but what if two users send a request at the same time? What methods are in place internally to prevent them getting the same id?
Thanks,
My understanding is of the internal session handling process is the following:
When session_start is called, PHP is looking for a parameter from the client that was sent via POST, GET, or in a cookie (depending on the configuration; see session.use_cookies, session.use_only_cookies, and session.use_trans_sid) with the name of the value of session.name to use the session ID of an already started session.
If it finds a valid session ID, it tries to retrieve the session data from the storage (see session.save_handler) to load the data into $_SESSION. If it can’t find an ID or its usage is forbidden, PHP generates a new ID using a hash function (see session.hash_function) on data of a source that generates random data (see session.entropy_file).
At the end of the runtime or when session_write_close is called, the session data in $_SESSION is stored away into the designated storage.
Look at php_session_create_id in ext/session/session.c in the php source
It goes like this:
get time of day
get remote ip address
build a string with the seconds and microseconds from the current time, along with the IP address
feed that into configured session hash function (either MD5 or SHA1)
if configured, feed some additional randomness from an entropy file
generate final hash value
So getting a duplicate is pretty difficult. However, you should familiarise yourself with the concept of session fixation, which allows an attacker to potentially choose the session_id their target will adopt - see Sessions and Cookies for a good primer.
The session ID is probably just a random string of letters and numbers. Also it would be strange if PHP didn't check to see that it is unique and therefore cannot be the same for two users. As for (1) and (2), I'd say you're correct, but I haven't worked with PHP recently, so feel free not to believe me.