Session hijacking from another angle - php

I have been working on a secure login/portal type set of tools, the general code is free from SQL injections, XSS etc, I have mulitple things in place to stop session hijacking.
regenerate session's ID for EVERY page
Compare the user's IP with the IP at login
compare the user's user_agent with the agent at login
have short session time outs
etc
I have done all I can think of to stop hijacking, however I have still located a situation where it might be possible and would like to know if anyone has any ideas.
Imagine a situation where you have 2 users behind a firewall which does SNAT/DNAT, so both apart to come from the same IP. They are both identical machines supplied by the same place. One connects to the site and logs in, the other copies the PHPSESSID cookie and can simply steal the session.
This might sound like an extreme example, however this is very similar to my place of work, everyone is behind a firewall so looks to be the same IP, and all machines are managed/supplied by the IT team, so all have the same version of browser, OS etc etc.
I am trying to think of another way (server side) to stop the hijacking or minimize it further, I was thinking of a token which gets embedded into every URL (changed for each page), and checked.
I am looking for ideas or suggestions, if you want to offer code or examples you're welcome, but I am more interested in out of the box ideas or comments on my token idea.

Force everything to use HTTPS.
I think you are referring to a passive attack where a user in the network sniffs the cookie. For that, you don't need HTTPS. There are several options that are sufficient when the parties are sure to whom they're talking (e.g. you could do a DH exchange first and the server would encrypt a token the client would use in the next request...), but it's not worth the trouble going down that route.
If the user initially types in a non-https address, an active attack is still possible, but there's nothing you can do in that case. In the future, you might prevent future attacks of this kind once the user establishes one unadulterated connection to your site through HTTP strict transport security..

I wrote the main login portal for a major branch of the U.S. military.
I did all you mentioned above, plus at least one more step:
Have you stored a cookie on first login w/ the SESSION salt? Then encrypt everything serverside using that salt. The crooks would have to know about THAT cookie and STEAL IT, and it dramatically reduces exposure to session hijacking, as they just aren't lokoing for it.
Also, use JS and AJAX to detect if they have flash installed and if they do, store a flash cookie, too, with another salt. At that point you can more or less assume you have some pretty dedicated attackers out there and there's not much more you can do (like sending your users GPG keys to use via javascript and make them sign every single bit of data they send to you).

Do not reinvent the wheal, the built in session handler for your platform is very secure.
There are a number of configuration for PHP's session handler. Use HTTPS, at no point can a session ID be transmitted over http "cookie_secure" does this, its a great feature but a terrible name. httponly cookies makes xss harder because javascript cannot access document.cookie. Use_only_cookies stops session fixation, because an attacker cannot influence this value on another domain (unless he has xss, but thats a moot point).
PHP configuration:
session.cookie_httponly=on
session.cookie_secure=on
session.use_only_cookies=on

I am trying to think of another way (server side) to stop the hijacking or minimize it further, I was thinking of a token which gets embedded into every URL (changed for each page), and checked.
You should look at:
Understanding the Rails Authenticity Token
Tokens are a good idea.

Related

How do I secure user login in PHP

So I have my database with the standard usernames and hashed passwords (password_hash).
There's a login form on my site, where users type their details and a session gets created based on that.
<?php
session_start();
//if the username and password is valid
if(validLogin){
$_SESSION['account'] = $username;
}
//$_SESSION['account'] is used from now on for backend user activities
?>
If the credentials are correct, an account session variable is created pointing to the username.
I have increased Session lengths to 1 month (as users complained they kept getting logged out before)
What can I do to increase security here?
If I go into Dev Tools, there is only a single cookie called PHPSESSID, which holds a 26 character value.
However, anyone can just copy and paste that value into their own browser and hijack someone's account - if they had the value.
I am not sure what to do and quite lost.
How can I improve the security here? Besides logging out users every 24 minutes
Firstly, The concept of a session (originally) implied:
The session begins when you open an application, continuous as long as
you work on it, and ends when you close the app.
Since the nature of apps changed and for convenience reasons, this basic pattern has been extended, and sessions kept alive much longer, even if the user is not actively working on it. However, if security is your main focus use a more strict approach, i.e. shorter expiration time and forced logouts.
Secondly, PHP sessions have been invented to solve many of the problems that plague regular browser cookies (stored on the client as text, limited to 4KB, rather accessible, sent along with every request, hence bloating the HTTP request). A PHP session only sends a hashed ID to the browser, and stores all data on the server. If an attacker owns the client security is indeed compromised. But this may be out of your hands if you cannot control the client device security. Security is a multi-layered concept that implies varying degrees of trust..
This answer gives more context on PHP session security and has some useful security recommendations. However, I have one additional recommendation: If you do not need to work with the PHP session id in your client code (i.e. JavaScript) disable session.cookie-httponly in your php.ini (or alike).
If this all is not 'good enough' you will need to implement a more secure protocol, use multi-factor-authentication, or alike. In general, session ids are probably your least concern; having a properly configured web server and following best practices is more important.

