Effective way to protect session hijacking in php - php

I read on how to protect a session in php, there are a few, but they are not so effective like adding to a session the useragent,ip and port and encrypting them both.
What is a good way to prevent session hijacking?
I thought to take the following steps:
Change the PHPSESSID key altogether to something generic like id
Generate token per page and put it on the page and then validate it as well as teh session. That would reduce my reliance on session alone for validation.
I would add a short session expiration.
Add more variables to the session id and encrypt it, so it would be longer and harder to crack. Perhaps I would use RSA encryption.
Put a logout button, so that the user will be able to terminate his session.
Use javascript to count the time, over 5 mins will alert the user to continue his session.
Save session in cookies only.
The difficulties that I heard are: When you use token per page, you need to disable the back button? why is that?
A few other things are also unclear? Is saving session in the database more secure? why?
How more secure is to use SSL? How about regenerating session id very quickly, would it help?
What system would prevent brute-forcing the encryption key (would identifying the ip of the user who tries to flood the server with massive attempts to guess the session id would help?)?
How does session regeneration works, is the old session key destroyed automatically, what if the hacker obtains an old session key would it still work? Please, it is important for me to understand session security, because I am learning how to be a penetration tester?
UPDATE
I thought to do this:
Symmetric encryption on the session id with key A
Symmetric encryption on a randomly generated token that will be in the post field with key
The randomly generated token will be appended to the session id too and then encrypted.
On Request, I should get those variables:
$_SESSION['PHPSESSID'] (has the randomly generated token encrypted in it)
$_POST['RandomlyGeneratedToken']
Decrypt session id with key A and decrypt randomly token with key B.
Do 2 checks:
-Check the token if it is the same as the token on the first request sent.
-Check if the token exists in the sessionid.
Possibility for the hacker:
-Bruteforce the session id.
My session id is long enough it would take him time. I could employ a system that detects massive flow of requests from the same ip with different session id and slow him down with the sleep function.
-Eavesdrop the traffic and get the session id from the user and also the token and try to submit those.
hmm... I will have to regenerate the session id with every request and expire the session quickly on certain pages..may be 1 minute..
But how fast can he eavesdrop?

"Change the PHPSESSID key altogether to something generic like id"
This is security through obfuscation and a weak on at that. The user only needs to view their cookies and put together which is being used for the session id to bypass this
"Generate token per page and put it on the page and then validate it as well as teh session."
this is an interesting idea. but what if the user has multiple pages open? can you support multiple tokens? when do the tokens expire?
"I would add a short session expiration."
Good idea but this might effect users who stay on a page for a long time and then hit refresh only to find that they are logged out too soon
"Add more variables to the session id and encrypt it, so it would be longer and harder to crack. Perhaps I would use RSA encryption."
why use RSA encryption? why not hash it with something one-way like SHA? don't forget to add salts or intialization vectors
"Put a logout button, so that the user will be able to terminate his session."
who ever hits the logout button? ;-)
"Use javascript to count the time, over 5 mins will alert the user to continue his session."
YES
"Save session in cookies only."
dont do this, save the data server side always. cookies can be manipulated as they are stored client side
as for your other comments: you can store your session variables in a database and this allows you to check for other things like ip address and the like (though you can check ip etc with custom session handling functions: http://php.net/manual/en/session.customhandler.php). However, if you use a database and you regenerate your session ID too frequently (e.g. with every page load) you'll find that if your user hits the refresh button rapidly the id will regenerate more quickly than your server can update it in the database and the session will be lost.
"How does session regeneration works, is the old session key destroyed automatically"
yes unless you write custom code then it depends on your custom code
I hope my answers were somewhat useful, but i recommend following the guidelines for OWASP for session management so that you follow best practices:
https://www.owasp.org/index.php/Session_Management_Cheat_Sheet
EDIT
im not sure what do you mean by token? do you mean token as in session id? What value would that provide?
Is your token a session variable? that doesn't make sense as it's value is stored server side the key to which is the phpsessid whose abuse you are trying to prevent.
Also- never count on a hacker's ability not to understand your logic. If they want to understand it they will.
lastly, why do you need so much security? there is such a thing as good-enough security (if you follow certain standards). you likely don't need to protect against foreign government hackers else you'd probably outsource this project. follow best practices outlined in easily googled tutorials or guidelines such as the OWASP one i provided above. It'll be sufficient :-)
edit
"Also, you say the optimal storage is database? what about the last method that I described against brute forcing"
database session storage isn't necessarily optimal. you use it when you need to such as when you load balance multiple web servers that need to share session data.
two ways to hinder brute force attacks are to 1) have a really long session id, and 2) regenerate it frequently

