User Management Design - Sessions

Discussions of secure PHP coding. Security in software is important, so don't be afraid to ask. And when answering: be anal. Nitpick. No security vulnerability is too small.

Moderator: General Moderators

User avatar
Verminox
Forum Contributor
Posts: 101
Joined: Sun May 07, 2006 5:19 am

User Management Design - Sessions

Post by Verminox »

This isn't a question but more of a doubt that's been troubling me for a while and I want to clear it out.

I've seen two types of ways to handle user logins, and I'm not sure which one is a better method...

METHOD 1

Login once, store user id in the session, and retrieve it for every subsequent check (Query only once)

Code: Select all

<?php
function login($username,$password) // Assume encryption and escaping
{
    $result = $db->query("SELECT * FROM `users` WHERE `username`='$username' AND `password`='$password';");
    if($result->rowCount==1)
    {
        $user = $result->fetch();
        $_SESSION['user_id'] = $user['id'];
        return $user['id'];
    }
    return false;
}
 
function checkLogin()
{
    if($_SESSON['user_id']){
        return $_SESSION['user_id'];
    }
    return false;
}
?>
METHOD 2

Store username and password in the session, and login on each page (Query every time)

Code: Select all

<?php
function login($username,$password) // Assume encryption and escaping
{
    $result = $db->query("SELECT * FROM `users` WHERE `username`='$username' AND `password`='$password';");
    if($result->rowCount==1)
    {
        $user = $result->fetch();
        $_SESSION['username'] = $user['username'];
        $_SESSION['password'] = $user['password'];
        return $user['id'];
    }
    return false;
}
 
function checkLogin()
{
    if($_SESSON['username'] && $_SESSION['password'])
    {
        $username = mysql_real_escape_string($_SESSION['username']);
        $password = mysql_real_escape_string($_SESSION['password']);
        return login($username,$password);
    }
    return false;
}
?>

It seems that Method #2 is more secure, and security is more important than saving that one extra query. However, my question is, is it really more secure? Is there really a diference? Is there any way that Method #1 could prove less secure than #2?

According to me Method #1 is only insecure if sessions could be faked (Can they?)... then anyone could just plugin a false user id and login as that person. But I'm not sure if sessions can be faked this way. If not this, I can't think of any other reason why Method #1 would be insecure.

Any comments?
User avatar
Mordred
DevNet Resident
Posts: 1579
Joined: Sun Sep 03, 2006 5:19 am
Location: Sofia, Bulgaria

Re: User Management Design - Sessions

Post by Mordred »

Method #2 is not more secure than #1, sometimes even less secure - i.e. shared hosting, someone gets your session data - whoa, instead of a limited usage SID token, he gets login credentials, thankyouverymuch.
The #1 code itself has some problems (most important - regenerate the SID), but regarding #1 vs. #2, #2 is useless.
The #2 code is also buggy with double escaping.
User avatar
Verminox
Forum Contributor
Posts: 101
Joined: Sun May 07, 2006 5:19 am

Re: User Management Design - Sessions

Post by Verminox »

Mordred wrote:Method #2 is not more secure than #1, sometimes even less secure - i.e. shared hosting, someone gets your session data - whoa, instead of a limited usage SID token, he gets login credentials, thankyouverymuch.
The #1 code itself has some problems (most important - regenerate the SID), but regarding #1 vs. #2, #2 is useless.
The #2 code is also buggy with double escaping.
Nah $_SESSION contains unescaped data, so it should escape only once, but anyway I just typed this code out in the post as examples... it's not actually part of an application. Good point about the risk of storing passwords in sessions though...
User avatar
Mordred
DevNet Resident
Posts: 1579
Joined: Sun Sep 03, 2006 5:19 am
Location: Sofia, Bulgaria

Re: User Management Design - Sessions

Post by Mordred »

Nah $_SESSION contains unescaped data
Indeed, mea culpa. Must have been reading too diagonally :)
User avatar
Verminox
Forum Contributor
Posts: 101
Joined: Sun May 07, 2006 5:19 am

Re: User Management Design - Sessions

Post by Verminox »

Mordred wrote:
Nah $_SESSION contains unescaped data
Indeed, mea culpa. Must have been reading too diagonally :)
In fact, I was hoping to find $_SESSION and other second order vulnerabilities in your paper, for that is indeed a very unexpected SQL injection.
User avatar
Mordred
DevNet Resident
Posts: 1579
Joined: Sun Sep 03, 2006 5:19 am
Location: Sofia, Bulgaria

Re: User Management Design - Sessions

Post by Mordred »

The paper is focused on the escaping mechanism and the cases when it is not sufficient, while second order injections happen when data is escaped the first time, but not escaped the second time (that's why I decided it's outside the scope of the article). The remedy is the same though - escape and quote all values, irregardless of where they come from. I have written indirectly about it: one does this not because of SQL injection, but for data integrity. Escaping is not a security measure.

In that respect, "classic" papers on the subject, such like this: http://www.ngssoftware.com/papers/advan ... ection.pdf do give wrong advice.
Bruno De Barros
Forum Commoner
Posts: 82
Joined: Mon May 12, 2008 8:41 am
Location: Ireland

Re: User Management Design - Sessions

Post by Bruno De Barros »

Currently, I keep all the user data on the sessions. Some of the data is encrypted, but what you said is very concerning, because I deal with very important data that needs to be safe. I'll just keep the User ID on the sessions, and whenever I call getUser(), It'll go to the Database and get the user info, instead of getting it from the sessions. Thank god I decided to abstract the user system. It means I won't have to refactor any code :).
Attilitus
Forum Commoner
Posts: 27
Joined: Wed Aug 08, 2007 2:32 pm

