PHP: best solution against hijacking sessions [duplicate] - php

Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
What are some guidelines for maintaining responsible session security with PHP? There's information all over the web and it's about time it all landed in one place!

There are a couple of things to do in order to keep your session secure:
Use SSL when authenticating users or performing sensitive operations.
Regenerate the session id whenever the security level changes (such as logging in). You can even regenerate the session id every request if you wish.
Have sessions time out
Don't use register globals
Store authentication details on the server. That is, don't send details such as username in the cookie.
Check the $_SERVER['HTTP_USER_AGENT']. This adds a small barrier to session hijacking. You can also check the IP address. But this causes problems for users that have changing IP address due to load balancing on multiple internet connections etc (which is the case in our environment here).
Lock down access to the sessions on the file system or use custom session handling
For sensitive operations consider requiring logged in users to provide their authenication details again

One guideline is to call session_regenerate_id every time a session's security level changes. This helps prevent session hijacking.

My two (or more) cents:
Trust no one
Filter input, escape output (cookie, session data are your input too)
Avoid XSS (keep your HTML well formed, take a look at PHPTAL or HTMLPurifier)
Defense in depth
Do not expose data
There is a tiny but good book on this topic: Essential PHP Security by Chris Shiflett.
Essential PHP Security http://shiflett.org/images/essential-php-security-small.png
On the home page of the book you will find some interesting code examples and sample chapters.
You may use technique mentioned above (IP & UserAgent), described here: How to avoid identity theft

I think one of the major problems (which is being addressed in PHP 6) is register_globals. Right now one of the standard methods used to avoid register_globals is to use the $_REQUEST, $_GET or $_POST arrays.
The "correct" way to do it (as of 5.2, although it's a little buggy there, but stable as of 6, which is coming soon) is through filters.
So instead of:
$username = $_POST["username"];
you would do:
$username = filter_input(INPUT_POST, 'username', FILTER_SANITIZE_STRING);
or even just:
$username = filter_input(INPUT_POST, 'username');

This session fixation paper has very good pointers where attack may come. See also session fixation page at Wikipedia.

Using IP address isn't really the best idea in my experience. For example; my office has two IP addresses that get used depending on load and we constantly run into issues using IP addresses.
Instead, I've opted for storing the sessions in a separate database for the domains on my servers. This way no one on the file system has access to that session info. This was really helpful with phpBB before 3.0 (they've since fixed this) but it's still a good idea I think.

This is pretty trivial and obvious, but be sure to session_destroy after every use. This can be difficult to implement if the user does not log out explicitly, so a timer can be set to do this.
Here is a good tutorial on setTimer() and clearTimer().

The main problem with PHP sessions and security (besides session hijacking) comes with what environment you are in. By default PHP stores the session data in a file in the OS's temp directory. Without any special thought or planning this is a world readable directory so all of your session information is public to anyone with access to the server.
As for maintaining sessions over multiple servers. At that point it would be better to switch PHP to user handled sessions where it calls your provided functions to CRUD (create, read, update, delete) the session data. At that point you could store the session information in a database or memcache like solution so that all application servers have access to the data.
Storing your own sessions may also be advantageous if you are on a shared server because it will let you store it in the database which you often times have more control over then the filesystem.

I set my sessions up like this-
on the log in page:
$_SESSION['fingerprint'] = md5($_SERVER['HTTP_USER_AGENT'] . PHRASE . $_SERVER['REMOTE_ADDR']);
(phrase defined on a config page)
then on the header that is throughout the rest of the site:
session_start();
if ($_SESSION['fingerprint'] != md5($_SERVER['HTTP_USER_AGENT'] . PHRASE . $_SERVER['REMOTE_ADDR'])) {
session_destroy();
header('Location: http://website login page/');
exit();
}

php.ini
session.cookie_httponly = 1
change session name from default PHPSESSID
eq Apache add header:
X-XSS-Protection 1

I would check both IP and User Agent to see if they change
if ($_SESSION['user_agent'] != $_SERVER['HTTP_USER_AGENT']
|| $_SESSION['user_ip'] != $_SERVER['REMOTE_ADDR'])
{
//Something fishy is going on here?
}

If you you use session_set_save_handler() you can set your own session handler. For example you could store your sessions in the database. Refer to the php.net comments for examples of a database session handler.
DB sessions are also good if you have multiple servers otherwise if you are using file based sessions you would need to make sure that each webserver had access to the same filesystem to read/write the sessions.

You need to be sure the session data are safe. By looking at your php.ini or using phpinfo() you can find you session settings. _session.save_path_ tells you where they are saved.
Check the permission of the folder and of its parents. It shouldn't be public (/tmp) or be accessible by other websites on your shared server.
Assuming you still want to use php session, You can set php to use an other folder by changing _session.save_path_ or save the data in the database by changing _session.save_handler_ .
You might be able to set _session.save_path_ in your php.ini (some providers allow it) or for apache + mod_php, in a .htaccess file in your site root folder:
php_value session.save_path "/home/example.com/html/session". You can also set it at run time with _session_save_path()_ .
Check Chris Shiflett's tutorial or Zend_Session_SaveHandler_DbTable to set and alternative session handler.