Related

Why not use a long life session ID for auto-login instead of a persistent cookie with a token?

On the PHP website it is stated that "Developers must not use long life session IDs for auto-login because it increases the risk of stolen sessions.". Instead it is recommended to use a secure one time hash key as an auto-login key using setcookie() - which then becomes a persistent cookie.
But I cannot understand how that is safer?
The persistent cookie with the token can also be stolen and stealing sessions IDs is very difficult if you make sure your website never works with HTTP only, but only uses HTTPS - like with HSTS, and also prevent JavaScript access with httponly.
What am I missing here?
I have a guess what they mean. I believe when they say "secure one time hash key" they really mean some kind of HOTP mechanism. Then I have some more guesses what they want to achieve with it. They want to be able to terminate the sessions when they time out, but they also want the client to be able to automatically recreate the session by simply calling its internal HOTP mechanism and generating the next token and finally passing it to the server.
That's a huge amount of guessing here, but honestly, saying "secure one time hash key" does not mean a thing and such an expression is really vague.
I think I have found the correct answer myself.
A session cookie is used to keep state between requests. It can be used to track a login during an open browser session, but the session should be ended when the user logs out or when the browser is closed. A "Remember Me" token in a persistent cookie is not used to keep state between requests, it's only used to "skip" the login procedure and give access to specific pages that other wise requires a login. When you use $_SESSION you're dealing with the session cookie and nothing but the session ID is stored in the browser or client and all the values you put into the $_SESSION array gets stored on the server in a file (by default) that contains the values in pure text.
The persistent cookie for "Remember Me" is not used for anything like that, it only keeps a hash token in the browser in order for the user to be recognized and avoid having to log in every time he visits the website.
In other words, the session cookie and the persistent "Remember Me" cookie are two different solutions to two different problems.
You can "keep state" with the "Remember Me" cookie, but that is not what it is used for and it doesn't provide you with a session. You can use the session cookie to implement a "Remember Me" functionality, but that is not what it is used for, it is used to store state variables on the server and to keep state in a session.
However, if you implement the proper security features for cookies, i.e. only serve on HTTPS and use secure and httponly, then they are both equally secure with regard to the risk of stealing the cookie or the session ID.

PHP - encrypt other site's username and password

