I’m using Symfony2.1, a very simple login form based on documentation (http://symfony.com/doc/current/book/security.html#using-a-traditional-login-form) and a custom authentication success handler.
Anonymous user can do some action which are stored in database with the user's session ID. Now the user is logging into the system and I want to update saved actions with user's ID so that logged user can continue its work . Unfortunately in success handler I have already an updated session ID and I don’t know which records in action's table belongs to user (since they are stored with old session ID that I can’t access to [or can I?]).
What is the best practice to handle this kind of situations. Should actions be saved in database with token stored in cookie instead of session id or is there a build in mechanism and I’m trying reinvent the wheel or maybe I’m asking wrong question and therefore I can’t find answer.
The default mechanism of generating a new session id on an access level change is best practise. You could write your own authentication that does something with the new and old session ID. But unless you really know what you are doing security and authentication code is best left alone.
Best method would be as you suggest to save a token in the database and in a cookie and track your users with that. Don't forget to clean up the used tokens in the database and cookies if you no longer need them.
Related
In my web application I would like to show the user if he/she is already logged in on another machine. Also I would like to provide the user with the option to sign out of all machines except the current one.
Now I'm talking about session logins, not active sessions so updating a last_activity column isn't going to do the trick.
Now I assume the (only) way to achieve this is to decrypt the session payloads from the database and checking the Auth id from there. This is quite a heavy operation to do for every page request for 1000 logged in users.
Am I correct in this guess? Is this the correct (or only?) way to do it? Is there a better way to do this? If decrypting the Session payload is indeed the best option, how do I do this? I tried using Crypt::decrypt($session->payload) but I get 'Invalid Data' from the Crypt class.
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 use the Yii framework, and I notice that when a user logs in his connection is saved inside a session.
What that means is if someone would guess someone's else session id, he could log in inside his account.
So I wanted to know if I should to keep it that way and should not change anything because it's secure enough, or will it be better to make some other authentication system? For example, storing the user's id and token inside a cookie.
I am using PHP and Codeigniter to do this. Currently I am just saving a cookie to the user with their username and a $logged_in variable set to true. Then when they try to access a page, I check for the status of their $logged_in, and if they are, they're free to access.
It occurs to me that this may not be the safest way to go about this. Is there a better tactic I should be using?
It's not safe at all. Cookie is considered user input and it can't be trusted in any case.
Use sessions instead.
Also you could use some sort of custom login encrypted code (I'd personally suggest SHA1) that is matched against the login code in the database and is refreshed every, let's say, 5 minutes.
CodeIgniter offers a nice solution to this problem - You can use Database Sessions.
With Database Sessions, all the data you put in a session is stored within your SQL database. The user gets a cookie with a unique session ID that changes on a regular basis. The session ID along with IP and User Agent is used to match up the user with their session data, thus making it impossible for users to tamper with their own session data, and very hard for them to hijack someone else's session.
You can read more about CodeIgniter Database Sessions in the CodeIgniter User Guide.
I'm developing my own PHP framework, and I'm trying to do things more "by the book".
I want to build login system. I have done this plenty of times, but now I just want to confirm/get some feedback on a system.
I know we need...
A Session Object
A User Object
A Login Controller
What my question is, is who holds what power?
Here's my thought - when you submit your un/pw, it obviously goes to the Login Controller. We need to look up that un/pw combo in the user database, and therefore I feel as if that should be done in the in the user object ... $User->authenticate($un, $pw).
All that should do i return true or false. Then the LoginController should tell the Session object to create a session ... $session->create(). But apart of me wonders if the User and Session object should be a bit closer knit, and not rely on a Controller.
Looking for opinions, thanks in advance.
In my opinion, the user object shouldn't know about persistence (session) or the application (controllers). All it should care for is representing a user and handling user-related functions like authenticate.
The controller is all about application logic, and the session is part of the application. I feel like it's the controllers task to open the session and store the user object for later usage, once authenticated.
P.s. Did you publish your framework? Github it! :-D
My thoughts for a framework like this:
Initialize session object on page loads, and set it to default to a "guest account".
Upon this initialization make your session object to look for a session identifier (from a cookie?) and validate that ID against your session tracking back-end, be it database or whatever you are using.
If the session ID validates, you get your relevant user ID which you can then use to populate the user object.
Login control should just authenticate the user from login, and initialize the session by binding session ID and user ID on the back end, and by writing the session ID to a cookie.
... A more efficient way, however, would be to authenticate the user once and write the user ID to a digitally signed cookie set by the server, and trust all valid cookies returned by the client. This would make session management so much lighter and save round trips do database.