This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
PHP Session Fixation / Hijacking
I've been using $_SESSION superglobal a lot and heavily.
However the situation is like this:
Once the user is logged I want to keep track of his ID(MySQL table). I can easily
insert the id into $_SESSION['id'] = $user_id;
After all I can use that variable across the pages on my site. What's on my mind is - user can trick the ID into another. If I would see that there's a simple number then I can change it a bit and see what happens - I want to prevent this as it can cause a lot of problems as user ID would be used for adding, deleting, editing entries inside the database.
Is session_regenerate_id() just enough to keep my session safe from hijack ?
Conclusion:
Cookie only stores session identificator - all the values are on the server and never get passed to the client side.
Read about session fixation/hijacking on StackOverflow
The user has no acccess to $_SESSION['id']. He can not modify a variable that's kept on your server (see session doc).
session_regenerate_id() has a different purpose. It resets the cookie SID. That's the handle that differentiates users and sessions. It only makes sense to use if you have a secondary identifier (IP or user agent string) to verify. It's main purpose is preventing stale or intersecting sessions. Again, see the manual.
If I were you I'd have a table in your database that stored a user_id and a session_hash. Possibly a date_expires as well. Then when a user logs in you create a hash based on their id and maybe a random salt, store that in the database as well as the session variable. That way if they change that value on their side, the chances of them matching some other stored value in your database is very unlikely. Along with this if the user performs any operations on their account you just check the database table for their hash to get their real id and then follow through with the operation like you normally would.
One option would be to hash it and then use that same hash in your database.
Example:
$_SESSION['id'] = md5($user_id);
$query = "SELECT * from database_table where md5(database_table.user_id) = " . $_SESSION['id'];
Related
I am a little confused on storing sessions with regards to having multiple users logged in at the same time...Does the session key have to be unique or just the value? Like is this ok, if all the $userIds are unique?
//if the user logs in:
$_SESSION['loggedIn'] = $userId;
In testing this it seems like if you have two logged in with separate $userIds at the same time and are trying to enter data to a db, it causes errors. Should the key be a random #? Not worried about security at this point.
The $_SESSION vector is part of the [Session management] of PHP:
Session support in PHP consists of a way to preserve certain data across subsequent accesses
It basically let's you store information in a per session fashion, and retrieve that same information in a subsequent call from the same session.
Each session have it's own data set.
PHP uses a cookie or a POST/GET parameter to identify each session and thus determine if the current call is part of a existing session and provide you with the data you stored there in previous calls.
session_start() creates a session or resumes the current one based on a session identifier passed via a GET or POST request, or passed via a cookie.
For more info, take a look at this topics in the manual:
session_start()
session_name()
session runtime configuration
$_SESSION is stored on the server side and is not a good way to track a user as a session can be terminated after a short period of inactivity. You'd be better off using cookies, if possible.
But to address your specific question, your code should work as the session will almost always be unique.
I was using $_SESSION to store users IDs but I want to change to using a regular cookie (with a KEY) paired with SQL so I can keep users authenticated when they close their browsers.
How do I create an unique key for each row in my SESSIONs table?
You're effectively looking to write your own session handler to bypass PHP's cookie expiration issue on session cookies. This is pretty straightforward, and pretty optimized if done properly.
Step 1: generating the session ID
A session ID is unique. However, if you're planning for permanent sessions, you have to bear a couple of things in mind: you want the session to carry over per browser, regardless of connection issues. So, you can cheat the system a bit by mapping the session ID with the user agent of the navigator (which doesn't change).
This allows you to reduce the chance for your session ID generator to generate the same ID for two distinct visitors. The rest is up to a random number generator and a hash algorithm, though - md5(microtime().$_SERVER['REMOTE_ADDR']) is usually a trusted friend.
Step 2: storing and retrieving the data
Storing the data is also trivial. Your aim is to create a MySQL table with a minimum of two columns: the session key (set to PRIMARY), and the data (serialized array for the simplest form, stored as TEXT).
When you create a session, just insert a new row and watch for errors. If an error comes up, the key was already used, so you'll need to re-generate another. If the row was inserted successfully - all good, you now have a session row for the user! All you need to do from there on is to read/write to this row as you see fit.
Cookie the user with the session ID, and you're done!
Caveats
Never ever use a userID as session ID. Cookies can be very easily manipulated. You want the cookie value to be random and completely separated from the user. It should be meaningless.
You'll need to write clean-up code to clean up the session table from time to time. A good way to do this is to keep track of when a session was last used - and delete accordingly.
The best way is to use some hash function, which is actually also used by PHP itself by generating session id's.
You can use something like this:
md5(microtime());
You can combine more values together, e.g. random number, user agent, server name or use stronger algorithms like SHA2.
But for uniqueness you will always need to look into table if there isn't such hash already stored (but the probability is very low of course).
But I would just go for standard session_id() which does all the job.
You can use MySQL's UUID().
If you want to keep the session alive you can also use PHP's session_set_cookie_params().
The SQL solution has one advantage though: you can scale to more webservers easily. On the other hand you can not use PHP's $_SESSION array and you have to write the session handling yourself.
I have a database in which I store session ID's once they have been validated to a user.
From a security standpoint, should I be checking the session ID against the session ID stored in the database for every protected page being accessed?
If I do not do this, wouldn't it be possible for someone to hijack the validated session ID, and do a post with the necessary variables to access restricted pages?
From a performance standpoint - if I should be checking the session ID against the database for every request, would it be significantly more efficient to store validated session ID's in their own text files instead of making so many database queries?
Thanks in advance.
Yes, you should check the session ID on every request. It's still possible for session hijacking to occur, although a rolling session ID would help mitigate this (i.e. change the session ID on each request).
It would not be more efficient to validate session IDs in a text file versus a database if your RDBMS supports results caching (MySQL calls this query caching).
If your query just verifies the existence of a session id like SELECT COUNT(session_id) FROM sessions WHERE session_id = ? (you are using parametrised queries to prevent SQL injection, right?) then this may be cached (although MySQL may not do so in versions earlier than 5.1.17).
If/when there is no cache, the lookup should not cause any issues. Switching to an in-memory table at that point may be a good idea.
About security:
You describe the hijack risk yourself quite well. More important is the question of how likely this would happen and how sensitive your site / data is.
Now if someone takes over the pc of a registered user who didn't destroy the session (log off), how would you determine this? And why / how should the session ID change and still be valid?
It would probably be better to check the identity of the caller by accessing a cookie, checking the ip (on ip change re-logon), ...
About performance:
In general a text file query should take much longer than a database query, since the text file is almost always a file system / storage query, while the database query will often be in memory (cached).
Think of your database as another software program running in the background - it's basically instantly accessible if it runs on the same server.
-> Correct me if I'm wrong...
From a security standpoint, should I
be checking the session ID against the
session ID stored in the database for
every protected page being accessed?
If I do not do this, wouldn't it be
possible for someone to hijack the
validated session ID, and do a post
with the necessary variables to access
restricted pages?
Yes, and you'll probably want to include some additional information in your database - e.g. last time accessed, ip address.
Generaly speaking checking and regenerating ID session occurs when you change status of user.
IE : user X get the admin access : You must check is session id before grant access and you regenerate a new id after the operation.
Since every user has a unique PHPSESSID, is it possible for two users, say a to inject info into b's SESSION data using standard PHP running on the server.
Note, I am not using this for any wrong purposes. Trying to use it for chatting without DB access.
Thank you for your time.
I'm assuming you want to somehow have A chat to B by sending a message which gets placed into B's session.
First of all, A needs to learn B's session ID, perhaps by selecting their name from a list. You'll almost certainly want to encrypt these session ids, otherwise you have created a nice security hole!
So, A posts data to the server containing the target session id, and a message. Here's how we could temporary switch session ids to write that data into the target session:
//get data from form - I'll leave the encryption of the target
//session id up to you!
$target_session_id=decryptSessionId($_POST['target']);
$message=strip_tags($_POST['message']);
//remember our "real" session id and close the session
$original_session_id=session_id();
session_write_close();
//open the target session
session_id($target_session_id);
session_start();
//add message to target session
$_SESSION['chat'][]=$message;
//close target session
session_write_close();
//reopen the "real" session
session_id($original_session_id);
session_start();
Read up on session fixation
Session is a simple thing that can be easily reimplemented to do as you wish. Take a look at this simple exemple I wrote some time ago: http://pastebin.com/f3ca0ae8d
Usage:
new mySession(); doing the same as session_start();
$_MYSESSION doing the same as $_SESSION
delete mySession(); doing the same as session_write_close(); not necessary to use unless you want to release the session before the script end.
You can make some adaptations to use it in your specific purpose, like defining the session ID yourself so you can share it among different users. As $_MYSESSION will be common among users, you can also use regular PHP Sessions together with it to store user specific information in $_SESSION.
[Edit]
http://pastebin.com/f3c31737e
Exemple: Enter the channel $_SESSION['channelid'] and print all unread lines.
session_start();
new mySession($_SESSION['channelid']);
while (count($_MYSESSION['chat']) > 100) unset($_MYSESSION['chat'][key($_MYSESSION['chat'])]);
while ($line = $_MYSESSION['chat'][$_SESSION['lastread']++])
echo "$line";
Exemple: Talk to the channel.
session_start();
new mySession($_SESSION['channelid']);
$_MYSESSION['chat'][] = $_SESSION['myname'] . ' says, "' . htmlspecialchars($_POST['message']) . '"';
etc...
Instead of farting around with what is, essentially, indirect file handling through the session system, why not go straight to the point and use text files?
It's less vulnerable to attacks, and also less volatile, in the sense that future versions of PHP could decide to prevent this sort of session switching for security reasons (complete hypothetical, but it makes sense).
I can't say for sure but since session data is by default stored in a file, if your app knows the session id of the other user you could replace in the session file that was written by the standard session functions with altered data. The next time the other user accesses a script the altered session data will be loaded.
But you are risking all sorts of race conditions and conflicts if you just do this on top of the built in session handling. You will probably want to replace the session handling functions with your own so you can deal with all of these issues. The issues are probably much more complex than they appear on the surface.
See: http://www.php.net/manual/en/session.customhandler.php for information about custom session handlers
PHP’s default session handler uses only the session ID to identify the session. That makes it possible to use the session ID from another user and thus use the same session (Session Hijacking). Another attack is to prepare a session and get the victim to use that session so that the victim and attacker again use the same session (Session fixation).
The base for such attacks is that you just need to know the session ID to use the session that is associated to it. Prevention techniques are to use more identification information than just the session ID. Some suggest to use the IP address (but that may change during a session) or the user agent identifier. Another technique is to hide the session ID externally by allowing only a cookie and HTTPS.
But be also aware of shared hosting. Some might use a common pool for all session data files of all cumstomers.
ive heard a few timse that sessions need to be cleaned with mysql_real_escape_string or htmlspecial chars because they can be modified. what im wondering is how are they modified because when i look at a websites session named PHPSESSID the value it contains is always encrypted.
first of all what encryption method is it using and how is it modified. the reason i want to know this is to better understand how to secure myself based on what methods people are using out there to high-jack sessions
thanks.
They cannot be modified, they're stored on the server. The PHPSESSID is just an identifier, it's not encrypted but randomly generated (so it's unique to each user). People hijack sessions by stealing the PHPSESSID cookie, usually through a cross site scripting attack. Read the answer to this for a nice summary of sessions in php - What do i need to store in the php session when user logged in
Sessions are stored on the server. That means all data is stored in temporary files and are deleted after an x amount of time. The browser does not store session data. It stores an ID of the session, which the server uses to get the right temporary file.
So the user never actually has access to variables stored in a session. But has a reference to their session. It is possible to get someone else's session ID. This way you can pretend to be another user. If sessions are used for validation.
Read up on session hijacking here.
The thing that can get modified is the session id send to you by the client. So, as with all user supplied data, this needs to be 'cleaned' before you use it anywhere, like for example with mysql_real_escape_string before inserting it into a MySQL database.