I am programming a PHP site that allows users to register, and both registered and unregistered users can enter their respective usernames and passwords (for example smith8h4ft - j9hsbnuio) for school site.
Then, my PHP script sends some $_POST variables, downloads and parses the marks page, making an array called:
marksDB = Array("subject" => Array("A", "B", "A", "C"), ...), and writes it reformatted.
My question is:
How should I keep the username and passwords safe?
For unregistered users, I currently forget username and password and put the marksDB into $_SESSION. When user is inactive for e.g. 30 minutes, marksDB is deleted. How safe are these data in $_SESSION ? And how about users that log in, view page once, and never view it again, so the script doesn't delete the marksDB from session? Is the session deleted automatically (gc.maxlifetime)?
And what about registered users? I want to have everything safe, but I don't want to annoy user with password prompts every 30 minutes of inactivity. Is it safe to encrypt credentials like described here, but without the third user-set password? Or have I to ask the user for his password every time?
EDIT:
Thanks for quick replies,
#Justin ᚅᚔᚈᚄᚒᚔ : I doubt they have some API, but I can ask them, just for case
#Abid Hussain: Thanks for very useful links. (Thanks both for answers too).
I will throw users' credentials away and have only parsed markDB, which I will probably throw away too (after logout or inactivity) - it is cheap to retrieve marks again when needed.
If the school site doesn't expose an API for this (for example, using OAuth like the StackExchange sites do), then your options are limited.
Generally speaking, it is never a good idea to keep a user's plaintext credentials for longer than is absolutely necessary. There are security implications for any possible way you can imagine to try to do it (session hijacking, stolen keys, decryption, etc).
A better approach might be to make the marks download process strictly user-initiated. Give them a button that says "retrieve my marks", and go through the authentication process there, download the marks, and throw away their credentials. Each time they "sync", they should have to authenticate. Unless the marks change on a frequent periodic basis, there should be no reason you can't download all the information you need at once and then cache it securely on the server for later usage.
session files will be deleted by the garbage collector after a certain time, but a good rule of thumb for storing in _SESSION is only store data that you would output on the screen, i.e. the password is probably not something you want to store in the session. Session files can be read from the server and it's possible for some nefarious user to hijack the session and see things they are not supposed to see or even somehow see a var_dump($_SESSION).
If you want to allow registered users longer sessions you can have periodic page refreshes with JS (not necessarily refreshing the page .. just an asynchronous request will do) or perhaps even increase the session time with ini_set if allowed. It's not necessarily safer to ask for passwords repeatedly .. it depends on how vulnerable the password is when you are asking.
Another solution is to have the infamous "Remember Me" cookie keep the users logged in.
Passwords are not for decrypting. Encrypt for secrecy. Hash for authentication.
Everything in the session is server side, so it's not accessible by others. However, sessions can be 'hijacked' as explained here.
You could increase the length of the session in your PHP.ini or use periodic AJAX calls on the background to keep the session alive. The sessions are deleted when they are expired by the server.
Encrypting a password so it can be decrypted is usually frowned upon unless there is no alternative. With encrypting, not only you, but also everyone else with access to your database and/or source code can retrieve the passwords.
See URL
http://phpsec.org/projects/guide/4.html
http://www.sitepoint.com/blogs/2004/03/03/notes-on-php-session-security/
http://talks.php.net/show/phpworks2004-php-session-security
http://segfaultlabs.com/files/pdf/php-session-security.pdf
safest way to create sessions in php
Also Read it
Sessions are significantly safer than, say, cookies. But it is still possible to steal a session and thus the hacker will have total access to whatever is in that session. Some ways to avoid this are IP Checking (which works pretty well, but is very low fi and thus not reliable on its own), and using a nonce. Typically with a nonce, you have a per-page "token" so that each page checks that the last page's nonce matches what it has stored.
In either security check, there is a loss of usability. If you do IP checking and the user is behind a intranet firewall (or any other situation that causes this) which doesn't hold a steady IP for that user, they will have to re-authenticate every time they lose their IP. With a nonce, you get the always fun "Clicking back will cause this page to break" situation.
But with a cookie, a hacker can steal the session simply by using fairly simple XSS techniques. If you store the user's session ID as a cookie, they are vulnerable to this as well. So even though the session is only penetrable to someone who can do a server-level hack (which requires much more sophisticated methods and usually some amount of privilege, if your server is secure), you are still going to need some extra level of verification upon each script request. You should not use cookies and AJAX together, as this makes it a tad easier to totally go to town if that cookie is stolen, as your ajax requests may not get the security checks on each request. For example, if the page uses a nonce, but the page is never reloaded, the script may only be checking for that match. And if the cookie is holding the authentication method, I can now go to town doing my evilness using the stolen cookie and the AJAX hole.
The session file is server side so it should be invisible to clients. But they still can trick your program into using another session if they know the session ID.
For the registered users you can store the password in a DB or a file after you have encrypted it with a key that only you know (maybe a new one generated randomly and stored for each user)

Is restoring a session with cookies the right way?

