I used $_SESSION['name'] to handle data from page to page. I mainly used it to keep the user logged in between pages. Within every page, i check if $_SESSION[logged_in'] is true or not. If true, keep user logged in. Otherwise, do something else.
This is how i handle my sessions - basic sample:
<?php
session_start();
if($_SESSION['logged_in'])
{
//show control panel list
}
else
{
//show login box. Once user logs in. Once user logs in,
//fetch userID, username, etc from database. Also set
//$_SESSION['logged_in'] = true.
}
?>
Somewhere in between codes i do the following:
SELECT * FROM User WHERE userID = $_SESSION['userID'];
I'm not sure if $_SESSION['userID'] would be accessible by users or not. If its accessible, then the page would be in threat because a user could change the userID manually and get access to others account he/she desires.
I'm not much into security. Please advice! What can i do?
Note: i'm trying to make code as simple as possible. For now, no oop is involved.
Your code is vulnerable to session fixation and session hijacking attacks. See http://phpsec.org/projects/guide/4.html for more information.
As you build bigger, more involved applications, you will also want to be careful how you handle logging the user out and handling other session-related aspects, such as privilege escalation. Handling sessions and logins safely is a tricky beast.
Implementing secure authentication is hard. Unless you are doing it as an academic exercise, i would strongly recommend using the library provided by your framework, if you are lucky enough to have a good one.
You will also want to consider things such as the following:
Do not allow the session id to be forced. [session fixation]
When permissions or credentials are changed (e.g. because the user has now logged in or out) then
immediately invalidate the session and start a fresh one.
Provide a logout feature, and be sure to invalidate the session upon logout.
Set the session cookie to HttpOnly -Preferably, require HTTPS and alo set the cookie to secure only.
Consider restricting the session validity to include checking some other information that helps to match the user e.g. user-agent. [session hijacking]
Always expire sessions after non-use and do not implement "keep me logged in" by reconnecting the user to their old http session.
Ensure that all session-related data is destroyed when a session is invalidated, regardless of where it is stored. A new user coming along, may just happen to get assigned a session id that has been used previously. This new session must not have any access to session data that has been set previously against that session id.
$_SESSION is one of the server-side Super Globals. It's not accessible by users or transmitted from your server in any way.
That's pretty good, here are a few other tips for session management:
Do not accept session identifiers from GET/POST variables:
Session identifiers in URL (query string, GET variables) or POST variables are not recommended as it simplifies this attack. It is easy to make links on forms which set GET/POST variables.
Regenerate the SID on each request:
In PHP use session_regenerate_id(). Every time a user's access level changes, it is necessary to regenerate the session identifier. This means that although an attacker may trick a user into accepting a known SID, the SID will be invalid when the attacker attempts to re-use the SID.
Yes, that is pretty much the right idea.
Here are a couple resources that may help, both with understanding session security and secure programming in general:
http://phpsec.org/projects/guide/4.html
http://phpsec.org/projects/guide/
Related
My question is about this summary on session fixation:
Alice has an account at the bank http://unsafe.com/. Unfortunately, Alice
is not very security savvy.
Mallory is out to get Alice's money from the bank.
Alice has a reasonable level of trust in Mallory, and will visit
links Mallory sends her.
Mallory has determined that http://unsafe.com/ accepts any session
identifier, accepts session identifiers from query strings and has
no security validation. http://unsafe.com/ is thus not secure.
Mallory sends Alice an e-mail: "Hey, check this out, there is a cool new
account summary feature on our
bank,http://unsafe.com/?SID=I_WILL_KNOW_THE_SID". Mallory is trying to
fixate the SID to I_WILL_KNOW_THE_SID.
Alice is interested and
visits http://unsafe.com/?SID=I_WILL_KNOW_THE_SID. The usual log-on
screen pops up, and Alice logs on.
Mallory visits http://unsafe.com/?SID=I_WILL_KNOW_THE_SID and now has unlimited access
to Alice's account. (credit: RichieHindle)
Questions:
Q1 - Is there a way to explicitly prevent the site from accepting any
session identifier?
Q2 - I don't use the $_GET variable on my site so is there a way to prevent accepting session identifiers from query strings?
Notes: I'm using php 5.4.3 with SSL and will also use session_regenerate_id..
You could set the options martinstoeckli mentioned in his answer, but this won't prevent session fixation. It makes session fixation a little harder to attack, but it doesn't prevent it.
As ServerBloke mentioned, you prevent session fixation by using session_regenerate_id() immediately after verifying the user's login information and before you show the first page that requires authentication.
Making it harder for the attacker to exploit session fixation does not prevent session fixation. You must generate a new session ID.
More and more, people are using public unsecured untrusted wi-fi hot spots. Sessions can be sniffed from the air. On a physical network, they can be sniffed off the wire. They can also force you to visit any URL by employing a man-in-the-middle attack. So, session fixation is still a problem, even if the attacker can't send you URLs.
Knowing that sessions (and passwords) can be sniffed, there is another step that is required to prevent session hijacking. That is HTTPS (TLS/SSL).
All protected pages that require authentication should be accessed only over HTTPS. So, the login page (the one where the user sends their username and password) should be accessed via HTTPs. In that same script, you must regenerate a new sessionID. All pages for the remainder of the session must then be accessed via HTTPs to protect the new session ID.
Here's an example pseudocode login.php script:
// Force SSL
if($_SERVER["HTTPS"] != "on") {
die('Must login via HTTPS');
}
// Load the current sessionID
session_start();
// Validate the login information, being sure to escape the input
...
if (! $valid) {
die('Invalid login');
}
// Start the new session ID to prevent session fixation
session_regenerate_id();
// Clear the old session
$_SESSION=array();
// Log them in
$_SESSION['user_id'] = $userID;
If you use session_regenerate_id() everytime a user logs in you will prevent session fixation. As the user logs in, their fixated session ID will be regenerated and thus stopping the attack.
Question 1) If your application needs a session, you will have to send some kind of session id. If your application doesn't use sessions, then there is no need to call session_start(), and ids (whether sent by URL or cookie) are simply not used.
Question 2) You can configure PHP, to accept session ids exclusively from cookies, and to ignore ids from the URL (see session.use_only_cookies). If you do that, you should also check, that the option session.use_trans_sid is set to 0 (this is the default).
I don't fully understand, is this a really problem?
Q1. I think you need to check is there are a SID recieved from GET of COOKIE in you Session storage already (for example, in database). If YES - its'okay, if no, create a new one on server side and do http redirect with new SID.
Q2. I don't use a php 5.4 but i think the following code will help:
unset($_GET['sid'])
Update: I think the common fix is than only the backend-server can generate a SID identifiers. No user posibilites for this!
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 trying to wrap my head around session hijacking and the use of tokens for CSRF protecting.
I use this object method in each of my scripts to check whether a session variable is set or the token matches the session token.
public function admin_index(){
session_start();
if(!isset($_SESSION["user"]) || $_GET['token']!=$_SESSION['token']) {
header("location: login/login_form.php");
session_destroy();
exit();
}
I'm new at this and my question is:
If my session id is somehow hijacked will he be able to some how also read my variable $_SESSION['token'] in the short time span after session_start and the the session data is fetched and populate in $_SESSION or is it still safe on the server?
Are session variables generally safe even though a valid session has been obtained?
Never mind the $_GET['token'] instead of POST. I'm still working on it.
Thanks
EDIT:
What I'm asking is. If a token also helps me secure my sessions the way I'm using it. If every query, link or view in my script requires a valid token and an attacker only got a hold of my session_id the tokens would be another layer of protection cause he/she would need both the id AND the token to do anything in the script, right?
And the token is secure on the server even though an attacker has acquired my session_id?
Session Hijacking and CSRF attacks are two completely different things and once someone has your access to your session they are 'you' and can access everything on your account.
A CSRF attack is an attack which forces an end user to execute
unwanted actions on a web application in which he/she is currently
authenticated
This is a social engineering and validation issue which using a token can obviously solve as it can be proved that the data was sent legitimately from your form. Using POST instead of GET will make this attack very difficult.
A Session Hijack on the other hand is where someone can use your
session, become 'you' and use your account which will allow them to do
whatever they please.
Once a malicious user has access to this session a CSRF attack is pretty much useless as it is not needed.
If you are worried about your session ids being hijacked then you can take some precautionary measures such as regenerating a users session id once they are elevated to a higher level of access. This can be done using the session_regenerate_id() PHP function. You can also check the User Agent of the browser to check if there are changes and if there are then you can simply ask the user to login and regenerate the id so it is then unknown to the attacker. Obviously there is always a chance that they will be the same user agent but it does limit the risk significantly. Encryption such as SSL/HTTPS are also an option that you may want to look at
For more information you should check out this link for some examples: http://phpsec.org/projects/guide/4.html. Hopefully this has solved your problem :)
Correct me if I'm wrong, but I'm quite sure you simply can't hijack $_SESSION values because these, unlike $_COOKIE is saved on the server and not in the webbrowser.
Therefor they can't change it either. They can close their webbrowser to remove it, but not edit it.
Session variables are stored on the server. They can not be read. However, a session can be hijacked typically by an attacker getting access to the session id of another user, and can then use that session id to impersonate them (hijack) their session.
CSRF is an entirely different concern. CSRF exploits get users to inadvertantly perform operations in a manner similar to xss exploits: I might post a bogus img link where the src is actually a url that passes parameters to a script that your browser runs on your behalf. In that case the attacker is simply getting your browser to make a request you didn't intend it to. The CSRF protection should stop this, because the user does not know what the token is, so they can't embed it into the url.
When a user logged in website, I only save user_id in SESSION to check it later whether user logged in or not.
if(!empty($_SESSION['user_id'])){
....
Is this enough for security?
This would depend entirely on how that variable makes it to the session and how well you're managing session.
One case to always consider when dealing with web-site security and user credentials is the possibility of a user logging on to your site in a public environment and then walking away. How long will he stay logged in? How accessible is the sensitive information when already logged in?
If you have a relatively short session timeout and are making sure that you are managing what makes it into $_SESSION['user_id'] then this is a reasonable approach. It may be better to actually check the VALUE of what is in $_SESSION['user_id'] but that won't be a huge improvement over what you currently have.
The main thing that I would recommend taking into account would be to require login credentials once more if a user ever wants to alter their account's details / access overly sensitive data (you wouldn't want a stranger changing your users' login names would you?). While this may be a bit of a hassle for regular users, it definitely adds a good measure of security to your application.
The value could only be changed if someone has access to the session files.
So usually yes.
But I would rather use isset():
function loggedIn()
{
if (isset($_SESSION['user_id']) && is_numeric($_SESSION['user_id']))
return true;
return false;
}
Because if the user id is 0, empty() will also return true!
If you are in a shared hosting environment, somebody else on the same server could potentially create a valid session and gain access.
Or, someone could be sniffing network traffic as one of your users visits the site and could catch the cookie and gain access to their account since you just using simple session based authentication.
A common way to fix this problem is to create a database table, perhaps called "sessions", and record the session id, IP address, and any other user-specific data you want to gather when the user first logs in. You can then repeatedly check against this session table to help ensure that it is indeed the original user logged in and not somebody else.
It depends...
if you never do something like $_SESSION['user_id'] = $_GET['user_id'] you can usually say: it is save.
BUT there are things like session hijacking, cross site scripting, cross site request forgeries, and so on.
Use
if(!isset($_SESSION($user_id){
Because if the $user_id==0 then isempty() will not work and be sure that the session which is not required on another page must be unset after the page end for the better security. The method to unset a particular session variable is
unset($_session_variable_name);
and the session should be destroyed whenever it is required ie when a user logout.
Thanks
Not really, apart from the comments above you should further check properties like IP-address or USER_AGENT to avoid session-hijacking.
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.