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.
Related
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).
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.
I'm using the following code for my user login. Everything works fine but im just wondering the security of using this. I'm using the userid as the sessionid when a user logs in.
What are my security issues with using this?
Can the user change the sessionid to a different number and then be logged in as a different user? (how do i stop this?)
if (!empty($row['member_id']))
{
$_SESSION['id'] = $row['member_id'];
header ("Location: team.php");
exit();
I'm not a security expert by any means.
There was an uproar back in, I want to say, 2010 about session theft. So much so that a group put out a tool called Firesheep that would let you quickly steal other sessions in an open wifi situation. The solution is to protect the entire logged in session with SSL or not be on an open network. Back when SSL was first being used, it proved too slow to be used as a session long security measure, but now computing is fast enough.
TLDR: If you don't SSL, someone can steal your session. Facebook and Google both had the same problem.
For clarification, they can't "steal" sessions so much as they can find out the SESSIONID being passed around in the POST request in order to keep you logged in and then modify their cookies to send that around as you instead. The Firesheep tool could snag Facebook logins in seconds. By modifying the cookie with someone else's SESSIONID, the tool was able to pretend to be the original user, allowing full access to the areas of the account that were unlocked upon login. See also: this.
Another good solution to help things is to reprompt the user during any account sensitive activity regardless of their session. For instance, if they try to change their password or change other account info, make sure to ask for their current password again.
The contents of the $_SESSION server-side are only safe as long as there is no way to submit user data in any way that would eventually end up in the session variable. If someone stole a SESSIONID and then entered data on some form (or if you blindly use the name of the form element as the index into the $_SESSION array) they could get stuff in there. The key is to never ever ever ever ever ever ever ever...EVER....trust what the client side has sent as valid or trustworthy. Paranoia is your friend.
I think you are mixing up the Session ID (SID) with your own login id, you save in $_SESSION['id'].
Your code is fine. Session data is saved on the server and cannot be manipulated by the client directly. So he cannot change the value of $_SESSION['id'] (btw: I suggest to use a more unique key name like 'login_id').
Talking about the real Session ID (SID). The SID is a random string generated by PHP automatically and saved as a cookie on the client’s machine. The client can actually manipulate his SID and so potentially takeover a different session. This is called Session Hijacking and it’s a general problem of using sessions, no special problem of your code. Have a look here for further information: PHP Session Fixation / Hijacking
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).