I have a php site that lets registered users login (with a valid passord) and sets up a session based on their UserID. However I'm pretty sure thisis being hijacked and I've found "new" files on my server I didn't put there. My site cleans all user input for SQL injections and XSS but this keeps happening. Has anyone got any ideas on how to solve this?
A session cookie hijacking should NOT allow an attacker to create new files on your server. All it could do is given access to an authenticated user's session. It'd be up to your code, and/or the server's configuration that would allow uploading arbitrary files to the site's webroot.
To check for remote compromise hits, get the file creation times of the suspicious files (searches.php, 7.php.jpg) etc..., then comb through your server's logs to see what was happening around that time. If you're logging the session ID along with the rest of the hit, you could trivially see if the session was hijacked, as it would be used from two or more different IPs during the session's lifetime. It'd be especially obviously if the original user logged in from one ISP, then suddenly appeared to jump to a completely different ISP.
And of course, how are your sessions implemented? Cookies? PHP trans_sid (passing the session in hidden form fields and query strings)? trans_sid is especially vulnerable to hijacking, as the mere act of sharing a link to something your site also transmits the session ID, and any external links on your site will have the session ID show up in the HTTP referer.
The solution that PHP experts have come up with is to use unique keys/tokens with each submission of the forms, have a look at the idea here at net-tutes.
Don't forget have a look at the PHP Security Guide.. It covers topics including XSS, Form Spoofing, SQL Injection, session hijacking, session fixation and more.
Remember, always use proper data types in your queries, for example use the int or intval function before numbers and mysql_real_escape_string function for the string values. Example:
$my_num = (int) $_POST['some_number'];
$my_string = mysql_real_escape_string($_POST['some_string']);
You may also use the prepend statements for your queries.
Popular Project To Secure PHP Applications:
XSS Filtering Functions by Christian Stocker (Also used by Kohana framework)
HTML Purifier (Also used by Kohana framework)
OSAP PHP Security Project
I'll have ago and say that your 'cookie' is easy to guess.
Some sites, when the user logs, just create a cookie and the authentication code just checks for the EXISTENCE of a cookie.
Now, if I register and login to your site and then cut your cookie open and notice that you just store my user id then I can manipulate the value to some other user id and voila!
You get the idea.
Related
I have a web application that I want to improve in its security flaws, I read a lot of articles about it but some questions are still unanswered. I appreciate your help.
First of all I have a login screen. After the user enters his credentials, they are checked against the database ( they are properly hashed ;)), and if it succeeds the server creates a session variable
//Jhon id = 1
$_SESSION["userID"]= '1';
At the beginning of every php file (e.g. dashboard.php) I have the following code:
session_start();
if(isset($_SESSION['userID'])) {
if($_SESSION["userID"]==""){header("location:login.php");}
}else{
header("location:login.php");
}
?>
<html ...
For improve maintenance i want to include this code in an external php file like
include('inc/restricted.php');
?>
<html ...
My two main questions are:
1) If an intruder handles to corrupt or to deny access to restricted.php, would the remain of dashboard.php show up? Is it possible to do something like that? If it is, how could I fix it the way I can include the security code as an external file?
2) As you see the value of my session variables are simple (integers numbers), should I change them to hashed values? I thought the php session was stored on server side but i read about some php session variables stored on cookies and now im worried about the chance of create a cookie with a random number and granted access.
It's possible if the code in this file is insecure. Since we can't see it it's impossible to say how it could be compromised. But generally speaking, the web-facing request should have no ability to control your php code unless you have a severely insecure setup.
The values don't matter. Data stored in $_SESSION is never stored on the client, only on the server. This is controlled in php by the session.handler interface (by default it's stored as a plain-text file on your server in session.save_path).
The things that tend to make sessions insecure are almost always the result of poorly written code or a poorly configured server.
Some things you can do to improve the security of your sessions are outlined below:
Always use session_regenerate_id(true) when logging the user in (this prevents session fixation attacks).
Always delete the session cookie on the client when you log the user out (see the first example in http://php.net/session-destroy). This prevents session take-over attacks when the user is logged in from a public computer, for example, as the session may not always be deleted instantly on the server side and the cookie allows the client to re-trigger the session TTL on the server.
Only transmit session cookies over a secure connection (See session.cookie_secure
To prevent some XSS and CSRF vectors consider using session.cookie_httponly and session.cookie_samesite to prevent malicious JS from opening up these kinds of attacks.
Always use CSRF tokens along with all modifying requests to protect the user from compromising their access strictly via sessions. This is an added layer of security.
Just remember that this is not an unabridged list. Security is built in layers and requires a lot of forethought in use cases and objectives.
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 created a login page and registration page and now I want to use that to password protect pages and have pages which show information specific to that user.
Would storing the user ID of the user logged in in a Session variable be a safe and correct way of doing this?
How easy would it be for a user to change the session variable to a different ID and access another user's information, and not having to type the users login details in?
EDIT: Would posting the user ID from each page to the next be more secure?
Here's an article on session security
If you encrypt user name in such a way that only your PHP scripts can decrypt it then you should be safe I guess.
That's what session meant to be
For session security, you can check http://phpsec.org/projects/guide/4.html
While I'm not aware of any way in which a user could manipulate the information in $_SESSION unless your code (or code on your server) allows them to, so don't do anything crazy like...
foreach($_POST as $key=>$value) { // DON'T DO THIS
$_SESSION[$key] = $value; // DON'T DO THIS!
} // WHY ARE YOU DOING THIS!?
You shouldn't do anything like this, where you're just putting whatever data the user gives you in your $_SESSION variables. Like the database, writing to the session should be thought of as a form of output, and you should sanitize what you put in it (and where it's put) accordingly.
So, unless you're doing something crazy like this (you might be; it can be much more subtle), I don't think you have to worry about a user changing the session variable. You might have to worry about the threats of a shared hosting environment where someone who's probably not quite an end user is manipulating the session info.
What's not so safe is the session identifier, as there are a few straightforward ways to hijack a session in PHP.
I recommend checking out that book I've been linking to, Essential PHP Secutiry. It's a very small and straightforward (but thorough) explanation of several basic PHP security concepts, many of which can be generalized and should be kept in mind when doing any web dev work.
I'll talk about the default session behavior, here: sessions are based on a cookie "PHPSESSID" which is set to an MD5 checksum (32 alphanumeric characters). PHP accepts this cookie from the browser, and uses it to load server-side session data. The client has no direct way to modify data in the session, but does get to specify their own session ID.
You can add additional layers of security (SSL, checking the client IP, etc.), but by default if I know your cookie I can effectively login as you. As far as how "easy" that is, well, that depends on lots of other layers of security: is someone sniffing your traffic, do you have malware installed, etc.
Tools like Suhosin attempt to improve session security.
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 ;-)
I am creating a login system for a web application using PHP. My question is, is it safe to only store the user login information in the current session? For example, if a user named John logs in successfully to my site, can I just store $_SESSION['Username'] = 'John' and $_SESSION['LoggedIn'] = 1 then check that $_SESSION['LoggedIn'] is equal to 1 on each page to verify the user is actually logged in? Or is there a better way to do this? I am not aware of any problems this may cause off the top of my head, but I wanted to make sure I wasn't leaving a big hole in my site that would cause problems down the road.
Also, I am storing an md5 hash of the user's password + salt in the database, not their actual string password so that is one less thing to worry about.
Let me know if you need any more information or if this is not clear. Thanks!
That's a perfectly reasonable approach. Your visitors will never be able to edit the session data on your server (unless the server itself is insecure, in which case anything's fair game), so a LoggedIn=1 value in the session is perfectly safe.
However, do keep in mind the risk that one visitor hijacks the session of another (by stealing the session key). One way to help protect against this is to also store the visitor's IP address (from $_SERVER['REMOTE_ADDR']) in the session and then in later requests confirm that it hasn't changed.
There are a number of risks to consider:
Session hijacking: this is where someone steals the user's cookie and pretends to be them. Some will suggest IP filtering to counter this but that can have awkward side effects. People use Websites from mobile devices or on laptops that are used at work, home and at wifi hotspots and there are other cases where IP addresses can change. So my advice is only do this for highly sensitive Websites (eg online banking);
Your Site is Compromised: in this case the user will have access to your database anyway so there is no extra risk with storing authentication information in the session. They can just as easily change who they are by issuing UPDATE statements to your database;
A Co-Hosted Site is Compromised: if you use shared hosting, a completely unrelated site could put you at risk (with or without this scheme) because a bunch of sites are all running on the same Apache instance and can thus access each other's files (although it can be hard to figure out what site they belong to). So if a site you've never heard of is hacked it can impact your site;
A Co-Hosted Site is Malicious: similar to (3) except the threat is internal but is otherwise similar.
So I'd say it's fine (subject to (2)) but just be aware of the risks. Follow, at a minimum, these best practices:
Never store unencrypted passwords;
Use a strong hashing algorithm (SHA1 preferred or MD5 at least);
Make sure authentication cookies expire at some point. How long depends on your site. It could be a week or two or an hour or two of inactivity or both.
Consider SHA1 or an even stronger hash instead of MD5. You're salting it, though, that's good.
Back to your question: yes, that's fine. However, implement measures to make sure sessions are not hijacked. Wikipedia actually has a fairly good article on it.
In most of the systems I've written, I've included logic to verify the remote IP hasn't changed. You can store that in the session, too, since the session vars don't get passed to the user (only the session ID). If you really want to get creative, you can add other checks -- user-agent, and what not.
You also have to account for session attacks. Check referrers. If you have a disastrous operation, let's call it a POST to DeleteMyAccount, I can write a form submission plus javascript to hit DeleteMyAccount in a forum post on an unrelated site, counting on that session to be present in the user's information.
Sounds OK; you may want to think about setting an expiry time (so if someone walks away and leaves the browser open they're not in too much danger).
On the whole, you are definitely on the right track. I would recommend you use IDs for your users in the session rather than the username as IDs are a better unique reference inside your code.
Also, md5 is not considered strong enough for password hashing anymore: it's is too fast to hash and you don't want that in a check that an attacker will need to run over and over again (whilst a real user only needs to do it once). I wish I could find the reference, but leading edge wisdom is to do lots of rounds of a leading edge hashing algorithm, like sha512.
You can use COOKIE instead of SESSION variable. you may set COOKIE by following
setcookie('ID', $variable, time()+8*60*60);
You have to be aware about SQL Injection. When you Insert or Update your database where user textbox relates please be aware about SQL Injection. Insert / Update your values by htmlentities() function.