I'm developing some additional functionality for a client's website that uses the email address as a key lookup variable between various databases (email marketing system, internal prospect database, and a third shared DB that helps bridge the gap between the two).
I'm concerned that storing a visitor's email address as a $_SESSION variable could lead to security issues (not so much for our site, but for the visitor).
Anybody have suggestions or experience on whether this is okay to do, or if there's another alternative out there?
It is important to understand the difference between how $_SESSION variables are stored and how cookies are used to retrieve it. All data in the session is stored on the server (in /tmp by default, I believe), and persisted between requests. No session data is stored directly in a cookie by default.
However, PHP will store a cookie with a unique id that identifies your user with a particular session (hence how the same information can be retrieved over different requests).
If the cookie with the session id is compromised, another user can impersonate someone with that session. This includes authenticated sessions, where a user has already logged in. If this happens, chances are you'll likely have bigger problems than exposing an email address.
It wouldn't be a bad idea to use some kind of user id in your session, as opposed to the email address. However there are a number of other, probably more useful, ways to add security to your session.
See this question: PHP Session Security
There isn't anything inherently dangerous to storing values in $_SESSION. It all depends on whether you provide code that would inadvertently output it to the browser.
You could use part of the email address in the variable. So for example, you could use the name joe from the e-mail joe#bloggs.com. Then use another parameter to perform the search.
Also, always use mysql_real_escape_string() when passing variables to the database, and add in some backslashes for good measure.
Related
So sometimes when I pass variables around from page to page, if I want to pass a variable into a form action, I would simply store it in an <input type="hidden"> element. This generally works well but I realized that someone could easily go into the HTML markup and simply change hidden to type text and therefore they could easily edit what is being passed (this can be bad if say they were editing their own profile and I had stored in the hidden input field their ProfileID and they changed it to someone else's)
I was wondering if there is a best practice to resolving this issue? I talked to some coworkers and they said to put checks on the server when they submit the form to make sure they aren't passing in the incorrect info. Is the best way of going about it or are there other ways?
Security-wise, you cannot trust any information that comes from the client, as you correctly noted. This means that you have to store it server-side when such pages are called.
A common practice is to give each client a session identifier in a cookie and on the server-side, you can relate all sensitive information to that session identifier. The session identifier should be random, because if it was sequential, you could just change its value and hijack someone else's session at random.
There are multiple ways to store information with regards to a session identifier. The most flexible one in PHP, and probably the easiest to implement, is to use built-in session support. PHP handles the session identifier for you and lets you store any serializable object in the $_SESSION superglobal. This is an okay-ish solution, as session data is often stored in the temporary folder of your server, and if it's a shared server, chances are other websites on that server could theoretically snoop in and see or even manipulate session data. Of course, if what you're doing is really low-impact, then it's kind of unlikely that someone would go as far as rent the same server just to mess with you. Still, for instance, OAuth providers recommend that you do not store OAuth tokens in $_SESSION storage in public environments.
<?php
session_start();
// place anything you need to save between pages in $_SESSION
$_SESSION["foo"] = array("bar", "baz");
// until you unset $_SESSION["foo"], it will be available in every page that called
// session_start().
?>
It's a good practice to call session_destroy when users log out to make sure that their session data doesn't exist for longer than it needs to.
On the other hand, you can also store information in a database, such as MySQL. This is better security-wise as you should run away from any host that doesn't have distinct database users or distinct databases for each server user, and you can be assured that no one else will be able to change (or even just see) the session information. However, this isn't as flexible, as you need a table structure to store anything you want to store.
I was doing some research on StackOverflow on how to properly set sessions and prevent hijacking, etc. I found an answer that someone posted on one of the questions and he provided the following code:
For when a user logs in and the username and password match
$_SESSION['fingerprint'] = md5($_SERVER['HTTP_USER_AGENT'] .''. $_SERVER['REMOTE_ADDR']);
Checking if user is logged in, for protected pages:
if ($_SESSION['fingerprint'] != md5($_SERVER['HTTP_USER_AGENT'] .''. $_SERVER['REMOTE_ADDR'])) {
session_destroy();
header('Location: login.php');
exit();
}
It seems to work fine, but my questions are: how secure is this, is this a good method or should I try something else? The post had no upvotes or anything so not sure if it's good.
Also, not sure how to get information about a user with this session .. do I need to store anything in the database?
Thank you!
There are two major problems with this code.
1) IP addresses change for legitimate reasons. If the client is behind a load balancer, like at a corporate network, then he will be unable to use your web app.
2) Checking the user agent is a lot like having a get variable that says ?is_hacker=false. If the hacker has the session id, he has the user agent and its trivial to spoof.
Further more i have no idea why you would want to use md5 for this when doing a plain text comparison is actually more secure. Because the user agent is first an attacker could use the md5 prefixing attack to produce a collision and there for would bypass the REMOTE_ADDR check. (A useful md5 collision attack doesn't come up too often, but this one is fun!)
Even with this check in place CSRF and XSS can still be used to influence the session. XSS can be used to read a CSRF token and then use XHR to make any request the attacker desires. One could make the argument that this is trying to mitigate OWASP a9, but really you need to be using SSL to protect the session id.
This looks like a good method, however the fingerprint hash is generated by client data, which can be spoofed. A good method to use for the login form is to generate a random token that is stored in the session and passed through the form. Once the token is validated (or not) it should be unset for a one time use only.
The session should also store the user id once the user is logged in to retreive the user info stored in the databse.
I agree with Rook's comments, it's a pretty good analysis of your code.
There's lots to consider for securing PHP sessions but with an up to date version of PHP it's not difficult to achieve, some things to think about:
- Where the session files are stored on your server (mainly an issue if it's a shared server)
- Using a secure connection for all sensitive data and cookies going between the client & server
- Doing what you can to make the cookie session ID on the client secure
- Not storing any sensitive data in a session variable
As for storing things in a database it depends on your needs but I'd say you probably don't need it and storing data in the session variable is fine for security, just (as I've already stated) don't store anything sensitive there. Retrieve sensitive data from another location, most likely a database.
If you need to know more about PHP session security I've got a series of blog posts on the subject.
I am wondering what the risks are of storing the userid in a session?
then simply doing a
if(isset($_SESSION['user_id'])){
login_user($_SESSION['user_id]);
}
Are sessions encrypted enough that we wont have to worry about hashing them?
What are the chances of someone being able to change their ID?
The session is by default stored in /tmp as a file. It is not viewable by the end user unless you have security issues such as directory traversal vulnerabilities.
The only portion the client sees is the unique hash stored in a cookie which maps to the relevant session on the server.
Most applications use $_SESSION as you are. If there where a wide spread weakness then major projects would be doing things differently.
Storing a user id in $_SESSION is a reasonably common practice.
Your alternative could be to store the session information (including current user id) in a table using the session_id() in some form, as the key.
Session information is stored as plain text.
Dependant on your setup, the session location should be safe on a properly setup server. It is possible to change the location with session_save_path() which will overcome potential location issues.
If some one can access your session, he can, probably, access much much more. I would not hash it and also make sure it does not get to the client
I would advise against adding only the user id to the session. For example:
1: Create an account in one browser and log in. Then leave that browser open and go to another computer.
2: Log into the same account and delete it. Now make a new account with a different password (with the same username, if that is used as the id).
3: Go back to your other computer and do stuff. You will find that you could quite possibly now be using the account made on the other computer.
Basically, since the session stores the id this may not necessarily still belong to the same person depending on iff accounts have changed etc. And if no password is required (since you already went though that process when you owned the account) then it is similar to breaking in.
So this seems to only have a chance of working if, when you delete user accounts from the database, numeric ids can be reused (about 2% of the systems I have seen do this). Or if the user id is the username (about 20% I have seen do this).
So I would instead suggest adding the userid and the password hash (i.e md5, sha1) to the session and obtain the user information using both of them each time.
I'm using php for my site and was wondeirng if it would be a good idea to use the $_SERVER
md5($_SERVER['remote_addr'] + $_SERVER['http_user_agent'])) into a cookie_auth field in the user table.
When the user logs in, php will use the above key to re-check the current user and compare it to the stored key and if matched get credintials for the user.
The problems are, the user agent can change and IP can change. I guess my main concern is the user user agent. IP addresses typically stay around for a month or two and my primary user base has static ip addresses (companies) so this shouldn't be issue.
Are there any other php $_SERVER variablies that I could concatinate that would be less volitile... but still dynamic?
I have the php manual infront of me but I don't see any usefull... Maybe I'm missing something.
Do other developers implement anything similar to this?
Thoughts?
Is there a better way to go about this?
It won't work, also because of proxies. If two people with the same user agent visit, then it's disaster.
Some projects can do "cookieless sessions" by passing the session id in a GET variable in all URLs that they use.
PHP can actually do this by itself. And you can even force PHP to not use cookies at all, just pass it in GET variables.
But there are some drawbacks. If you invoke URLs of your application in your javascript code, you have to insert the session id there. Also, if there are external links, the session id can be made available via the referer (sic) HTTP parameter to third parties, which could result in potential session stealing. You have to be extra careful with XSS holes. You probably have to be careful with session fixation happening during the login procedure of your application. And so on.
my primary user base has static ip addresses (companies)
So, if one persone in MegaCorp (with all the same browsers, and the same external IP address) logs in, everybody there is logged in? Don't do it.
And another reason: all iPhones in the same area (same proxy, same browser) are logged in. All I have to do to break in is just to be within several hundred meters (to some kilometers in some places) to someone with access, and it's automagically granted to me.
There are in general 2 ways to have a 'passwordless login' (which is where most of these questions originate):
Cookies with a sufficient 'unguessable hash' from a previous login
Convince the user to install a certificate you can validate over HTTPS.
Most of the $_SERVER variables are attacker controlled (remote_addr is pulled directly from the tcp socket and there for cannot be spoofed or otherwise tampered with). However an attacker can change the user-agent to anything.
Don't re-invent the wheal. session_start() and the $_SESSION super-global is secure, easy to implement and robust. To use this you should always call session_start() in a header file for all pages.
if(!$_SESSION[logged_in]){
header("location: login.php");
die();//Yes php keeps executing so you need this!
}
then in login.php:
if(login($_REQUEST[user],$_REQUEST[password])){
$_SESSION[logged_in]=true;
}
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.