Re: User Management Design - Sessions

Post by Attilitus »

Those are both truely TERRIBLE methods. You should not store any meaningful information on the client's computer. (not even their "userid")

You ought to do something like the following method:

On login:

1) Verify that a user entered in the right username/password.
2) Generate a random unique LONG hash.
3) Delete all entries from the Sessions table where userid = the user's userid.
3) Store the userid and the aforementioned long hash in a table called: sessions.
4) Set either $_SESSIONS[] or set a cookie that stores the long random hash on the client's computer.

5) When the user goes from page to page fetch the value assigned to the $_SESSIONS array or to the $_COOKIES array and select from table SESSIONS where hash = $_COOKIES['siteauth_hash'] and if you find a match your script knows with absolute certainty that the user has logged in properly.

Your script should confirm if a user is logged in, and then fetch the confirmed userid in the SESSIONS table and use that id to fetch information about that user from other tables. (Like a "user" table.)

This method doesn't store any meaningful information on the client's computer.
Bruno De Barros
Forum Commoner
Posts: 82
Joined: Mon May 12, 2008 8:41 am
Location: Ireland

Re: User Management Design - Sessions

Post by Bruno De Barros »

@Attilitus, is it just me, or do you think $_SESSIONS are kept on the host's computer? They are not. They are kept on PHP's own storage. While it has the (small) problem of possibly being accessed by someone else (thus, only storing the user ID on the session would be the way to go) from within the server, it is as safe as your method.

The long random hash would be the session ID. And the user ID would be... the user ID.
This would save on database calls. And if you are security obsessed, you can encrypt your session data (so people reading it don't understand it). Proper garbage collection and correct session expiry dates would be an extra.
Attilitus
Forum Commoner
Posts: 27
Joined: Wed Aug 08, 2007 2:32 pm

Re: User Management Design - Sessions

Post by Attilitus »

Bruno De Barros wrote:@Attilitus, is it just me, or do you think $_SESSIONS are kept on the host's computer? They are not. They are kept on PHP's own storage. While it has the (small) problem of possibly being accessed by someone else (thus, only storing the user ID on the session would be the way to go) from within the server, it is as safe as your method.

The long random hash would be the session ID. And the user ID would be... the user ID.
This would save on database calls. And if you are security obsessed, you can encrypt your session data (so people reading it don't understand it). Proper garbage collection and correct session expiry dates would be an extra.
Yea, I know how sessions work. However, it is unwise to store data in sessions on a shared hosting environment. My approach is a catch-all method for all cases. (And typically I use cookies as opposed to sessions).

The necessity of sessions and cookies is to find some way to associate a user with the database. This can be done without storing any valuable information outside of the database system. Sessions store valuable information outside of the database system, and thus are a less elegant solution.

But yes, my system is essentially a more secure version of the way normal sessions work in php. Good observation. :)
User avatar
Verminox
Forum Contributor
Posts: 101
Joined: Sun May 07, 2006 5:19 am

Re: User Management Design - Sessions

Post by Verminox »

@Attilitus: How is storing a long hash in the session any more secure than storing the user id? If you are in a shared hosting environment and someone is destined to gain access to your session data and is going to fake a sesion, then gaining either data is just as bad, the only difference being in your case the attacker doesn't know who's session data he has stolen...

Edit: OK, I just realised that if the attacker had write access to the session directory and created a new session with a user id of his choice, he could exploit the first method, while with your method he can't do anything without database access as he has to match a hash with a userid. Is that the reason?
Attilitus
Forum Commoner
Posts: 27
Joined: Wed Aug 08, 2007 2:32 pm

Re: User Management Design - Sessions

Post by Attilitus »

Well the random hash would only be associated with the user for the duration of that user's activity on the site, as the hash is generated randomly on each login before associated with a given user.

I don't like using sessions at all, I prefer using cookies.

Edit: I just read your edit. Thats correct, a user with the ability to read/write to the sessions directory wouldn't be able to do much of anything under my system. Unless he discovered the sessionid associated with the hash, and then forged that sessionid. However, that would only be valid for the duration of that user's activity and the attacker would have absolutely NO information on what data the particular session he was forging was associated with.

For all the attacker knows he isn't even forging the sessionid of an actual user.
User avatar
Verminox
Forum Contributor
Posts: 101
Joined: Sun May 07, 2006 5:19 am

Re: User Management Design - Sessions

Post by Verminox »

Good point. Your system could be further strengthened by regenerating the long hash at every request, even though that would take an extra query everytime.
Attilitus
Forum Commoner
Posts: 27
Joined: Wed Aug 08, 2007 2:32 pm

Re: User Management Design - Sessions

Post by Attilitus »

Verminox wrote:Good point. Your system could be further strengthened by regenerating the long hash at every request, even though that would take an extra query everytime.
Precisely! There are in fact, many many different things you can do to strengthen this system. Its strength is in its flexibility. :D
Bruno De Barros
Forum Commoner
Posts: 82
Joined: Mon May 12, 2008 8:41 am
Location: Ireland

Re: User Management Design - Sessions

Post by Bruno De Barros »

Hmm... I'm getting ideas for making a full fledged sessions system using your method. It does not suffer from PHP's natural vulnerability, and I could make it work the same way (including the $_SESSION manipulation). Hmm... Interesting :).
Post Reply