Related

Improve Web application security based on php session

I have a web application that I want to improve in its security flaws, I read a lot of articles about it but some questions are still unanswered. I appreciate your help.
First of all I have a login screen. After the user enters his credentials, they are checked against the database ( they are properly hashed ;)), and if it succeeds the server creates a session variable
//Jhon id = 1
$_SESSION["userID"]= '1';
At the beginning of every php file (e.g. dashboard.php) I have the following code:
session_start();
if(isset($_SESSION['userID'])) {
if($_SESSION["userID"]==""){header("location:login.php");}
}else{
header("location:login.php");
}
?>
<html ...
For improve maintenance i want to include this code in an external php file like
include('inc/restricted.php');
?>
<html ...
My two main questions are:
1) If an intruder handles to corrupt or to deny access to restricted.php, would the remain of dashboard.php show up? Is it possible to do something like that? If it is, how could I fix it the way I can include the security code as an external file?
2) As you see the value of my session variables are simple (integers numbers), should I change them to hashed values? I thought the php session was stored on server side but i read about some php session variables stored on cookies and now im worried about the chance of create a cookie with a random number and granted access.
It's possible if the code in this file is insecure. Since we can't see it it's impossible to say how it could be compromised. But generally speaking, the web-facing request should have no ability to control your php code unless you have a severely insecure setup.
The values don't matter. Data stored in $_SESSION is never stored on the client, only on the server. This is controlled in php by the session.handler interface (by default it's stored as a plain-text file on your server in session.save_path).
The things that tend to make sessions insecure are almost always the result of poorly written code or a poorly configured server.
Some things you can do to improve the security of your sessions are outlined below:
Always use session_regenerate_id(true) when logging the user in (this prevents session fixation attacks).
Always delete the session cookie on the client when you log the user out (see the first example in http://php.net/session-destroy). This prevents session take-over attacks when the user is logged in from a public computer, for example, as the session may not always be deleted instantly on the server side and the cookie allows the client to re-trigger the session TTL on the server.
Only transmit session cookies over a secure connection (See session.cookie_secure
To prevent some XSS and CSRF vectors consider using session.cookie_httponly and session.cookie_samesite to prevent malicious JS from opening up these kinds of attacks.
Always use CSRF tokens along with all modifying requests to protect the user from compromising their access strictly via sessions. This is an added layer of security.
Just remember that this is not an unabridged list. Security is built in layers and requires a lot of forethought in use cases and objectives.

What to store in a session?

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 think my PHP app is being session hijacked?

I have a php site that lets registered users login (with a valid passord) and sets up a session based on their UserID. However I'm pretty sure thisis being hijacked and I've found "new" files on my server I didn't put there. My site cleans all user input for SQL injections and XSS but this keeps happening. Has anyone got any ideas on how to solve this?
A session cookie hijacking should NOT allow an attacker to create new files on your server. All it could do is given access to an authenticated user's session. It'd be up to your code, and/or the server's configuration that would allow uploading arbitrary files to the site's webroot.
To check for remote compromise hits, get the file creation times of the suspicious files (searches.php, 7.php.jpg) etc..., then comb through your server's logs to see what was happening around that time. If you're logging the session ID along with the rest of the hit, you could trivially see if the session was hijacked, as it would be used from two or more different IPs during the session's lifetime. It'd be especially obviously if the original user logged in from one ISP, then suddenly appeared to jump to a completely different ISP.
And of course, how are your sessions implemented? Cookies? PHP trans_sid (passing the session in hidden form fields and query strings)? trans_sid is especially vulnerable to hijacking, as the mere act of sharing a link to something your site also transmits the session ID, and any external links on your site will have the session ID show up in the HTTP referer.
The solution that PHP experts have come up with is to use unique keys/tokens with each submission of the forms, have a look at the idea here at net-tutes.
Don't forget have a look at the PHP Security Guide.. It covers topics including XSS, Form Spoofing, SQL Injection, session hijacking, session fixation and more.
Remember, always use proper data types in your queries, for example use the int or intval function before numbers and mysql_real_escape_string function for the string values. Example:
$my_num = (int) $_POST['some_number'];
$my_string = mysql_real_escape_string($_POST['some_string']);
You may also use the prepend statements for your queries.
Popular Project To Secure PHP Applications:
XSS Filtering Functions by Christian Stocker (Also used by Kohana framework)
HTML Purifier (Also used by Kohana framework)
OSAP PHP Security Project
I'll have ago and say that your 'cookie' is easy to guess.
Some sites, when the user logs, just create a cookie and the authentication code just checks for the EXISTENCE of a cookie.
Now, if I register and login to your site and then cut your cookie open and notice that you just store my user id then I can manipulate the value to some other user id and voila!
You get the idea.

Login system and sessions (php)

I've created a login page and registration page and now I want to use that to password protect pages and have pages which show information specific to that user.
Would storing the user ID of the user logged in in a Session variable be a safe and correct way of doing this?
How easy would it be for a user to change the session variable to a different ID and access another user's information, and not having to type the users login details in?
EDIT: Would posting the user ID from each page to the next be more secure?
Here's an article on session security
If you encrypt user name in such a way that only your PHP scripts can decrypt it then you should be safe I guess.
That's what session meant to be
For session security, you can check http://phpsec.org/projects/guide/4.html
While I'm not aware of any way in which a user could manipulate the information in $_SESSION unless your code (or code on your server) allows them to, so don't do anything crazy like...
foreach($_POST as $key=>$value) { // DON'T DO THIS
$_SESSION[$key] = $value; // DON'T DO THIS!
} // WHY ARE YOU DOING THIS!?
You shouldn't do anything like this, where you're just putting whatever data the user gives you in your $_SESSION variables. Like the database, writing to the session should be thought of as a form of output, and you should sanitize what you put in it (and where it's put) accordingly.
So, unless you're doing something crazy like this (you might be; it can be much more subtle), I don't think you have to worry about a user changing the session variable. You might have to worry about the threats of a shared hosting environment where someone who's probably not quite an end user is manipulating the session info.
What's not so safe is the session identifier, as there are a few straightforward ways to hijack a session in PHP.
I recommend checking out that book I've been linking to, Essential PHP Secutiry. It's a very small and straightforward (but thorough) explanation of several basic PHP security concepts, many of which can be generalized and should be kept in mind when doing any web dev work.
I'll talk about the default session behavior, here: sessions are based on a cookie "PHPSESSID" which is set to an MD5 checksum (32 alphanumeric characters). PHP accepts this cookie from the browser, and uses it to load server-side session data. The client has no direct way to modify data in the session, but does get to specify their own session ID.
You can add additional layers of security (SSL, checking the client IP, etc.), but by default if I know your cookie I can effectively login as you. As far as how "easy" that is, well, that depends on lots of other layers of security: is someone sniffing your traffic, do you have malware installed, etc.
Tools like Suhosin attempt to improve session security.

What is the best practice for using Cookies for authentication with PHP?

I'm looking for tips and ideas on how to best incorporate authentication with PHP using Cookies.
Should each php script check for the cookie value to determine if the user is still logged in? Should there be one script that does this check and Include that script from each of the other scripts? Can the cookie value be seen by php from different depths of the filesystem?
Like: blahblahblah.com/ and blahblahblah.com/login/
Can they both read the cookie?
Lots of questions on one post, but thanks!
nothing is safe on the client side.
You change the login flag on Cookies easily on any browser. Thus it is more recommended to be saving login-related data on php's $_SESSION
If you wish to extend the session, simply look at session_set_cookie_params().
By default, the same session will be used for the current domain and all the paths on that domain. Thus it is readable for both blahblahblah.com/ and blahblahblah.com/login/
When the user logs in, save the username and the hash of the password in the Session.
At the start of each script, verify the Session's username and password with the one in database. If is correct, then set a flag (e.g. $userLoggedIn = true) to indicate on server-side that the user is logged in. else false.
Some thoughts, in no particular order:
Separate out the various layers: persistent storage vs authentication.
PHP sessions are quite robust and are the recommended way to maintain persistent storage.
You can have a valid session, but not a valid login.
Avoid multiple cookies. One is enough. PHP sessions work with one cookie.
You can set sub-domains and paths on cookies, but there's really little point unless you set lots, which is not recommended (see above).
Put everything you think you might want in a cookie in the session instead.
You should have some common code that all your pages include. That is where you initialize your session. Then everything will Just Work. It can also verify the login is valid, too.
Have one place that does the login authentication and everything associated with that.
Don't forget a logout screen!
Its a good idea to have one script do the session/login check and include it in the secure pages. AS for the depth , you can define that in the setcookie() if the directory parameter is set to "/" then its accessible all across.
Generally its a good idea to use sessions instead of cookies , as thats more secure , but you can decide to build your own session system based on encrypted data in the cookie and that can work too , but again sessions, which store data on the server side are recommended.
The cookie is per domain, so no matter how deep you are in your directory structure, the cookie will be read OK (as long as your domain stays the same - NB this means that www.example.com and example.com can be different cookies).
I'd suggest having an authentication check that compares the session ID in the cookie with eg a database table listing logged in users and their session ID - this check can be in its own method/include file that is include()'d on each page. That way the check will be performed on every page load. NB this is basic and there are much more secure methods - some of which have been mentioned in other comments here.
As Mauris said though, nothing is safe on the client side - don't use a cookie to store a "logged_in" value which you check for true/false!

Categories