Related
I've been googling this for some hours but everyone handles it in a different way.
So I'm wondering how to handle the informations when someone logs in.
I thought that I'll save the user ID, name and user-agent-data in the session. But what if someone steals the cookie content and replaces his own cookie with the stolen one?
And yeah, that's actually my question. How can I "protect" the user? Checking the IP as well? Anything else?
Thanks,
Albin.
Not to have a session id or cookies in general stolen is a task the browser has to handle. There are some conceptual means to prevent 3rd parties to learn the contents of your cookies like the same origin policy.
You can help the browser by setting the http-only flag for cookies. See the argument $httponly for setcookie. If a cookie is marked as http-only, the browser will not make it accessable for scripts like javascript. The cookie will only be transferred in the original http-header. this will practically eliminate the risk of XSS-based session capturing, as they usually use javascript.
Another big attack is the man in the middle attack. An attacker has access to the traffic between your client and your server. He now can read the http headers, therefore the cookies and imitate the request. He could even spoof your client's IP address. To protect against this kind of attacker, you will need an encrypted connection. Most websites use HTTPS for this purpose.
If you only need authentication, you can also use HTTP's digest authentication. There is a working example for digest auth using PHP here.
Testing if the IP stays the same would be one way. However it's better to test wether it matches a given subnet mask (e.g. 255.255.0.0), because some users might have dynamical IPs.
Another "protection" measurement is testing wether the user agent of the browser is the same that was used to log in, but of course that's pretty easy to bypass.
Make sure you set the cookies only for your domain or subdomain, and also make sure to check your code not to allow any XSS flaws, as these often can be used to steal cookies.
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.
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.
I've developed my website that checks if the user is registered and creates a session variable with the username. It's all that is stored as a session variable. If I want to protect my pages (so that only registered users may see them), I check if the session variable is set.
Is this secure?
Or can you give a more secure method?
Generally, the Session is server side, but If I somehow get the Session ID I can just hijack it.
I'd recommend at least storing either the IP and maybe also the User-Agent, and in case of mismatch, invalidate the Session.
Basically, you are fine with storing whatever you want in Session. The only caveats are:
if you are not using secured connections (like SSL), the sessionId can be sniffed and hijacked. This is of no importance because the username and pass can also be hijacked, and you are subject to "man in the middle" attacks, etc. So basically, your system is fine and provides low security without SSL.
In the articles on PHP they mention some concerns with shared hosting and session hijacking. I'm not sure if this is true, so I've posted a question here. Edit: This concern seems to be real, so you'll have to use one of the workarounds for storing session (e.g., database) if you use PHP.
In general, though, most of the security concerns mentioned (including XSS attacks) are not with storing stuff in Session but rather general security concerns. Storing userid -- or some encrypted form of the same -- in Session is generally quite secure.
Most importantly: if you were to use your own algorithm to generate a random cookie code for each user, that would no doubt have more security flaws (not being an expert) than the session-key generation algorithms of PHP, ASP.NET, Rails, whatever...
I could find a more appropriate Bruce Schneier quote, but this one will do, "No one can duplicate the confidence that RSA offers after 20 years of cryptanalytic review.”
It keeps running in my mind the last couple of days, but I read some articles about how to make your PHP sessions more secure. Almost all of these articles say that you need to save the useragent in the session WITH an additional salt. Something like this:
$fingerprint = md5('SECRET-SALT'.$_SERVER['HTTP_USER_AGENT']);
The salt would make it harder for an attacker to hijack or whatever the session. But WHY add a salt every time you would check it like this:
md5('SECRET-SALT'.$_SERVER['HTTP_USER_AGENT']) == $_SESSION [ 'fingerprint' ]
So WHY would a salt make it more secure, since the attacker still only needs the useragent (which is relativly a small set of different useragents) and the sessionid?
Probably something small I'm overlooking, but can't figure it out, drives me crazy haha
Thanks!
The reason that it's suggested to add a salt is simple. Generally, when you're creating this "fingerprint" - if you're using only one item of data, which has a limited dataset, then it makes it easier for an outside hacker to generate this, and hijack the session.
In your example above, yes, if the attacker has both the "fingerprint" and the User agent, then they will be able to hijack the session.
Adding a salt only makes it harder for an attacker to generate the fingerprint, it's a case of "if they have all but one piece of information, then the last piece of information is rendered useless)
I'd suggest that you add some more things in, for example, within vBulletin (a project I used to work on) the session ID hash (which is basically the same as the fingerprint) is generated with the following code.
define('SESSION_IDHASH', md5($_SERVER['HTTP_USER_AGENT'] . $this->fetch_substr_ip($registry->alt_ip))); // this should *never* change during a session
Also, a session hash is generated using
md5(uniqid(microtime(), true));
These are both checked when trying to identify the session
So, to hijack the session, the person would need to know the following
The time (exactly) on the server when the session was created
The users Browser agent string
The user's IP address
They would also have to spoof the IP address (or at least the first 2/3 octets) to be able to do this.
If they're actually at a point where they've managed to get the above information, then they're probably likely to be able to attack in other ways than just session hijacking.
vBulletin don't actually use a "salt" per se, but, in your above example, the salt is just adding a limited amount of entropy, it's always best to find as much entropy as possible.
For example, in something I'm currently writing in python, I generate a hash for usage with XSRF protection. The following is what I use.
self.key = sha1(
self.user.username +
self.user.password +
settings.SECRET_KEY +
strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime())
).hexdigest()
Which takes the user's username and password, the current time, and a preset salt to generate this. This would be hard for an attacker to generate due to the salt, and the time (though, do note that this is only made secure by the fact that it changes once it's used, with time, it wouldn't take much for someone to crack this for a particular user if it wasnt changing)
If I understand correctly, you want to prevent session hijacking by a remote attacker that guesses session IDs?
If this is not the case, then you are seriously out of your depth - an attacker that can snoop the traffic can also mimic the user agent, and an attacker that gains access to your session storage has you by the balls anyway.
If you store the user agent string to "lock" the session to the current user agent, then there is really no point in hashing it - string comparison on the full user agent string is faster (then hashing and then comparing) and not significantly more expensive in terms of storage.
I don't believe storing the user agent is providing enough differentiation - something better would be to generate a larger ID (with more bits) at session start time (maybe sha1 the current time stamp + user name + user agent + something), then store that in a cookie as well as in the session and match it up on each additional request. This doesn't change the attack vector much (you still need to guess some number), but its easy to significantly increase the number of bits that must be guess for a successful attack there by massively increasing the difficulty of the attack.
Update:
Something that other answers have mentioned in passing but is important to point about salting hashes: salting your hashes only makes sense if you expect an attacker to gain access to your stored hashes but not to your code, and then somehow uses it to leverage an attack.
This makes sense to passwords that are stored for a long time, usually in a well known location, and used by code that is hard to locate.
This does not make sense for your use case because:
The information is only viable while a session in progress (before timing out) this is rarely more than a few hours, after which - even if they got the storage and decoded everything - the session cannot be hijacked because it is over.
Usually if the attacker has timely access to your session storage, they have access to your plain text PHP code and can see your salt.
Unless you store your sessions in a completely unreasonable place (such as an S3 bucket), a hash stealing attack is mind boggingly less likely than a lot of other attacks that will be a lot more useful.
In short: don't waste your time writing session verification code - PHP built-in session management is already secure enough.
If you are on your own server, encrypting session variables is pointless, because they don't get out of the server. See Linead answer to What do I need to store in the php session when user logged in? for more info. If you are in a shared server, you may need to encrypt every session variables, besides the session ID, because they are stored on temp files readable by the same web server all your neighbours are using.
Anyway, if you are really worried about security, you are better with your own (virtual or not) server, so danger will only come from outside your server.
Some examples of risk to your sessions:
Your server sends the session ID in the URL, and your user follows a link to badguys.com They will get in server variables the referer (complete URL, including your session ID), the browser and the IP address of your user. If you are not checking IPs, or your user uses an open proxy, they only have to install same browser version, paste the URL, and they're done.
User go to a public PC, logins, and leave without closing his session (hey, he's human after all). Next guy in the row opens the browser, check history and finds an open session. Yuck.
So, some measures you can take, by my usual preference:
Don't send the session ID in the URL; enable session.use_only_cookies in PHP. Cons: User needs to enable cookies.
On dangerous actions (change password, make an order...), ask user for password again. You can do it periodically too. Cons: Annoying.
Timeout sessions fast. Cons: In most sites, this will force users to login often, annoying them.
Use SSL (only way to avoid 'man in the middle' attacks). Cons: Slow. Stupid browser messages. Need SSL on server.
Check the IP. Cons: Inneffective for visitors using a public proxy. Annoying for dynamic IPs.
Check the User Agent (browser). Cons: pretty much useless, UA is easy to get and trivial to imitate.
(I take for granted you have yet PHP configured for maximum security).
Some more extreme measures:
Maintain a permanent connection between server and browser, e.g. using a Java applet. No connection, no session. Cons: User needs Java, ActiveX or whatever you use. Session closes with browser (this can be good). Doesn't work on very slow connections. Higher load on server. You need to open ports, have a special server for the applet.
The same, but using asynchronous requests (e.g. AJAX) to refresh very frequently the session, and a very short timeout. Or refreshing a hidden IFRAME. Cons: User needs JavaScript. Doesn't work on very slow connections. Higher load on server.
The same, but reloading the whole page. Cons: User needs JavaScript. An automatic reload while you are reading a page is very annoying.
In some corner cases, you can forget about sessions and use Apache authentication instead. Simplest solution, but a lot of limitations.
As the fingerprint is stored on the server side, you don’t need to use a salted hash. A “normal” hash is enough to reduce the data.
I see one purpose in salting your fingerprint. If a bad guy gets hold of your session-db (god knows why) but not of your code he couldnt "guess" your fingerprinting method by trying the common user-agents against it.
I do that as well to partially protect from session impersonation attacks. You need to include the IP address as well.
Keep in mind that when the client's browser auto updates the user agent changes and you'll think that his session has been hijacked ;)
Bear in mind that if you do that you're forcing people to login again if they upgrade their browser. This can be OK but just make sure it's your intent.
Using the user's remote address is not without problems either. Many people use the same computer from different locations. Mobile devices, laptops being used at home and work, laptops being used at Wifi hotspots and so on. IMHO it's a bad idea to use IP address in such a way that a new IP address requires a login unless you're dealing with highly sensitive information such as online banking. Is that the case?
What are you concerned about? External attack? Or in a shared host situation that someone can read your session information?
If it's the latter, the solution is simple: just don't store anything sensitive in the session. Anything sensitive should be stored in the database.
In terms of creating a secret salt, you need to use something that isn't guessable. I would go for something like a random string that's created when the user is created. If necessary recreate it each time the session is invalidated.
As for what it would make it more secure, you said it yourself: there are limited user agent strings (less than a hundred will probably cover 99.99% of users). A salt simply increases the number of possibilities. That being said, if you use the same salt for all sessions then it's only a matter of time before it's found with brute force.
Okay, for example I'm using the following fictional code:
<?php
// The sessionid cookie is now a certain hash
if ( array_key_exists ( $_COOKIE [ 'sessionid' ] ) )
{
// Get the session from database
$db_sessid = $pdo -> getStuff ( 'session_database', $_COOKIE [ 'sessionid' ] );
if ( $db_sessid !== null && $db_sessid [ 'fingerprint' ] == sha1 ( 'SOMESALT' . $_SERVER [ 'HTTP_USER_AGENT' ] ) )
{
set_cookie ( ... ); // New sessionid and write also to DB
// User is now logged in, execute some user stuff
}
else
{
// Session doesn't exist, or the fingerprint does not match
}
}
Now the attacker only still needs the sessionid, which is in the cookie (sent along HTTP headers) and the useragent. So what's still the point of the additional salt?
Checking for IP's is also in my opinion not such a good option, some providers or proxy's change them every single request.
Thanks so far (-:
you allow the cookie after all the safegard parameters are met to just set a cookie if parameter are not met the cokkie will never be set nice but if the cookie has a parameter vissible what happens then. as well if conditions are never met the session willneevr be met.is that what you realy want. remeber a check met conditions give session and seession data way through the cookie
remember the cokkie sits on the clients browzer
regards stelios