in Web 2.0 applications many users usually want to stay logged in ('remember me' flag) and on the other hand their cookie can give access to very private data. Is there a way to prevent that somebody who steals the cookie - directly from the computer or via sniffing - can use the cookie to get access to the user's data? Always HTTPS is not an option.
Thanks, Bernd
[Edit] Connect the IP address to the cookie is not an option either.
KISS -- just use sessions so that you're using an ID that is already automatically created by the server-side scripting language of your choice. That's hard enough to guess. Then, if it's stolen, store the IP address and user-agent of the visitor in the session (making sure never to output that) and only consider the session valid only if the already stored IP address and user agent match that which is found for the remote client.
In this scenario, the attacker would have to do the following three things:
Steal the victim's cookies
Spoof the correct IP address
Spoof the correct User Agent
It also helps to make sure that the attacker doesn't already know all of the things he/she would have to do in order to correctly take over a victim's session. IE: They may assume just the cookie is needed and then fail... and have to figure out everything else through a very long trial and error. In this way, you gain security through obscurity and through difficulty, depending on the skill of the attacker and his/her existing knowledge of the system.
Bernd -- the trouble with anything done over standard HTTP is that it's plaintext; anyone can fake anything. IP Spoofing is a bit more challenging to do than just plain cookie stealing, so tying to the IP tends to be what people do. Like you said, that does not work very well with highly dynamic environments.
The only mostly secure way I can think of is to use HTTPS to place and verify a "permanent" cookie, and then place (in the same HTTPS session) a short-lived session cookie. The rest of the communication can be done over regular HTTP, using the session cookie to authenticate.
That way, fewer resources are used in supporting encryption (just the handshake), the permanent cookie is not exposed -- it's only transmitted under encryption -- and stealing the session cookie opens up to only limited risk, since that cookie will quickly expire.
All that being said -- don't let users click "remember me" on a site that contains truly sensitive data! That's why Banks don't do it..
Hope this helps.
About storing complex cookie ids and associated IPs in a database -- you don't really have to do that. If you have a secret key K, it is enough to encrypt the user's ip with your K, and place the result {IP}K as a cookie. As long as your key is secure (and the crypto hasn't been broken -- but if that happens, we have bigger problems), this is safe.
Perhaps using a Session ID and token (a hash based on the IP, a salt, and the Session ID), that is regenerated every request (use a fast hashing algorithm) would be a good approach? I store session data in a database (currently), and this means I have a two query overhead every request. It works like this:
Select where SID and TOK match.
Verify a token generated based on current client matches that in the database.
deserialise the data into a property.
Scripts etc happening.
Serialise the updated data, regenerate the SID/TOK, and update DB where SID/TOK = old sid and tok, updated data and new sid and tok. Set the cookie to the new SID and TOK.
In this way, firstly cookies are bound to whatever I base the token on (in this case, remote address), and if that is stolen and client data spoofed, the cookie is only useful for one request anyway - by the time the cookie is intercepted, it is useless.
The only perceivable weakness I can see is if the attacker managed to grab a cookie, spoof, and use it, before the real person could do another request. There are a few ways to solve this that I need to think about. The overhead is two queries and generating a token hash twice (once for verification, once for replacement).
Put a lid on the cookie jar.
Jokes aside, the best option has already been stated - make the cookie an obscure ID and tie it to an IP address lookup on the server side. Since you edited to say you cannot tie it to an IP address, that leaves the obscure ID part. Your options are limited with cookies - the minute you place something on the client, it becomes a risk.
Store a cookie that is an obscure ID into your local server database. Do a server-side DB lookup based on the ID provided in the cookie. Be sure to make the ID sufficiently complex that it cannot be easily guessed. Map the ID to the IP Address of the user. If their IP changes, then force them to log in again, and create a new ID.
On second read, it sounds like you want a high level of security with your hands tied. The user must have the choice to remain logged in and thus increase his/her risk. You can implement all the security in the world from the application's and server's point of view, but if the user forgets their laptop on a table in Tim Horton's (Canadian Starbucks), then none of it will do you any good.
Leave the choice up to the user as to whether or not they remain logged in, and give them a warning about their information being at risk.
Bernd - you say connecting the IP address to the cookie is not an option, I'm assuming that's b/c the user could be connected via DHCP, and thus could come in under a different IP each time. Have you considered tying the cookie to the DNS host name? You could encrypt the cookie using a private key, and store it on the user's box. Then whenever they come in, check the cookie, un-encrypt it, and then check the user's current DNS Host name against the one in the cookie. If it matches, you allow them in. If not, you don't allow the auto-login.
FYI - in ASP.Net, to get the DNS host name of the user's box, just look at
Page.Request.UserHostName
Related
So I just noticed that one of the internet banks websites is passing session id as url parameter. ( See image below )
I didn't previously see anywhere that ';' in url, in this case it is after 'private;'.
1) What is the use of this ';'?
2) And why internet bank, which needs to be securest place in the internet is passing session id as url parameter?
At first, I thought they are doing it because some of the users disallow use of cookies, but then again, if they allow it, use cookies, if not - url, but I do allow use of cookies, so obviously thats not the case.
3) I guess then they should have some other security measures? What they could be?
4) And what one can possibly do if he knows others valid session id?
As I know, you can quite easily log into others peoples session if you know that id, because its not hard to edit cookies and its much easier to pass that session id as url parameter, especially if you have something like:
session_id($_GET[sessionid]);
Thanks!
1) You should ask whoever designed the application your red box is covering. URL can be anything you want; the convention of key=value&key2=value2 is just that - a convention. In this case, it's Java, and it commonly uses the convention of ;jsessionid=.... for its SID.
2) It's not that big of a deal. Normal users can't copy-paste cookies like they can copy-paste a GET parameter, but power users can do whatever they want (using Mechanize, wget, curl and other non-browser means, or even browser extensions). And if you allow it for some users and disallow for some, it's not really much of a security precaution, is it? Basically, cookie SID will make the attack a bit harder, but it's like putting your front door key under the mat - definitely doesn't keep your door secure. Additionally, cookies are shared between tabs: if a site wants you to be logged in with two accounts at once, you can't do it with cookies.
3) Serverside security, yes. One effective countermeasure is one-time SIDs (each time you visit a page, the server reads the session from the current SID, then starts a new session with a new SID for the next request). A less effective but still good method is to validate other information for consistency (e.g. - still same IP? Still same browser?)
4) Yes, if you know someone's valid SID, and the server does not adequately protect against session fixation, you can "become" that person. This might enable the attacker to, say, pay his bills with your money, for instance.
So, #Amadan correctly covered #1 and #4. But there's a bit more that needs expansion.
Using Session identifiers in a URL can be a major problem. There are a few cases where it's critically bad:
Session Hijacking:
If a user copy-pastes a URL into an email.
In this case, the attacker can simply read the email, and steal the session identifier (thereby resuming the session).
You could partially defend against this by making session lifetimes short, and validating things like IP addresses or User Agents in the session. Note that none of these are foolproof, they just make it "slightly" harder to attack.
If the connection is ever downgraded to HTTP.
If they are not using Http-Strict-Transport-Security (HSTS), then an attacker may be able to successfully downgrade the session to HTTP only (via MITM style attack). If the server isn't setup perfectly, this can cause the URL to leak to the attacker, and hence the session identifier.
Session Fixation Attacks
An attacker can craft a session identifier, and send the user a forged link with that session identifier. The user then logs in to the site, and the session is now tied to their account.
You can mitigate this by strictly rotating session identifiers every time the session changes (log in, log out, privilege upgrade or downgrade, etc). But many servers don't do this, and hence are susceptible to fixation style attacks.
The reason that cookie sessions are seen as more secure is not because they are harder to edit. It's because they are more resistant to fixation attacks (you can't create a URL or link or form or js or anything that sends a fraudulent cookie on behalf of the user).
Why the bank uses a URL parameter? I have two guesses:
Because they want to support those who don't allow cookies.
Which is sigh worthy.
They don't know any better.
Seriously. If it's not in a compliance doc or NIST recommendation, then they likely don't do it. Hell, there are implemented NIST recommendations that are known to be insecure, yet are still followed because it's in writing.
What is the use of this ;?
This is just a query string separator. & isn't the only sub-delim specified in the URL specification (RFC 3986).
And why internet bank, which needs to be securest place in the internet is passing session id as url parameter?
It could be that this session ID is never used, and the actual session identifier user is passed in cookies or in POST data between each navigated page. The only way to verify this is to try copying the URL into another browser to see if your session is resumed, however then again they may be checking things like User Agent - not real security but would dissuade casual attacks. Do not try this on a live system you do not have permission to do so on as it would be illegal. If you want to learn about security download something like Hacme Bank and try on there.
I guess then they should have some other security measures? What they could be?
No doubt they will, otherwise this would be a huge security threat. The URL could be leaked in the referer header if there are any external links on the page. The types of security a bank uses for their website is too large to list here, however they should be meeting certain industry standards such as ISO/IEC 27001 that will cover the types of threat that their site would need to be secure against.
And what one can possibly do if he knows others valid session id? As I know, you can quite easily log into others peoples session if you know that id, because its not hard to edit cookies and its much easier to pass that session id as url parameter, especially if you have something like:
As the ID is displayed on the screen it might be possible to read it (although IDs are generally long). A more realistic attack is Session Fixation. This is where an attacker can set the Session ID of their victim. For example, sending them a link that includes the attacker's Session ID. When the victim follows it and then logs in, as the attacker has the same session, they are logged in too.
Storing the Session information in a cookie or in a URL are both viable methods. A combination may used as
Security session management and (Server) Session management are separate aspects:
The fundamental difference is that cookies are shared between browser windows/tabs, the url not.
If you want your user to be logged on when navigating to the same site in different tab, sharing the security session (=without a new logon procedure) then cookies are a good way.
To differentiate "sessions" per tab and associate distinct server sessions with distinct tabs (Think of the user running two "stateful" transactions in two different tabs in parallel), managing a sessionId on the client which can be different per tab is required. Cookies won't work here.
Putting it in the URL is one way to assure this information is routinely added to requests fired from the page (referrer header). Alternative methods would require specific code to add this information explicitly to each request which is more work.
See How to differ sessions in browser-tabs?
I want to authenticate my users based entirely on cookies and sql db.
What I do is:
1. Once they login, I generate a random string, create a hash from it, save it in the database along with the user id and his IP.
2. I send the hash to the user as cookie
3. Whenever he wants to access something, I verify if his cookie hash matches the one on the server and also if his IP matches. Of yes, he is valid or else, log him out.
4. (As pointed by Akhil) If he clears his browser cookies or anything does not match the information on the database, I clear all the rows with his username and log him out.
Note: I use a session cookie for storing the random hash, which again is generated using the timestamp, and as long as time doesn't repeat itself(I believe), its random in the corect way.
Is this fine? How can I make it better?
Once they login, I generate a random string
Make sure you use a cryptographically secure method to generate the random string. Do not use mt_rand use something such as openssl_random_pseudo_bytes.
create a hash from it,
Make sure to use a secure hashing algorithm (not MD5, and at least SHA-2).
save it in the database along with the user id and his IP.
One thing to bear in mind is that some internet connections share IP addresses or will sometimes change the client IP address (e.g. AOL or mobile).
I send the hash to the user as cookie 3. Whenever he wants to access something, I verify if his cookie hash matches the one on the server and also if his IP matches. Of yes, he is valid or else, log him out.
It sounds like a good way of doing it and there are no flaws in itself. I would implement a session timeout mechanism. For example, store the date last used in the DB for a sliding expiration and the query will only query records that have not expired. You could have a background process that runs to clear out old, expired records.
Also, use HTTPS and set the Secure and HttpOnly flags on the cookie. This will prevent them being leaked over HTTP, but I would not go as far as disabling HTTP on your system as there are workarounds for an attacker if it is anyway.
I would not be concerned with the cookie being stolen by another user on the same machine. If the cookie can be stolen in this way then the user's machine is probably compromised anyway and you cannot make your system protect data that is outside of your control. You could however renew the token (random string) on a periodic basis giving the user a rolling cookie. You would have to ensure only one user can be logged in at once under the same account though for this to be effective.
Your method only makes sure that the user possess the random string you generated and is using the same external IP address. There exists several way of abusing this system:
if your website doesn't enforce HTTPS then a user connecting using an unsecured public WiFi network could be at risk: if another user of the WiFi network is listening to all the packets being sent on the network, he could intercept your cookie and use it to access the website as your legitimate user. Your server would be unable to differentiate them because they'll both use the same IP address... (There is a Firefox extension available which enable anyone to intercept such login cookie easily: http://en.wikipedia.org/wiki/Firesheep)
This system is also more generally vulnerable to man in the middle attacks (without HTTPS)
If your cookie is stored on the user computer's hard drive it could be reused by another user.
So to answer your question, your system can be deemed as secured provided a few conditions:
you enforce the use of HTTPS on your website (unencrypted HTTP connections should be refused)
your random string is truly random (there exist right and wrong ways of generating random strings in PHP)
your cookie has a short expiry and preferably is set as a session cookie.
You should take a look at the following related question providing details about the proper way of doing what you want to do: How to secure an authentication cookie without SSL
One cannot say this is "bad". But in Web Development, and specifically in its security domain relativity talks. I recommend you to download a CodeIgniter (google it for more info) Session Class (standalone version) and use it. The basic idea is the same as yours, but it is properly more mature since it is developed in such a famous php framework. You can do your DB operations within that class too, since it allows session saving to DB.
I have multiple clients connecting to a Node.js TCP socket server from an app. I would like to know a secure way of managing their session.
Username + password is passed over the socket to the server. The server confirms this is correct.
I believe that I now need to generate a unique token to send back to the client.
Now if the user closes the app, then opens it again, this token can be passed to the server and thus the server will confirm the user is authenticated again.
Potentially though, this token could be used by somebody else to gain access to this persons account. Is there a way to prevent this?
Is there a more secure way (whilst still maintaining the ability for the user to authenticate without logging in again)?
How would you handle connections from other devices using the same login. Do they get a different token or the same token?
Many thanks.
It comes down to your definition of secure enough. What you're doing now, which is essentially session tracking, and it is generally secure enough for a lot of general purpose usages - however there is typically an extra component added in which is a session should only be considered valid for a particular ip. If the users' IP changes, you should make them login again and issue them a new token. That way if some bad guy hijacks their session id it won't do them any good.
Now of course this is only valid if your bad guy can't appear to come from the same IP address as your client. If you are concerned about bad guys who are behind the same NAT as your client, and thus can appear to come from the same IP, then you'll have to bump up your security a bit more and maybe consider a system similar to what SSH uses, but that's a bit more complex.
As for connections from multiple devices, it's up to you - you can either keep track of some single token and just hand back that token when the user logs in from a different IP (while at the same time now allowing both IPs to access the site using that same token), or you can just issue a fresh token every time someone authenticates. Personally I tend to find issuing fresh tokens easier, much less tracking and hassle... but it comes down to your application and how you want to organize things, I could dream up good use cases for both methods.
Also, as for doing the password exchange.. You should at least do some hashing there, ie, server sends client some random_string, client then uses some hash function (such as md5 or sha) to compute hash(random_string + hash(username + password)) and sends it back. The server then verifies that this matches by checking hash(random_string + password_hash) is equal to whatever the user sent it. This makes it so the user's plain text password never has to be stored anywhere - on the server you just store password_hash = hash(username+password) when the password changes.
Maybe something like this:
FIRST LOGIN:
username + pwd (hashed) ---> check user/hashed pwd
receive token <--- send token
NEXT LOGIN:
request login ---> receive request
receive random string <--- send random string
hash string with token as salt ---> compare hashed string
You should allow only one attempt with that random string and if possible check the IP from the original login.
This is not perfect because you could still intercept the token at login, but then you would also have the username and pwd.
This question basically comes down to session hijacking using stolen cookies. So the question is how you can secure the cookie as good as possible.
Use https instead of http and force your users to use https. This way, the cookie is not transmitted as clear text and can not be stolen using eavesdropping.
Set the secure attribute on cookies (see Wikipedia) to bind the cookie to https and avoid it from being transferred via http.
Use some kind of message authentication digest, such as HMAC, to make sure that the cookie has not been tampered.
Optionally you can embed the client's IP address into the cookie and only accept it if it is being sent from the specific IP. Unfortunately this may cause problems with proxy servers or dial-up connections where IP addresses are newly assigned from time to time.
Last but not least allow one token only to be used once at a given point in time. If the user logs on using the same token on a second machine, either disallow the connection or end the first machine's session.
Hope this helps ...
PS: I am very sorry, I skipped the TCP part. Of course most of what I wrote only applies to http, not TCP. Anyway, some things might help anyway, such as #3, #4 and #5.
I'm designing a very secure login mechanism using play framework2. Since Play does not have a notion of sessions and keep things in the cookies (which I like) I was wondering what are the security measures I need to think about. We obviously going to use SSL to communicate the login credentials and also the cookie is going to be encrypted value of some of user's information like their email or userid. Is it possible that someone can sniff that cookie or get a hold of it from another user's cookie and reuse it? how can i make this more secure?
In fact the cookie isn't encrypted. It is signed. This signature comes from the application.secret in your application.conf.
It means that anyone can see the content of the cookie (and eventually try to spoof other sessions or change their login/id/token...)
From Play documentation :
Of course, cookie values are signed with a secret key so the client can’t modify the cookie data (or it will be invalidated).
I am not a security guru, but, if you keep your application secret secret, it seams enough to me.
Discussion about the strength of the signature are welcome !
Well if you want it really secure, you should general communicate via SSL not only for login. Otherwise someone can get the Cookie. The main-problem you have with the cookie-solution or better the play session is that you have no session-timeout. So imagine that I was able to get the cookie, I can use this user account forever. So you need something like a session-timeout. This becomes really tricky if there are more then one request from the same client, because both try to change the same cookie. A workaround is to handle the session timeout via cache, but have in mind that you need a distributed cache solution if you run in a cluster.
You can try to follow changes at https://launchpad.net/permsec the security solution I wrote. This is an open todo I must do.
If there's a risk of eavesdropping the communication and stealing the cookie, you can make things harder for the attacker. For example add IP address of the computer in the signed cookie. If someone else steals it, he'll have to use the same IP address as the victim. It's not impossible but it raises the bar.
Specifically this is regarding when using a client session cookie to identify a session on the server.
Is the best answer to use SSL/HTTPS encryption for the entire web site, and you have the best guarantee that no man in the middle attacks will be able to sniff an existing client session cookie?
And perhaps second best to use some sort of encryption on the session value itself that is stored in your session cookie?
If a malicious user has physical access to a machine, they can still look at the filesystem to retrieve a valid session cookie and use that to hijack a session?
Encrypting the session value will have zero effect. The session cookie is already an arbitrary value, encrypting it will just generate another arbitrary value that can be sniffed.
The only real solution is HTTPS. If you don't want to do SSL on your whole site (maybe you have performance concerns), you might be able to get away with only SSL protecting the sensitive areas. To do that, first make sure your login page is HTTPS. When a user logs in, set a secure cookie (meaning the browser will only transmit it over an SSL link) in addition to the regular session cookie. Then, when a user visits one of your "sensitive" areas, redirect them to HTTPS, and check for the presence of that secure cookie. A real user will have it, a session hijacker will not.
EDIT: This answer was originally written in 2008. It's 2016 now, and there's no reason not to have SSL across your entire site. No more plaintext HTTP!
The SSL only helps with sniffing attacks. If an attacker has access to your machine I will assume they can copy your secure cookie too.
At the very least, make sure old cookies lose their value after a while. Even a successful hijaking attack will be thwarted when the cookie stops working. If the user has a cookie from a session that logged in more than a month ago, make them reenter their password. Make sure that whenever a user clicks on your site's "log out" link, that the old session UUID can never be used again.
I'm not sure if this idea will work but here goes: Add a serial number into your session cookie, maybe a string like this:
SessionUUID, Serial Num, Current Date/Time
Encrypt this string and use it as your session cookie. Regularly change the serial num - maybe when the cookie is 5 minutes old and then reissue the cookie. You could even reissue it on every page view if you wanted to. On the server side, keep a record of the last serial num you've issued for that session. If someone ever sends a cookie with the wrong serial number it means that an attacker may be using a cookie they intercepted earlier so invalidate the session UUID and ask the user to reenter their password and then reissue a new cookie.
Remember that your user may have more than one computer so they may have more than one active session. Don't do something that forces them to log in again every time they switch between computers.
// Collect this information on every request
$aip = $_SERVER['REMOTE_ADDR'];
$bip = $_SERVER['HTTP_X_FORWARDED_FOR'];
$agent = $_SERVER['HTTP_USER_AGENT'];
session_start();
// Do this each time the user successfully logs in.
$_SESSION['ident'] = hash("sha256", $aip . $bip . $agent);
// Do this every time the client makes a request to the server, after authenticating
$ident = hash("sha256", $aip . $bip . $agent);
if ($ident != $_SESSION['ident'])
{
end_session();
header("Location: login.php");
// add some fancy pants GET/POST var headers for login.php, that lets you
// know in the login page to notify the user of why they're being challenged
// for login again, etc.
}
What this does is capture 'contextual' information about the user's session, pieces of information which should not change during the life of a single session. A user isn't going to be at a computer in the US and in China at the same time, right? So if the IP address changes suddenly within the same session that strongly implies a session hijacking attempt, so you secure the session by ending the session and forcing the user to re-authenticate. This thwarts the hack attempt, the attacker is also forced to login instead of gaining access to the session. Notify the user of the attempt (ajax it up a bit), and vola, Slightly annoyed+informed user and their session/information is protected.
We throw in User Agent and X-FORWARDED-FOR to do our best to capture uniqueness of a session for systems behind proxies/networks. You may be able to use more information then that, feel free to be creative.
It's not 100%, but it's pretty damn effective.
There's more you can do to protect sessions, expire them, when a user leaves a website and comes back force them to login again maybe. You can detect a user leaving and coming back by capturing a blank HTTP_REFERER (domain was typed in the URL bar), or check if the value in the HTTP_REFERER equals your domain or not (the user clicked an external/crafted link to get to your site).
Expire sessions, don't let them remain valid indefinitely.
Don't rely on cookies, they can be stolen, it's one of the vectors of attack for session hijacking.
Have you considered reading a book on PHP security? Highly recommended.
I have had much success with the following method for non SSL certified sites.
Dis-allow multiple sessions under the same account, making sure you aren't checking this solely by IP address. Rather check by token generated upon login which is stored with the users session in the database, as well as IP address, HTTP_USER_AGENT and so forth
Using Relation based hyperlinks
Generates a link ( eg. http://example.com/secure.php?token=2349df98sdf98a9asdf8fas98df8 )
The link is appended with a x-BYTE ( preferred size ) random salted MD5 string, upon page redirection the randomly generated token corresponds to a requested page.
Upon reload, several checks are done.
Originating IP Address
HTTP_USER_AGENT
Session Token
you get the point.
Short Life-span session authentication cookie.
as posted above, a cookie containing a secure string, which is one of the direct references to the sessions validity is a good idea. Make it expire every x Minutes, reissuing that token, and re-syncing the session with the new Data. If any mis-matches in the data, either log the user out, or having them re-authenticate their session.
I am in no means an expert on the subject, I'v had a bit of experience in this particular topic, hope some of this helps anyone out there.
There is no way to prevent session hijaking 100%, but with some approach can we reduce the time for an attacker to hijaking the session.
Method to prevent session hijaking:
1 - always use session with ssl certificate;
2 - send session cookie only with httponly set to true(prevent javascript to access session cookie)
2 - use session regenerate id at login and logout(note: do not use session regenerate at each request because if you have consecutive ajax request then you have a chance to create multiple session.)
3 - set a session timeout
4 - store browser user agent in a $_SESSION variable an compare with $_SERVER['HTTP_USER_AGENT'] at each request
5 - set a token cookie ,and set expiration time of that cookie to 0(until the browser is closed).
Regenerate the cookie value for each request.(For ajax request do not regenerate token cookie).
EX:
//set a token cookie if one not exist
if(!isset($_COOKIE['user_token'])){
//generate a random string for cookie value
$cookie_token = bin2hex(mcrypt_create_iv('16' , MCRYPT_DEV_URANDOM));
//set a session variable with that random string
$_SESSION['user_token'] = $cookie_token;
//set cookie with rand value
setcookie('user_token', $cookie_token , 0 , '/' , 'donategame.com' , true , true);
}
//set a sesison variable with request of www.example.com
if(!isset($_SESSION['request'])){
$_SESSION['request'] = -1;
}
//increment $_SESSION['request'] with 1 for each request at www.example.com
$_SESSION['request']++;
//verify if $_SESSION['user_token'] it's equal with $_COOKIE['user_token'] only for $_SESSION['request'] > 0
if($_SESSION['request'] > 0){
// if it's equal then regenerete value of token cookie if not then destroy_session
if($_SESSION['user_token'] === $_COOKIE['user_token']){
$cookie_token = bin2hex(mcrypt_create_iv('16' , MCRYPT_DEV_URANDOM));
$_SESSION['user_token'] = $cookie_token;
setcookie('user_token', $cookie_token , 0 , '/' , 'donategame.com' , true , true);
}else{
//code for session_destroy
}
}
//prevent session hijaking with browser user agent
if(!isset($_SESSION['user_agent'])){
$_SESSION['user_agent'] = $_SERVER['HTTP_USER_AGENT'];
}
if($_SESSION['user_agent'] != $_SERVER['HTTP_USER_AGENT']){
die('session hijaking - user agent');
}
note: do not regenerate token cookie with ajax request
note: the code above is an example.
note: if users logout then the cookie token must be destroyed as well as the session
6 - it's not a good aproach to use user ip for preventing session hijaking because some users ip change with each request. THAT AFFECT VALID USERS
7 - personally I store session data in database , it's up to you what method you adopt
If you find mistake in my approach please correct me. If you have more ways to prevent session hyjaking please tell me.
Try Secure Cookie protocol described in this paper by Liu, Kovacs, Huang, and Gouda:
As stated in document:
A secure
cookie protocol that runs between a client and a server
needs to provide the following four services: authentication, confidentiality, integrity and anti-replay.
As for ease of deployment:
In terms of efficiency, our protocol does not involve any database
lookup or public key cryptography. In terms of deployability, our protocol can be easily deployed on an existing web server, and it does not require any change to
the Internet cookie specication.
In short: it is secure, lightweight, works for me just great.
Ensure you don't use incremting integers for session IDs. Much better to use a GUID, or some other long randomly generated character string.
There are many ways to create protection against session hijack, however all of them are either reducing user satisfaction or are not secure.
IP and/or X-FORWARDED-FOR checks. These work, and are pretty secure... but imagine the pain of users. They come to an office with WiFi, they get new IP address and lose the session. Got to log-in again.
User Agent checks. Same as above, new version of browser is out, and you lose a session. Additionally, these are really easy to "hack". It's trivial for hackers to send fake UA strings.
localStorage token. On log-on generate a token, store it in browser storage and store it to encrypted cookie (encrypted on server-side). This has no side-effects for user (localStorage persists through browser upgrades). It's not as secure - as it's just security through obscurity. Additionally you could add some logic (encryption/decryption) to JS to further obscure it.
Cookie reissuing. This is probably the right way to do it. The trick is to only allow one client to use a cookie at a time. So, active user will have cookie re-issued every hour or less. Old cookie is invalidated if new one is issued. Hacks are still possible, but much harder to do - either hacker or valid user will get access rejected.
AFAIK the session object is not accessible at the client, as it is stored at the web server. However, the session id is stored as a Cookie and it lets the web server track the user's session.
To prevent session hijacking using the session id, you can store a hashed string inside the session object, made using a combination of two attributes, remote addr and remote port, that can be accessed at the web server inside the request object. These attributes tie the user session to the browser where the user logged in.
If the user logs in from another browser or an incognito mode on the same system, the IP addr would remain the same, but the port will be different. Therefore, when the application is accessed, the user would be assigned a different session id by the web server.
Below is the code I have implemented and tested by copying the session id from one session into another. It works quite well. If there is a loophole, let me know how you simulated it.
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpSession session = request.getSession();
String sessionKey = (String) session.getAttribute("sessionkey");
String remoteAddr = request.getRemoteAddr();
int remotePort = request.getRemotePort();
String sha256Hex = DigestUtils.sha256Hex(remoteAddr + remotePort);
if (sessionKey == null || sessionKey.isEmpty()) {
session.setAttribute("sessionkey", sha256Hex);
// save mapping to memory to track which user attempted
Application.userSessionMap.put(sha256Hex, remoteAddr + remotePort);
} else if (!sha256Hex.equals(sessionKey)) {
session.invalidate();
response.getWriter().append(Application.userSessionMap.get(sessionKey));
response.getWriter().append(" attempted to hijack session id ").append(request.getRequestedSessionId());
response.getWriter().append("of user ").append(Application.userSessionMap.get(sha256Hex));
return;
}
response.getWriter().append("Valid Session\n");
}
I used the SHA-2 algorithm to hash the value using the example given at SHA-256 Hashing at baeldung
Looking forward to your comments.
Let us consider that during the login phase the client and server can agree on a secret salt value. Thereafter the server provides a count value with each update and expects the client to respond with the hash of the (secret salt + count). The potential hijacker does not have any way to obtain this secret salt value and thus cannot generate the next hash.
To reduce the risk you can also associate the originating IP with the session. That way an attacker has to be within the same private network to be able to use the session.
Checking referer headers can also be an option but those are more easily spoofed.
Use SSL only and instead of encrypting the HTTP_USER_AGENT in the session id and verifying it on every request, just store the HTTP_USER_AGENT string in your session db as well.
Now you only have a simple server based string compare with the ENV'HTTP_USER_AGENT'.
Or you can add a certain variation in your string compare to be more robust against browser version updates.
And you could reject certain HTTP_USER_AGENT id's. (empty ones i.e.)
Does not resolve the problem completley, but it adds at least a bit more complexity.
Another method could be using more sophisticated browser fingerprinting techniques and combine theyse values with the HTTP_USER_AGENT and send these values from time to time in a separate header values. But than you should encrypt the data in the session id itself.
But that makes it far more complex and raises the CPU usage for decryption on every request.
If ISP hijack the certificate-verification, ISP will possibly initiate a Man-in-the-middle attack. Especially with a compromised certificate authorities.
So I believe you can not prevent session hijack from ISP. Especially when legal forces come with a fake certificate got from CA under law enforce.
You will need something outside the network to protect your session, for example one time pad. This is why one time pad so sensitive and can only be sold by few companies.
Be careful, one time pad may be exploited. Choose your one time pad with profession.
Protect by:
$ip=$_SERVER['REMOTE_ADDER'];
$_SESSEION['ip']=$ip;