How exactly does session hijacking work in PHP?

I've made a website which has registration/login. I can see the PHPSESSID cookie in Chrome's Developer Tools, so I'm wondering how can I use this session id value to hijack into the account I'm logged, from let's say a different browser, for simplicity's sake?
Should a secure website be able to determine that this session is being hijacked and prevent it?
Also, how come other big sites that use PHP (e.g. Facebook) do not have PHPSESSID cookies? Do they give it a different name for obscurity, or do they just use a different mechanism altogether?
Lots of good questions, and good on you for asking them.
First.. a session is just a cookie. A 'session' is not something that's part of the HTTP stack. PHP just happens to provide some conveniences that make it easy to work with cookies, thus introducing sessions. PHP chooses PHPSESSID as a default name for the cookie, but you can choose any you want.. even in PHP you can change the session_name.
Everything an attacker has to do is grab that session cookie you're looking at, and use it in its own browser. The attacker can do this with automated scripts or for instance using firebug, you can just change the current cookie values.
So yes, if I have your id.. I can steal your session if you didn't do anything to prevent it.
However.. the hardest part for an attacker is to obtain the cookie in the first place. The attacker can't really do this, unless:
They have access to your computer
They somehow are able to snoop in on your network traffic.
The first part is hard to solve.. there are some tricks you can do to identify the computer that started the session (check if the user agent changed, check if the ip address changed), but non are waterproof or not so great solutions.
You can fix the second by ensuring that all your traffic is encrypted using HTTPS. There are very little reasons to not use HTTPS. If you have a 'logged in' area on your site, do use SSL!!
I hope this kind of answers your question.. A few other pointers I thought of right now:
Whenever a user logs in, give them a new session id
Whenever a user logs out, also give them a new session id!
Make sure that under no circumstances the browser can determine the value of the session cookie. If you don't recognize the cookie, regenerate a new one!
If you're on the same IP and using the same browser, all you have to do is duplicating the session ID (and maybe other cookie values: not really sure if browser specific things like its agent string is tracked/compared; this is implementation dependant).
In general, there are different ways to track users (in the end it's just user tracking). For example, you could use a cookie or some hidden value inside the web page. You could as well use a value in HTTP GET requests, a Flash cookie or some other method of authentication (or a combination of these).
In case of Facebook they use several cookie values, so I'd just assume they use one of these values (e.g. 'xs').
Overall, there's no real 100% secure way to do it (e.g. due to man-in-the-middle attacks), but overall, I'd do the following:
Upon logging in, store the user's IP address, his browser agent string and a unique token (edit due to comment above: you could as well skip he IP address; making the whole thing a bit less secure).
Client side store the user's unique id (e.g. user id) and that token (in a cookie or GET value).
As long as the data stored in first step matches, it's the same user. To log out, simply delete the token from the database.
Oh, and just to mention it: All these things aren't PHP specific. They can be done with any server side language (Perl, PHP, Ruby, C#, ...) or server in general.
Someone sniffs the session ID cookie and sets it for a subsequent request. If that's the only thing authenticated a user, they're logged in.
Most sites will use authentication based on cookies in some form. There are several ways to make this more secure such as storing info about the user's browser when they log in (e.g. user agent, IP address). If someone else naively tries to copy the cookie, it won't work. (Of course, there are ways around this too.) You'll also see session cookies being regenerated periodically to make sure they aren't valid for a particularly long time.
Check out Firesheep for a Firefox extension that performs session hijacking. I'm not suggesting you use it, but you may find the discussion on that page interesting.

Hashing a session fingerprint really necessary?

Please read this THOUROUGHLY before voting...
So I have seen a lot of session management classes that create a fingerprint via concatenation of user agent and a couple of ip blocks or whatever. They seem to also add a salt and then hash this fingerprint before storing it in a session variable.
This fingerprint generation typically happens every request in order to verify that the current user of the session is in deed the original session user. This is why I am wondering, is the salt and hash really necessary on something like this?
If a hacker can get onto your filesystem to see your session file contents, aren't you already hosed at that point?
Any info greatly appreciated.
Most of it makes sense, but the hashing and salting makes no sense.
If you tie the session to an IP address, then it becomes a lot harder to hijack into a session. This is something I recommend doing, but you don't need to be utterly strict about it. You can just tie to the first three parts of the IPv4 or so. The choice is yours. The more strict IP check the more secure it is, but the less convenient it is for users.
And as for tying the session based on the user agent, that may also help. It must be realized that if you work on an unencrypted channel (HTTP for example), then the user agent check is less useful as it can be reproduced by the intruder as well.
When it comes to salting and hashing, that is useless. They add no strength to your identity checks. The only thing they do is complicate your design. For this matter, I believe they lower your level of security.
As always, a few rules to keep in mind:
Use strong session identifiers. This means use good random sources and make sure there are enough bits.
Tie the session to an IP, at least to some extent.
Tie the session to a user agent, if possible.
Use SSL/TLS. Without it, theoretically all session systems are insecure.
Secure your session storage. Whether it's filesystem based or database based.
I can think of two cases where it would be useful:
When the session data is stored client-side. (Like in a cookie.) So, I'd be prevented from taking my cookie to another computer, and I'd be prevented from making up my own cookie contents. (Ok, so this is not a very likely scenario...)
When the session data is stored in some shared server-side resource (i.e., /tmp) and is vulnerable to snooping. In this case, if the snooper is able to see the contents of the session, they'll still be unable to fake a connection to that session because they don't know what data went into the fingerprint.
In complement to the response of #Kai Sellgren (+1) which contains some good hints on how to secure your session storage I would add some ideas than can explain the hash & salt on some specific applications.
I'm not talking of application that are using the cookie as a session storage, we still see this for example on Prestashop eCommerce solution, with encryption of the cookie content (why the hell did they decide to store the session on the cookie?). I understand we talk about server side session storage.
The key point is layered Security and in-depth defense:
Compromissions are never boolean things, your are not 'completly compromised' or 'completly secure'. One of the the real history I like about that is the mySpace worm explanation, it shows a real attack and how defensive steps must be break. There's always a new wall. Just one example, I share the same IP as my boss when i'm in the office, and maybe the same browser, this could break a security based only on IP+user-agent.
So in the hash & salt of session stamping we are clearly acting after a few walls have fallen. And kai shows us some of these walls. When he talks about securing the session storage I would add 2 things:
it's a really good idea to alter the session.save_path and the open_basedir of each PHP application (and get a separate Virtualhost for each). Rarely done.
if your application is installed on a path (like /myapp), add a prefix_path on the session cookie (and fix it for any other app on the same server)
Now Let's imagine a realistic compromission. You've several ways to compromise the session on the server side:
The application is running on a website with some other applications running in other paths (or in other domains in the same server). And at least on of theses applications is quite unsecure. At worst server side code could be injected in this app, but some of the security walls (like open_basedir or other chrooting techniques) may prevent this injected code from affecting your separate application (or data).
Some of the javascript libraries comes with some test subdirectories containing highly insecure scripts, with not only nice session disclosure but maybe some session fixation or prediction available.
The application is shared, and talking about wordpress-like softs you can imagine some platforms sharing a lot of different installations, with different modules and maybe some custom code. On such platforms you'll find settings to allow altering the salt for each consumer, there's a reason for that. One of the website could impact the security of others and clean separation can be harder to do if the applications wants to manage the websites all-in-one.
Your targeted application may get hit by the environment, if the session storage can be shared with some scripts from other application, or from a script in your own application that you did'nt even notice (like these f*** examples in javascript libs, why didn't you suspend php execution on static file directories!)
From this first step of compromission the attacker could potentialy (and in severity increasing):
read the session stamps and maybe find which information he should fake to get the same stamp
build a new session containing a session stamp valid for his configuration, and then use this new session identifier on your application. Your application will find the session file, and accept him.
alter one of your valid session to modify the stamp in the same way
A simple hash of the stamp would make his life harder, but it would just be a wall to break, the salt make this wall really harder to break.
One important point is, from your question, if a guy can alter something in the session storage am I already in a bad mood?. Well, maybe not completly. If it is the only thing the chroot/separation/securization of applications allows him to do this salt will be a nightmare for him.
And the second important point is: should I do this level of in-depth security on every web application?. Answer is no. Overengineering is a bad thing and can reduce the security of your application by the simple fact it became harder to understand and maitin. You do not need to complexify your application if:
you've got a pretty good level of session storage separation
you're alone on your server, only one application, and not any sort of multisite handling
your application security level is so weak that a simple code injection is available on the application, so a session fixation is not needed for an attacker :-)
I can imagine that the point of hashing that fingerprint information is storage space as the resulting hash has a fixed length.
But to also use a salt doesn’t make much sense to me. Because, as you’ve already said, since that data is stored in the session data storage location, you would already have a bigger problem than session fixation/hijacking if someone would be able to obtain that data.
You can find a plausible solution here:
http://shiflett.org/articles/the-truth-about-sessions
Fingerprinting combats session hijacking.
The attacker not only needs your session_id, he also needs any sensitive HTTP headers.
It adds another barrier for the attacker, albeit one that can be easily overcome.
The hash is there to make the data uniform. The salt is there to obscure the hashing process - so an attacker can not generate a valid fingerprint for his own combination of HTTP headers.
If a hacker is in your filesystem you have bigger problems :D
A lot of people who don't understand very much about security combine bits of advice floating around the internet in the hope that what they end up with will be "good enough". Tying the session ID to the U-A breaks browser upgrades (which Chrome does fairly often) and tying to the IP address breaks mobility (anyone with a laptop that uses Wi-Fi), and many ISPs don't have contiguous allocations. Anyone who can sniff cookies can also sniff the U-A, and will probably have access to the same IP address because they got the cookie off insecure Wi-Fi behind a NAT.
What you probably do want to do is change the session ID on a login attempt, which is a reliable way to prevent "session fixation" attacks (where the attacker makes the victim load http://example.com/?SESSIONID=foo e.g. through an <img>, waits for you to log in, and now knows the victim's session ID). There is little reason to preserve a session across a login, and you can copy the few things that need to be preserved (e.g. a shopping cart) across.
If a hacker can get onto you
filesystem to see your session file
contents, aren't you already hosed at
that point?
If you are using PHP as CGI (like in the case with nginx), then I think no. If you set permissions right then your session files must have read/write permission for PHP user while your PHP files should have only read permissions. So, if you pass the salt from the web server to PHP, then PHP user can't get access to it (he can't create any new/change existing PHP files that can be run by your web server and he can't access web server as it is run on another user), so he can't really hack(change) cookies (only delete them) because he can't get salt. Of course you will have to pass database settings from web server as well.
I never really tried it, so please correct me if I am wrong.
is the salt and hash really necessary on something like this [http client fingerprint]?
The hash might be useful to reduce the number of bytes consumed by the fingerprint inside the session data. So as long as the hashed fingerprint is of a smaller size than the fingerprint itself this can make sense in terms of space reduction. Price is the consumption of system resources to generate the hash.
Does it really make sense? You would need to benchmark this to say so.
How can a salt be helpful then? I must admit, I see no reason for a salt. It would only make sense to make it harder to guess the fingerprint from a hash. But as I do not see any security benefit in hashing the fingerprint (it's kept on the server-side only and is already considerably secure), salting is not adding anything.
In case the session store itself is not considered secure (if that's for the argument), the whole session should be encrypted, not only the fingerprint.
So particularly for the fingerprint, I do not see much use in hashing and salting it.

php session hijacking - is HTTPS enough? Suggestions for fingerprinting?

I use HTTPS, but want to minimize the risk of someone evil crafting their own cookies with a session ID that someone else actually uses recently.
As a session variable I have an expiry time so the session is invalidated if it hasn't been used recently, so I figure the window of opportunity is when the victim is active or recently left the site without logging out properly.
I don't expect huge amounts of traffic and I use the standard php methods of generating session IDs. I believe the "risk" of someone actually succeed (or even try) hijacking someones session here is close to zero.
What I would want to do is to "identify" the remote user somehow, without using $_SERVER['REMOTE_ADDR']. My thoughts being that the attacker would have to both find a valid session ID, as well as impersonating the different properties of the actual user.
I don't want to force the user to use a certificate to log in. I want it to work in all standard web browsers, even for my grandmother and other non tech-people like her.
So, what I originally wanted to ask was: are there any "properties" of the HTTPS session that could be used? Would they be useful? If so, how do I find them? phpinfo() reveals nothing HTTPS specific. (Is it because httpd doesn't expose it?)
Should I just use a concatenation of HTTP_USER_AGENT + HTTP_ACCEPT + HTTP_ACCEPT_LANGUAGE + HTTP_ACCEPT_ENCODING + HTTP_ACCEPT_CHARSET or something similar that is assumed to be unique enough between users?
Very happy for all answers! (But please read the question before answering with only referrals to other questions on StackOverflow)
Thank you!
You need to ensure that you've got both the secure and http_only flags set on your session cookies. You also need to change the session_id when a user authenticates to avoid session fixation problems.
While what you propose should be relatively safe in terms of finger-printing, it's not really all that selective - otoh there are lots things which should NOT be used for fingerprinting (like CLIENT_ADDRESS) so its not really very easy to suggest something better.
Apart from my suggestions above, I'd recommend spending your time looking at other potential security problems.
C.
The OWASP top 10 is an excellent aid for this class of attacks.
Specificlly you need to worry about these three:
A2: Cross-Site Scripting (XSS)
A3: Broken Authentication and Session Management.
A5: Cross-Site Request Forgery (CSRF) (Also known as "Session Riding")
Almost all of the $_SESSION variables are known to the attacker and can be any value. There is no point is checking these variables as it is trivial for an attacker influence them. A important exception is $_SERVER['remote_addr'] which is pulled directly from apache's TCP socket, thus this value cannot be spoofed or otherwise tampered with. However, if the attacker is on the same network segment (such as if he was sipping a cup of coffee right behind you at the cafe), then the attacker would have the same ip address.

Cookies/Sessions login system

When a user logins I get him/her's ID and save it in a session var. What I wonder is, is this the way to go? Or should I use cookies? so it automatically login and so on.
session_start();
ifcorrectlogin {
$_SESSION['id'] = mysql_result($loginQuery, 0, 'user_id');
}
how do you authenticate your users?
//Newbie
Yes, this is the way to go. The session itself is already backed by a cookie to remove you any programming efforts around that. The session (actually, the cookie) will live as long as the user has the browser instance open or until the session times out at the server side because the user didn't visit the site for a certain time (usually around 30 minutes).
On login, just put the obtained User in the $_SESSION. On every request on the restricted pages you just check if the logged-in User is available in the $_SESSION and handle the request accordingly, i.e. continue with it or redirect to a login or error page. On logout, just remove the User from the $_SESSION.
If you want to add a Remember me on this computer option, then you'll need to add another cookie yourself which lives longer than the session. You only need to ensure that you generate a long, unique and hard-to-guess value for the cookie, otherwise it's too easy to hack. Look how PHP did it by checking the cookie with the name phpsessionid in your webbrowser.
Cookies can be manipulated very easily. Manage login/logout with Sessions. If you want, you can store the users emailaddress/username in a cookie, and fill the username box for them the next time they visit after the present session has expired.
I would try to find a session engine so you don't have to deal with the misc. security issues that bite you in the ass if you do the slightest thing wrong. I use django which has a session engine built in. I'm not aware of the other offerings in the field although I would assume most frameworks would have one.
The way they did it in django was by placing a cryptographic hash in the user's cookies that gets updated every page view and saving all other session information in a database on your server to prevent user tampering and security issues.
As BalusC mentions, the session_-functions in php are the way to go, your basic idea is sound. But there are still many different realisations, some of them have their pitfalls.
For example, as Jonathan Samson explains, using cookies can result in security holes.
My PHP is a bit rusty, but I remember that the session_-functions can also use session IDs that are encoded in URLs. (There was also an option to have this automatically added to all local links (as GET) and form targets (as POST). But that was not without risks, either.) One way to prevent session hijacking by copying the SID is to remember the IP address and compare it for any request that comes with a valid session ID to to IP that sent this request.
As you can see, the underlying method is only the start, there are many more things to consider. The recommendation by SapphireSun is therefore something to be considered: By using a well tested library, you can gain a good level of security, without using valuable development time for developing your own session system. I would recommend this approach for any system that you want to deploy in the real world.
OTOH, if you want to learn about PHP sessions and security issues, you should definitely do it yourself, if only to understand how not to do it ;-)

Categories