Correct me if I'm wrong please:
Sessions will last a finite amount of time (refreshed from the server every 15 or so minutes until the browser is closed) - more secure/short term
Cookies on the other hand can last until the browser closes or to some specific time in the future - least secure/long term
Given this, how do allow a user to close his/her computer, come back a few days later and open a site and still be logged in using cookies and still somehow being secure?
How does someone like, amazon for instance do this?
EDIT:
To be more clear, here is an example:
if (!isset($_SESSION['id']))
{
$_SESSION['id'] = $_COOKIE['id'];
$_SESSION['email'] = $_COOKIE['email'];
}
this is obviously bad, what is a better way?
First of all, "session" is more of a concept rather than a concrete implementation.
For PHP I believe the default way that session data is stored on the file system and it is associated with a session id that is usually stored in a cookie (although it can also be sent via query string parameter:http://stackoverflow.com/a/455099/23822).
It's also possible to store session in a database. Doing so allows you full control over how session data is stored and when it expires so you can have sessions that last as long as you want them to. You just need to make sure the session cookie also shares the same expiration time as the data in the database.
As to your question of in a comment about "What's stopping someone from grabbing the cookie data and falsifying a login using the token?" Theoretically that can happen, but the session ID stored in the cookie should be random so it would be highly unlikely that it would be guessed (an attacker would have a much easier time guessing the user's password). In fact the same thing is already possible with any kind of session.
Sessions expire mostly because keeping them open on the server is inefficient. You need a cookie (or some other mechanism, but cookies are usual) to associate them with a browser anyway.
Amazon handles security by having three levels of "being logged in".
Level 1: Basic functionality just works.
Level 2: You must reenter your password to access some things (e.g. order history)
Level 3: You must reenter payment information to access some things (e.g. adding a new delivery address)
For the cookies I use the method described here:
http://fishbowl.pastiche.org/2004/01/19/persistent_login_cookie_best_practice/
and here: http://jaspan.com/improved_persistent_login_cookie_best_practice
You store a session-based security token inside the user's cookie data, and store that same token in the user's db table. At session creation, you check if this username/token pair can login to your website according to the previously stored data, and then invalidate the token.

$_session security

Currently I autheticatic user sessions by matching a key in the session to the same key in a MySQl database. I regenerate the session with a random number that is MD5 protected on every page load. I am aware that sessions are not inherently secure and I'm looking for further security options that can be attached to this method in a speedy manner.
Any Ideas?
Since the session data is stored on the server side and the session ID is used to associate a client’s request with a certain session, it’s the session ID that needs to be protected. And the only viable measure to protect that session ID is to encrypt the connection between the client and server using TLS/SSL.
So you can use sessions as long as the data transfer between client and use is secured. Additionally, you can fix the PHP session to the TLS/SSL session so that the PHP session is only usable within that specific TLS/SSL session.
You're already jumping through hoops which do nothing to enhance the security, and potentially compromise the functionality of your site.
I autheticatic [sic] user sessions by matching a key in the session to the same key in a MySQl database
Even leaving aside the spelling mistakes, this is nonsense. Do you mean you authenticate requests by this method? If so, it's still not helping your security. You've already authenticated the request by de-referencing the session. Whether the request is authorized is completely different - if you need to authenticate the user then you should flag this in the session data.
It sounds like you're trying to prevent a CSRF, but getting this all mixed up with whether you're authenticating a user, a session or a request.
I regenerate the session...on every page load
Again, this is semantic nonsense. You can't "regenerate the session". Do you mean you create a new sessionId? If so then all you are achieving is creating errors when users try to open a second window or use the back button. It provides very little CSRF protection.
is MD5 protected
Just using random cryptographic functions doesn't make your application secure. It doesn't matter what the mapping between the real data and a surrogate identifier is, on its own it provides no protection against MITM.
Either you've done a very bad job describing your current security measures, or you've written lots of code which serves no useful purpose.
Go and read a lot of Stefan Esser's and/or Chriss Schiflet's stuff.

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