I really have a lot of questions about this specific area. But basically I just want to know how to create the most efficient and secure php session communication method. I have read so many websites talking about this and they don't seem to agree or relate to my current situation.
My problem is that I don't know how to create login, sessions, cookies, registration etc. properly to match a high security level. This is my idea so far.
1. PHP SESSIONS
I will start a session after the login has been made. I know that there are different ways for me to handle these but at the moment I have created a session variable like so $_SESSION['user'] which lets me store the users e-mail address during the session. Then I have a problem when the session is ended with the server. That leads me to the next property.
2. COOKIES
With cookies I would be able to store the e-mail address and the hash encoded password and then be able to recreate a session based on these login information.
<?
session_start();
require_once('config.php'); //retrieved from the servers include folder specified on the apache server.
// if session is closed that means that there wouldn't be stored a session variable called 'user' anymore.
if ($_SESSION['user'] == '') {
// if the cookie hasn't been set..
if ($_COOKIE['user'] == '') {
// ... close the session and return to the login page
session_destroy();
header('Location: login.php?err=4'); // err=4 means session ended
} else {
// We don't know wether the user has logged in using e-mail or username, so that's why we connect using either email or username.
$sql = 'SELECT * FROM login WHERE (email = :user and password = :psw) or (username = :user and password = :pass)';
$statement = $conn->prepare($sql);
$statement->bindParam(':user', $_COOKIE['user'], PDO::PARAM_STR);
$statement->bindParam(':psw', $_COOKIE['psw'], PDO::PARAM_STR);
if ($statement->execute() && $row = $statement->fetch()) {
$_SESSION['user'] = $_COOKIE['user'];
} else {
// Failed to retrieve data somehow.
}
}
}
?>
But then I have read that the session_id() also is a cookie stored value, which will be the same every time I recreate the session. So I actually don't have to match the values to the server again, cause I can simply start session again and continue from where I left.. But I see this as a security break, since that if the session_id() has been retrieved by somebody else, they will be able to connect using same session_id() etc.
3. I also need to use the values from other domains
I know that it is possible to use the same login-details from another website e.g. Facebook, Google etc. I want to be able to reuse the same login for all the domains I am working with, but how do I secure that only mine (registered) domains can have access to the login information, and not other sites?
4. Is there another secure way?
This is actually my question. I am not sure that what I have done or planned is highly secure, and I definitely don't think that my newbie experience is good enough to create a login-secure database connection. So I would like to know if anybody could link me to the official page of the right way to store and use login details in PHP in the most efficient and secure manner.
PHP sessions are the way-to-go when you want to handle logins in PHP. To do this in a save manner you should make sure that your session data is stored on your server and the client only has a session_id in a cookie.
Every time you have a security-level change (login, logout etc), you should regenerate the session id to ensure more safety (old stolen session id's will become unusable). You should also make the session cookie http_only, which will make it impossible to steal the cookie using JavaScript.
From a security perspective I would recommend you to never use cookies to store sensitive information. Information stored in cookies are not save, they are stored on the clients computer and can be altered or stolen.
Google and Facebook make logging in to all kinds of websites possible using openAuth(2). I'm not sure whether that would be usable for you, but cookies will only be accessible by at most one domain.
I would recommend using PHP sessions, they are secure if you handle them correctly. If you are not really sure how to do that you could take a look at some good PHP frameworks. I know from experience that the Laravel framework has a good login-handler.
Sessions already use cookies to keep the session. If you configure it properly, you can keep sessions open indefinitely, if that's what you want to do (unless the user deletes cookies, but then your cookie-based solution won't help either). Anything you build yourself with cookies will probably be less secure than that, so I wouldn't bother with it. Properly configure the session settings of course.
Reusing information across domains is a complex field. If they are all backed by the same database, just let the user log in on any site. You will need to manage separate sessions (read: user will need to log into each site separately, but can use the same user/password) or built some pretty complex cross-domain session sharing (hint: you probably don't want to). If you want to go for a more complex solution (e.g. because your domains don't share a central database), google "single-sign on" and prepare for hours, days and weeks of reading.
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I started learning PHP about a month and a half ago, and I started doing so by trying to create my own very simple CMS in order to learn how to construct basic CRUD scripts that would interact with a mysql database and so on.
I am currently building my login form for the private admin section of my CMS and by doing so I wanted to learn about basic security in PHP.
I wanted to do some basic research on user authentication but the explanations I came across often included information on best security practices which I did not fully understand.
So, I looked for more information on the small bits I did not understand which included other bits I was not acquainted with and I got dragged into absorbing a lot of information on security topics like security through obscurity, one way password hashing, security through proper php configuration setup, defending against sql injection, php injection, session hijacking and so on.
I am having trouble implementing all this since I can't really make sense of it all.
So the first question is about storing the user session in the database.
What I know at this moment is that if I am using a shared host, the server might not be configured properly and the folder where the server is storing the session might be accessed by other people.
Is this the only reason why I would like to store the session in the database?
Second, how does storing the session in the db solve the access problem?
To elaborate on my confusion, it is clear to me that once the session is stored in the database it safe from the people on the shared host, but how do I tell php -"Hey, I stored my user session in the database, exclude it from wherever you are instructed to store it by default"?
In other words, just because I stored the session in the database does not mean that the server excluded it from the place where it stores the sessions by default. Is this correct, and if it is how do I take control over that?
Third, how do I actually store the session in the database? I assume the following process:
session_start();
//Assume a user has successfully logged in
//For better security regenerate the session on login
$session = session_regenerate_id();
$data[]= $session;
$query = $db_connection->prepare("INSERT INTO `sessions`(`session`) VALUES (?)");
$query->execute($data);
Is this what it means to store the session in the database in its most basic form?
Moving on to the next question.
Lets assume that I have resolved the issue above. Now how do I authenticate if a user is logged in?
Normally I would do something like this:
if(!isset($_SESSION['user'])) {
redirect_to('login.php');
}
But since the user session is stored in the database, is it available to me directly or do I need to pull it out of the db first in order to use it?
I am aware of the fact that once a session starts there is an encrypted/hashed (don't know exactly which one it is)session cookie in the browser called PHPSESSID.
But since I am storing the session in the database to me it means I am taking manual control of what PHP usually does automatically, which in my head the process chain is generate->store->encrypt/hash->set session cookie.
Is that assumption correct?
And lastly cross site forgery requests.
My understanding is that while a user is logged in, he is tricked somehow to click on a link, etc. that will copy his browser's cookies and now the attacker is in possession of the session cookie and can impersonate the user.
How does a csrf token stored in a hidden field on my forms help in this situation?
If the attacker has hijacked the session of the user checking the token against the session does not help since the attacker has a valid session.
What am I missing?
There are knowledge gaps in my head on how things work, I hope you can somewhat fill these for me.
Is this the only reason why I would like to store the session in the
database?
The database is password protected, the sessions directory isn't. This goes without saying that most servers should secure the /tmp/session path (iirc) and nobody can access it.. but again, you'd have to trust the host quite a bit.
Second, how does storing the session in the db solve the access problem?
See answer #1
In other words, just because I stored the session in the database does not mean that the server excluded it from the place where it stores the sessions by default. Is this correct, and if it is how do I take control over that?
Basically, sessions are identified with a unique IDentifier. The browser is sent a cookie with the ID, and the server reads the cookie ID and references it to a configured location on the server. To set the save path, you can use session_set_save_handler - this will allow you to do whatever you want with the session (on save) - such as save it to a DB. See Example #2.
Now how do I authenticate if a user is logged in?
**There are various ways to determine if a user is logged in. A basic way is to store unique data in a session and relate it to the users table. When the browser sends the session ID, the server can then retrieve the data based on the ID. You can then take this data and cross-reference it with your users table to authenticate the user. Remember, servers are (typically) stateless, meaning navigating between pages, the server doesn't keep track of users between pages. Hence the use of sessions. A very basic example, and I wouldn't use this, is such:
<?php
function isLoggedIn() {
if(!empty($_SESSION['user'])) {
$uuid = $_SESSION['user']['uuid']; // universal unique id
$username = $_SESSION['user']['username']; // username
$last = $_SESSION['user']['last']; // last use of session
if($last > time() - 600) { // active last 10 minutes?
$stmt = $db->prepare("SELECT username FROM users WHERE uuid = :uuid");
$stmt->bindValue(":uuid", $uuid, PDO::PARAM_STR);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if($username == $user['username']) { // user is logged in. uuid on session matches uuid in users table
$_SESSION['user']['last'] = time();
return true;
}
}
}
session_destroy(); // clear everything!
return false;
}
?>
But since the user session is stored in the database, is it available to me directly or do I need to pull it out of the db first in order to use it?
Don't confuse user session with the user object itself. The session is used to tie the actual USER and the APP together. See above answers & example
How does a csrf token stored in a hidden field on my forms help in this situation?
When you have CSRF tokens in your forms, you also have the CSRF token on the server... Meaning when the page with the form is loaded, a CSRF token is generated and stored in a session for the specific user. Remember, users who have session cookies do NOT have data -- just identifiers. The form will also have a hidden field, such as csrf_token. On POST, the server will compare the post token with the session. It will ALSO reset/clear the token so that it cannot ever be posted/used again. These tokens should be unique.. usually something like md5(time()) works well. If the token doesn't match, or is missing, it's possible there's an attack. The best action to take here is to display the form again, with a new CSRF token.
I am trying to understand security when it comes to session cookies in php. I've been reading a lot about it, but I still lack the specifics. I need the basics, someone to show examples.
For example: Do I place session_regenerate_id() before every session cookie? What more shall I think about. I am asking about specifics in code - examples if possible.
Thank you very much.
I am using 4 session cookies after logging in.
SESSION "site_logged_in" = true
SESSION "site_user_nr" = the number of the user to access user_table_nr
SESSION "site_user_id" = the user's id to use when changing data in tables
SESSION "site_user_name" = the name of the user to display on page
When I check if the user has access, I check if all 4 cookies are set, and if site_logged_in is set to true.
Are there better ways? Do I have the completely wrong idea about this? Can users easily be hacked?
In fact you need to have only one session in your website. When you call session_start() session is being created on server and user automatically gets session cookie. Think like session is a some sort of container that placed on the server, you can put whatever you want in that container. However session cookie is just a key to access that container on the server.
It means that you can safely put some data in the $_SESSION and only the user that have cookie with matching session id can read it.
About users being hacked. Yes they can be hacked as long as you don't use HTTPS connection, because cookies and all other data is being transferred in clear text, so if someone intercept users cookie he can access the data stored in the session.
Always use a security token for logging users. This security token could be generated by using crypt(). After logging users in, change the security token periodically until they log out. Also keep the server backup of all the session variables including the security token (in a database). This would also help you to track user login history.
One more personal suggestion: Never use any data from the database as session variables without encrypting it with any of the hashing functions or functions like crypt().
The session information is stored server-side. What you should check is that they're logged in, and that they exists/can log in (in case of deletions/bans).
As you're checking they exist/can log in, you can pull the other information from the database such as name, nr and so on. All you really need is a key called 'logged_in_user' or something that stores the ID of the logged in user. As Alex Amiryan said, the cookie can be copied, so you might also want to store the IP address of the last accessing view in the session, so you can try to ensure security.
I'm using the following code for my user login. Everything works fine but im just wondering the security of using this. I'm using the userid as the sessionid when a user logs in.
What are my security issues with using this?
Can the user change the sessionid to a different number and then be logged in as a different user? (how do i stop this?)
if (!empty($row['member_id']))
{
$_SESSION['id'] = $row['member_id'];
header ("Location: team.php");
exit();
I'm not a security expert by any means.
There was an uproar back in, I want to say, 2010 about session theft. So much so that a group put out a tool called Firesheep that would let you quickly steal other sessions in an open wifi situation. The solution is to protect the entire logged in session with SSL or not be on an open network. Back when SSL was first being used, it proved too slow to be used as a session long security measure, but now computing is fast enough.
TLDR: If you don't SSL, someone can steal your session. Facebook and Google both had the same problem.
For clarification, they can't "steal" sessions so much as they can find out the SESSIONID being passed around in the POST request in order to keep you logged in and then modify their cookies to send that around as you instead. The Firesheep tool could snag Facebook logins in seconds. By modifying the cookie with someone else's SESSIONID, the tool was able to pretend to be the original user, allowing full access to the areas of the account that were unlocked upon login. See also: this.
Another good solution to help things is to reprompt the user during any account sensitive activity regardless of their session. For instance, if they try to change their password or change other account info, make sure to ask for their current password again.
The contents of the $_SESSION server-side are only safe as long as there is no way to submit user data in any way that would eventually end up in the session variable. If someone stole a SESSIONID and then entered data on some form (or if you blindly use the name of the form element as the index into the $_SESSION array) they could get stuff in there. The key is to never ever ever ever ever ever ever ever...EVER....trust what the client side has sent as valid or trustworthy. Paranoia is your friend.
I think you are mixing up the Session ID (SID) with your own login id, you save in $_SESSION['id'].
Your code is fine. Session data is saved on the server and cannot be manipulated by the client directly. So he cannot change the value of $_SESSION['id'] (btw: I suggest to use a more unique key name like 'login_id').
Talking about the real Session ID (SID). The SID is a random string generated by PHP automatically and saved as a cookie on the client’s machine. The client can actually manipulate his SID and so potentially takeover a different session. This is called Session Hijacking and it’s a general problem of using sessions, no special problem of your code. Have a look here for further information: PHP Session Fixation / Hijacking
When a user logged in website, I only save user_id in SESSION to check it later whether user logged in or not.
if(!empty($_SESSION['user_id'])){
....
Is this enough for security?
This would depend entirely on how that variable makes it to the session and how well you're managing session.
One case to always consider when dealing with web-site security and user credentials is the possibility of a user logging on to your site in a public environment and then walking away. How long will he stay logged in? How accessible is the sensitive information when already logged in?
If you have a relatively short session timeout and are making sure that you are managing what makes it into $_SESSION['user_id'] then this is a reasonable approach. It may be better to actually check the VALUE of what is in $_SESSION['user_id'] but that won't be a huge improvement over what you currently have.
The main thing that I would recommend taking into account would be to require login credentials once more if a user ever wants to alter their account's details / access overly sensitive data (you wouldn't want a stranger changing your users' login names would you?). While this may be a bit of a hassle for regular users, it definitely adds a good measure of security to your application.
The value could only be changed if someone has access to the session files.
So usually yes.
But I would rather use isset():
function loggedIn()
{
if (isset($_SESSION['user_id']) && is_numeric($_SESSION['user_id']))
return true;
return false;
}
Because if the user id is 0, empty() will also return true!
If you are in a shared hosting environment, somebody else on the same server could potentially create a valid session and gain access.
Or, someone could be sniffing network traffic as one of your users visits the site and could catch the cookie and gain access to their account since you just using simple session based authentication.
A common way to fix this problem is to create a database table, perhaps called "sessions", and record the session id, IP address, and any other user-specific data you want to gather when the user first logs in. You can then repeatedly check against this session table to help ensure that it is indeed the original user logged in and not somebody else.
It depends...
if you never do something like $_SESSION['user_id'] = $_GET['user_id'] you can usually say: it is save.
BUT there are things like session hijacking, cross site scripting, cross site request forgeries, and so on.
Use
if(!isset($_SESSION($user_id){
Because if the $user_id==0 then isempty() will not work and be sure that the session which is not required on another page must be unset after the page end for the better security. The method to unset a particular session variable is
unset($_session_variable_name);
and the session should be destroyed whenever it is required ie when a user logout.
Thanks
Not really, apart from the comments above you should further check properties like IP-address or USER_AGENT to avoid session-hijacking.
I currently have a website that allows my visitors to login via a simple script i've pasted together and wrote. Currently I only use sessions to keep visitors logged in. Are there any advantages to adding cookies to my website to store user logged in status?
Or is there a better way altogether?
using PHP
If you are using PHP sessions then you are using cookies. PHP stores session ID in cookies and the session data to a file on the disk on your web server.
#Ramiro Gonzalez Maciel he said he has made that script, he doesn't need frameworks to take as examples. Frameworks usually have scripts wrapped up and well placed.
To respond that question:
I usually store in cookie some md5 strings that are combined from his md5(password) and his username so I'll know next tim he enters my website that is was logged in so I wouldn't make him login again
my example:
<?php
$username = $_POST['username'];
$password = $_POST['password'];
// sql and escape stuff witch will return 1 if he has entered a valid login
if($sqlreturn == 1){
// do login
$wraplogin = md5($username."-".md5($password)."-".SECRET_KEY); // I always define a define('SECRET_KEY', 'mysecretkey'); in global file.
// now you can store that $wraplogin in cookies and remember his login. Next time he enters the website, you read that cookie, compare it with what you have in your database and let him in.
}
?>
Now I know that is not the best example, but I've personally used it in very large websites (>500.000 users) and none has hacked in yet :)
That's the advantage in cookies for the login part.
Best of luck.
The web frameworks ( Java Servlets and others ) usually use cookies to identify sessions; the other usual option is URL parameters. So assuming you're using any web framework, it's probably already using cookies to store the session id. The Web Framework will use this ID to identify the Session object in every request. Although cookies survive server restarts, since they're stored in the browser, Session objects usually don't unless you've configured Session persistence.
If you want to users to "auto login" as in the usual "rembember me" option many web sites implement, you would have to persist Session objects if your framework provides that. Or implement a similar system, using cookies to store a "logged in token", and checking that token when the user access the system to auto-log them or send them to a login page. ( Edit: like Mihai proposes in other answer )
If you want to implement your own method, I suggest checking how the popular web frameworks implement this, specially the security and privacy aspects of storing user data in cookies.