After reading a great post on PHP session security .I have two questions from the discussion.
1)$_SERVER['HTTP_USER_AGENT'] -This gets the information about the user's browser and other details and since a person can access their account from a different computer then how is it useful?
2)session_regenerate_id - This regenerates a session id , How should I use it ? Is the session_id deleted after a session has timeout or closed?
Thanks for all your help.I appreciate each view and response.
$_SERVER['HTTP_USER_AGENT'] , you can use this information for when you are using special features that may not work for everyone, or if they want to get an idea of their target audience. This also is important when using the get_browser() function for finding out more information about the browser's capabilities. By having this information the user can be directed to a version of your site best suited to their browser.
session_regenerate_id, When it renames the session id it does not remove the old session, leaving it active and potentially usable by a would be hacker. This does not pose a problem if the function is only used during new session create as the means of preventing session fixation, which is the intended use btw. However, it makes it completely useless if used on each session based request to prevent session leakage via HTTP_REFERER and similar, since the previous session id is still usable. It also means that changing the id on “actions” as some scripts to do prevent session theft also is pointless; in fact it doubles the amount of session ids for the same user making it only simpler to assume their identity. Furthermore it means that on every call to the function there is duplication in the number of sessions entries that will hang around until they are considered expired and removed by the garbage collection process.
The User-Agent is useful for determining the browser being used, which may lead to guessing some of its capabilities. For example, most mobile devices can be accurately identified by their browser's user agent (see WURFL), thus allowing a site's developer to direct mobile devices to the site's mobile version.
However, it can be modified by the user, so its value should be taken with a grain of salt as is the case with any user input.
session_regenerate_id() doesn't delete the session. It merely changes its id to a newly created one. To avoid having its old session file hang around until auto deletion by the system, you can delete it yourself by setting the optional function parameter to true. Its use is to avoid session fixation attacks where an attacker can gain access to an existing session's data by knowing and presenting its id to the server.
1) Sessions aren't bound to accounts, they're bound to browser sessions. You can use the user agent information to see if that someone other user agent is trying to hijack the session. However it's not fail-proof. You can also use things like the user's IP address (or a given range of it) to catch hijack attempts.
2) By calling session_regenerate_id from time to time, you reduce the chance of someone hijacking the session. This is especially true if the session ID is passed in the URL. For example let's say someone accidentally pasted a link to a chat with the SID in the URL. If you regenerate the session ID periodically, the users who saw that link can't hijack the session with it, as the ID would've changed already.
I'll try to answer your questions from the bottom up: session_regenerate_id() is useful in preventing session fixation attacks, where a malicious user who has obtained your session ID hijacks your session and can then act as you. When you regenerate the session, you can track the latest session ID in a database or something similar, and only allow access with the most current session ID (incidentally, if you regenerate sessid frequently enough, this will prevent users from browsing your site with multiple browsers/windows), otherwise old sessions will be available by default (unless you pass a boolean true parameter to the session_regenerate_id function call).
Some security-crazy people will suggest regenerating the session ID after every request, but you can also track a session variable that increments per request, and just regenerate every X number of requests (5 or 10 or whatever you determine is a sufficient amount for your security level). The other option is to regenerate the session ID during a privileges escalation, such as logging in.
As for HTTP_USER_AGENT, it is mostly useful in implementing browser/client-specific functionality (for example, displaying a "Get Chrome!" link when users visit your site using Firefox or IE).
Related
I'm using session variable for login purpose. If login is successful $_SESSION['userName'] is set. In some pages there are codes like if(isset($_SESSION['userName'])) echo $_SESSION['userName];
I wonder if $_SESSION['userName'] is already set by other website in someone's browser it will lead to a huge problem. How may I overcome this problem, please suggest.
The session value is communicated between a browser and a server by HTTP cookie.
The HTTP cookie is only shared on the same host name like (*.stackoverflow.com)
So, I think another website cannot be get a session value of others.
So this is how a PHP session works.
PHP generates a session id for a specific user. It then hashes that ID and passes the hash to the user as a cookie.
On each subsequent request the user send that cookie back, PHP and looks up the session data for that session hash. It is then able to start the session associated with that user. In that sense no other user is able to access the first user's session without knowing the session hash.
However the end user is vulnerable to session hijacking in case someone else steals their cookies and there's a number of ways this can happen.
Session fixation which someone tricks a user of your site to use a session ID that someone has provided them (there's not much you can do about this).
Man in the middle attacks where someone is between the user and your website and intercepts all data that get passed along. This usually can be protected against by serving the page under HTTPS (not always but it's a lot harder for someone to steal data that comes over HTTPS).
Cross-site scripting (XSS), when someone uses client-side code (which can access cookies) to impersonate that user. You can protect against this by implementing CORS restrictions and sending a "nonce" with each response which you expect the user to return when they send the next request.
Taking advantage of browser exploits that expose the user's cookies to another website. It's normally a requirement to browser manufacturers to prevent websites from accessing cookies they did not set, but sometimes bugs can be present that prevent this. This is usually taken care of if the user keeps their browser up to date (not because exploits are not there but because most people haven't found them yet).
Someone breaks into a user's house and uses the user's browser (can't do anything about this one either).
There's probably more ways
i have just learning session fixation attack from this atricle
http://shiflett.org/articles/session-fixation
but for defence of this attack i do not understand what is the usage of session_regenerate_id()?
when attacker include session id in url and say to server that i want use this session so all of the session variables related to this session is for him so why regenerating id is useful?
thanks
Throughout the lifetime of a website, there will be many 'sessions'. Each of these sessions is identified by an ID, and is how the web site knows who is who and is able to keep state between different requests.
A session fixation attack is really only possible if you can get ahold of the session id. Some sites allow sessions to persist between different actual browsing sessions (aka 'Remember Me' functionality), and are more vulnerable to this attack if the same session id is used.
If I get ahold of your session id then I can impersonate you only so long as that session id is valid. Using session_regenerate_id, the old ID becomes invalidated, making it useless to anyone who may have intercepted it. If you generate a new ID once a user successfully authenticates themselves, then any of the attempts at capturing a session identifier will no longer yield a valid identifier for an authenticated user (only the 'anonymous' session that the user had prior to authenticating themselves), meaning attackers can only 'impersonate' anonymous users.
Some more security conscious frameworks actually regenerate the session id within browsing sessions (using a timeout as low as 2-3 minutes) rather than just whenever a user logs in to help guard against people grabbing the session id via packet sniffing on the network. Session IDs can only be regenerated in response to a request.
The key point to have in mind is that in order to maintain session state, on every request the client reports its current session id to the server. The reporting mechanism itself (e.g. through a cookie or a URL parameter) is not important here.
From the viewpoint of the server, and excluding advanced precautions being taken¹, the session id reported by the client is authoritative: the server doesn't have a notion of a "correct" or "real" session id for any particular client. Clients are who they say they are.
Of course this raises the question: what is then preventing me from declaring that I am a site administrator with privileges to do anything on your application? Only the fact that I don't know the session id of the real administrator (assuming the real admin does have a session). If I did, I could impersonate the admin and do whatever they can do.
So now from the attacker's viewpoint: how can I learn the admin's session id? Tricking the admin into reporting to the server a specific session id of my own choosing would work! This is the essence of the session fixation attack.
There are several ways to prevent or mitigate the effects of this attack, and one of them is to make the server tell the client "I changed your session id; from now on, use this one". Of course the client is not forced to comply, but friendly clients will of course do so (and the server can refuse to recognize clients even if they were hostile). So even if the attacker manages to trick the admin into using a specific session id known to the attacker, the attack will work only as long as the server doesn't instruct the client to switch to a different session id.
And that's exactly what session_regenerate_id does.
¹ Advanced precautions: for example, the server might keep a track of the last IP address used by the client for each session id. If the server sees a request with a given session id coming from a different IP address then that could be considered suspicious. Of course this simplistic example cannot account for the sophistication of modern internet infrastructure, but the idea is clear. High-security services (e.g. Gmail) use sophisticated techniques of the same type to detect and prevent suspicious activity.
It the session ID is in the URL and the attacker somehow gets another user to visit this URL, the attacker will know the session ID.
e.g. suppose the attacker places this code snippet on their own website "evil.com" (session ID trimmed for brevity)
Login to site to continue
and then induces their victim to visit their site (e.g. sending them an email containing a link to "evil.com"). If the user visits the attackers website, and then follows the link to "example.com" and then logs in it may be possible for the attacker to follow the same link and hijack the now logged in session (as the IDs will match). e.g. the link could be to a funny video on Facebook but will contain the session ID in the URL rather than just a straight login page.
However, if however session_regenerate_id() is called as part of the login process (just after username & password are verified) the session ID will now be new and the attacker will have no way of hijacking the session using this method.
This is not a vulnerability restricted to session IDs in the URL. Say the rest of the website is HTTP and after login the session is moved to HTTPS then it is also wise to regenerate the Session ID because the existing Session ID could have been intercepted when the traffic was on HTTP.
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).
After hours of reading and trying to understand sessions, this is my general conclusion/perspective:
Simple (and realistic) situation:
Attacker takes an existing website 'website.example.com' and put random SID behind URL '9gag.com/?SID=1234'
Attacker paste this URL on a 'forum' with text: '9gag gives away free stuff for first 1000 logins!'
Victim recognizes the website, because he has an account there, he quickly clicks on the given URL.
Victim gets on the site and logs in.
Because Victim clicked on the '9gag.com/?SID=1234' and logged in; he is now logged in on
a session with id=1234. Note that every session has a unique id. This is necessary for the server to handle each session individual. It is possible though to get on the same session (with same id) from several computers at the same time.
Attacker goes to '9gag.com/?SID=1234' too. He is now on the same session as the Victim. This means that he is logged in like the Victim. He can see all the Victims account settings and change them.
To prevent this, the host of this site can use the following PHP code:
<?php
session_start();
if (!isset($_SESSION['initiated']))
{
session_regenerate_id();
$_SESSION['initiated'] = TRUE;
}
?>
When initiated is true (so when random sessionID has been generated)
a new sessionID won't be generated. Otherwise, generate new sessionID.
So when a victim logs in with a given sessionID '1234', it will throw
it away and generate a new one. Now the Attacker can't get on the same
sessionID as you because he does not know it.
The Attacker is smart and knows another way:
Attacker goes to the site and logs in. A new sessionID has been generated from PHP server.
Attacker looks in his COOKIES to see what sessionID he received. He finds SID='412e11d5'
Attacker does the same steps as before, but uses the given ID instead of '1234'. -> '9gag.com/?SID=412e11d5'
QUESTIONS: How is this possible?:
Is the $_SESSION['initiated'] based on the given ID? So 'initiated == true' because it uses the session of id '412e11d5'?
Attacker made the session first, otherwise the ID couldn't have been generated. So shouldn't the Victim get on the Attackers session (on his account settings,..) instead of visa versa?
It looks like session fixation is based on a lot off luck. The Attacker has to get on the website at the same moment as the victim. I guess I just don't get how this works..
EDIT: Attacks using cross-site cooking:
Attacker creates an own website 'evil.example.com' that stores an specific sessionID in the COOKIE of an existing website '9gag.com'.
Victim clicks on the URL 'evil.example.com' just like in the other examples. A sessionID has been stored in his COOKIE of '9gag.com'.
Victim logs into '9gag.com' later that day.
Attacker can now use Victim's account using the fixated session identifier.
QUESTIONS: again, how is this possible?:
Even if the Attacker can store something in the COOKIE of another website. How/when can he get on the same session as the Victim? Seems he doesn't have to log in at the same time? Or can he just get the Victims private data in another way (but with use of sessionID)?
PLEASE MODIFY ANY MISUNDERSTANDINGS FROM MY PART! Thanks in advance.
Is the $_SESSION['initiated'] based on the given ID? So 'initiated == true' because it uses the session of id '412e11d5'?
No, it's based on a given session. But initiated == true, since for that given session it is initiated. The session is saved with that id at that time, yes, so that session with that id is initiated.
Attacker made the session first, otherwise the ID couldn't have been generated. So shouldn't the Victim get on the Attackers session (on his account settings,..) instead of visa versa?
Yes. But if the attacker created a session without logging in, and Victim would log in, it would be (originally) attackers session, but victims logging details.
It looks like session fixation is based on a lot off luck. The Attacker has to get on the website at the same moment as the victim. I guess I just don't get how this works..
No, the attacker doesn't need to get in at the same moment. Just when the session is still valid with the given id.
Now, an easy solution for all this is to disable session id in urls (trans_sid). This should be always done.
For more security, session id can (and in some cases should) be regenerated on every request/response.
When a low-privilege non-administrator user logs into my web app successfully, I am storing the following data in the $_SESSION array:
$_SESSION = array(
'user_id' => 2343, // whatever their user_id number is from the DB
'allow_admin' => false, // don't give them access to admin tools
'allow_edit' => false, // don't let them edit stuff
);
Is there any way that they could manipulate the $_SESSION array to give them Admin or Edit access, apart from somehow editing the session files in /tmp? (The above code is the only place where those items are added to $_SESSION)
The contents of the session are only visible and modifiable on the server side.
They could only be modified in an "unauthorized" way if your application or server contains some vulnerability.
You should also be aware of such things as session fixation attacks, where an attacker forces a particular session id onto an unsuspecting user, who when logs in and elevates that session's privileges, allowing an attacker to share that session.
One approach to mitigating these is to regenerate the session id whenever you change privilege levels of the session.
See also this question:
PHP Session Security
If you want to avoid javascript reading your cookies and man in the middle attacks, you need to use a server with https and set the session cookie to only be transported over https.
session.cookie_secure specifies whether cookies should only be sent over secure connections. Defaults to off. This setting was added in PHP 4.0.4. See also session_get_cookie_params() and session_set_cookie_params().
session.cookie_httponly Marks the cookie as accessible only through the HTTP protocol. This means that the cookie won't be accessible by scripting languages, such as JavaScript. This setting can effectively help to reduce identity theft through XSS attacks (although it is not supported by all browsers).
To secure admin privileges better for someone leaving his computer unguarded for a few mins, you should have a timer on last (admin) login. If that time is more then x timeunits away, the user has to login again to use admin rights.
Shorter sessions are also more secure then longer ones.
Server
Sessions are stored on the server. A user could change session data if they have direct access to the directory where sessions are stored. A solution to this is to secure the directory. And make sure you don't have a hole in your php code where you allow the user_id to be set by a $_POST or $_GET.
Client
But on the client side manipulating sessions is possible by hijacking someones session_id. This will let the hijacker pose as that user. And send request on their behalf.
There is also Cross-Site Request Forgery. This is when a hacker tricks a user into sending requests for him. By making him click on a link for example. You could combat this with tokens. A token is a generated string that is put in the $_SESSION array and in every HTML form as a hidden field. When the user submits a form the values are checked against each other. And every time the user requests a new page the token changes. This way an attacker must try to predict the token, which is pretty hard depending on how you make the token.
The links will also show examples on these attacks.
If you don't provide such access in your script there isn't much users can do about that. So your session data should be pretty secure. The only thing user can do is to manipulate session cookie or session id passed in the URL but it's unlikely that he will find an existing session id of another user.
Not unless you've left a security hole somewhere (such as allowing users to add/change $_SESSION data somehow).
As far as i know, no, unless user guess your session id and replaces it in his cookies. You should add additional IP-check at least server-side to prevent this.