473,405 Members | 2,354 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,405 software developers and data experts.

Session fixation idea

I had this idea about preventing session fixation, and I'm wondering
what anyone else thinks about it. The idea is, essentially, don't
allow session ids that YOUR PHP didn't generate (and aren't yet
expired) to log in. That way if someone sticks a made-up session
ID on a URL, it won't matter, unless it happens to correspond to
an active session (guessing a user password is probably easier).

Is this already standard practice, new, or is there something better?

I like to use a session save handler to put the data into a database.
So in my case, using a session save handler isn't a lot of extra
work. My approach can deal with sessions saved just about anywhere,
but you need explicit handlers you can modify to use it.

This approach assumes that you already have a login setup and every
protected page will check for a logged-in and unexpired session,
and if not, redirect the browser to the login page. There's some
session data like $_SESSION['logged_in'] = 1 to indicate a valid
login. You also have a timeout so the session expires some time
(say, an hour) after the last click.

When the session handler "open" routine is called, session_id()
returns the session ID the browser supplied if there was one,
otherwise it returns an empty string. The documentation says this
but not specifically about what happens when it's called from the
session handler open routine.

So, if session_id() returns a non-empty string, and
that session doesn't exist in current sessions, you have
(1) A session-fixation attempt,
or
(2) A user returning after their session has expired (or they logged
out explicitly) and been deleted.
Either way, there is no existing session data, so they can't be logged in.
I propose setting a global variable like $possible_session_fixation_attempt
to either 0 or 1 depending on the results of this check.

If the user tries to go anywhere but the login page, he's not logged
in, so he'll be redirected to the login page. At the login page,
if $possible_session_fixation_attempt is set, call
session_regenerate_id(true). The argument causes the deletion of
the old session. Then proceed with the normal logic for the login
page. The logged-in session will have the new session id.

Now, this idea doesn't prevent (or attempt to prevent) hijacking
of unexpired sessons due to snooping or extremely lucky guessing
or the user publishing the session ID. It does prevent tricking a
user into using a pre-determined session ID, which can then be
trivially guessed.

Mar 10 '07 #1
2 2616
go***********@burditt.org (Gordon Burditt) wrote:
I had this idea about preventing session fixation, and I'm wondering
what anyone else thinks about it. The idea is, essentially, don't
allow session ids that YOUR PHP didn't generate (and aren't yet
expired) to log in. That way if someone sticks a made-up session
ID on a URL, it won't matter, unless it happens to correspond to
an active session (guessing a user password is probably easier).
This is problem I had already considered. With the current design of the
'session' extension, the function session_start() actually has two
roles:

1. If the browser does not sent a cookie, or the sent cookie is not valid
or expired or does not match any of the existing session files, a new
session is created with an empty $_SESSION[] array.

2. If the cookie returned from the browser match an existing session file,
the session is renewed (the same cookie is sent back to the browser).

Unfortunately this design has two drawbacks:

a. Entropy waste and possible security issue. Commonly, programmers call
session_start() in every page of their WEB site. A malicious remote user can
then repeatedly call any one of these pages so forcing the server exhaust
its entropy reserve, and the less secure pseudo-random number generator is
used instead.

b. The programmer needs to add an element to the $_SESSION[] array in
order to check for a valid login session. Typically this element is the
user name $_SESSION['user'] or the primary key that identify this user
$_SESSION['user_pk'] or simply a flag $_SESSION['logged_in'].

In my opinion, two functions should be introduced in place of session_start():
session_new() and session_exists().

session_new() create a new empty session and send the corresponding cookie to
the browser. This function must be called only after the user has successfully
logged-in. The implementation is really simple:

/*. void .*/ function session_new()
{
session_destroy();
$_SESSION = array();
session_start();
}

session_exists() return FALSE if the browser does not sent a valid
session cookie, otherwise this function renew the session calling
session_start(), then return TRUE. This is the function that must be
used in every page of the WEB site (apart the login page). If the session
exists, the code of the page can be executed, otherwise the browser
should be redirected to the login page:

<?php // some_page.php
if( ! session_exists() ){
header("http://www.mysite.xxx/login.php");
exit;
}

// rest of the page here:
header("Content-Type: text/html; charset=utf-8");
// etc. etc.
?>

Note that the program does not need to check for the existence of the
$_SESSION['user'] or $_SESSION['user_pk'] elements, since if the session
exists it was certainly created by our program at the time of the login.
The implementation of the function session_exists() can be as follow:

/*. boolean .*/ function session_exists()
{
$sn = session_name();
if( ! isset( $_COOKIE[$sn] ) )
# No cookie from client.
return FALSE;
$sv = (string) $_COOKIE[$sn];
if( preg_match('/^[-,a-zA-Z0-9]+$/', $sv) !== 1 )
# Not a valid cookie syntax.
return FALSE;
$sf = session_save_path() ."/sess_". $sv;
if( ! file_exists($sf) )
# This cookie is not a session or session expired.
return FALSE;
session_start(); # restore session.
if( session_id() === $sv )
# The restored session is that we actually expected.
return TRUE;
# Race condition detected: the old session $sv expired
# in the meanwhile and a new one was created by session_start(),
# so $_SESSION[] is empty. Roll-back and return FALSE.
session_destroy();
return FALSE;
}
Is this already standard practice, new, or is there something better?

I like to use a session save handler to put the data into a database.
So in my case, using a session save handler isn't a lot of extra
work. My approach can deal with sessions saved just about anywhere,
but you need explicit handlers you can modify to use it.

This approach assumes that you already have a login setup and every
protected page will check for a logged-in and unexpired session,
and if not, redirect the browser to the login page. There's some
session data like $_SESSION['logged_in'] = 1 to indicate a valid
login. You also have a timeout so the session expires some time
(say, an hour) after the last click.

When the session handler "open" routine is called, session_id()
returns the session ID the browser supplied if there was one,
otherwise it returns an empty string. The documentation says this
but not specifically about what happens when it's called from the
session handler open routine.
session_id() returns the empty string before session_start(), and the
session value after session_start() has been called, so this function
is not useful to test for an existing session created at login.
So, if session_id() returns a non-empty string, and
that session doesn't exist in current sessions, you have
(1) A session-fixation attempt,
or
(2) A user returning after their session has expired (or they logged
out explicitly) and been deleted.
Either way, there is no existing session data, so they can't be logged in.
I propose setting a global variable like $possible_session_fixation_attempt
to either 0 or 1 depending on the results of this check.

If the user tries to go anywhere but the login page, he's not logged
in, so he'll be redirected to the login page. At the login page,
if $possible_session_fixation_attempt is set, call
session_regenerate_id(true). The argument causes the deletion of
the old session. Then proceed with the normal logic for the login
page. The logged-in session will have the new session id.

Now, this idea doesn't prevent (or attempt to prevent) hijacking
of unexpired sessons due to snooping or extremely lucky guessing
or the user publishing the session ID. It does prevent tricking a
user into using a pre-determined session ID, which can then be
trivially guessed.
I don't understand this last sentence. Session IDs are always created by
the server. The browser cannont force the server to create an arbitrary
session with an arbitrary value.

Regards,
___
/_|_\ Umberto Salsi
\/_\/ www.icosaedro.it

Mar 10 '07 #2
>When the session handler "open" routine is called, session_id()
>returns the session ID the browser supplied if there was one,
otherwise it returns an empty string. The documentation says this
but not specifically about what happens when it's called from the
session handler open routine.

session_id() returns the empty string before session_start(), and the
session value after session_start() has been called, so this function
is not useful to test for an existing session created at login.
But I'm not looking at it BEFORE or AFTER session_start(), I'm
looking at it DURING. Specifically, when the session save handler
open() routine is called (while session_start() is running). THEN,
it appears to be usable to tell whether a session is going to be
created.
>So, if session_id() returns a non-empty string, and
that session doesn't exist in current sessions, you have
(1) A session-fixation attempt,
or
(2) A user returning after their session has expired (or they logged
out explicitly) and been deleted.
Either way, there is no existing session data, so they can't be logged in.
I propose setting a global variable like $possible_session_fixation_attempt
to either 0 or 1 depending on the results of this check.

If the user tries to go anywhere but the login page, he's not logged
in, so he'll be redirected to the login page. At the login page,
if $possible_session_fixation_attempt is set, call
session_regenerate_id(true). The argument causes the deletion of
the old session. Then proceed with the normal logic for the login
page. The logged-in session will have the new session id.

Now, this idea doesn't prevent (or attempt to prevent) hijacking
of unexpired sessons due to snooping or extremely lucky guessing
or the user publishing the session ID. It does prevent tricking a
user into using a pre-determined session ID, which can then be
trivially guessed.

I don't understand this last sentence. Session IDs are always created by
the server. The browser cannont force the server to create an arbitrary
session with an arbitrary value.
The browser usually can make the server create an arbitrary session
with a user-specified *ID*. This is called session fixation, and
what I'm trying to prevent. The contents of the $_SESSION variable
may not be specified, or sessions would be completely hopeless for
security.

In the existing setup, pretty much every page calling session_start(),
all that is necessary for creating a session with an ID that I, the
user, specify, is to create a cookie in my browser and make a HTTP
request of the server. This is really easy with things like CURL.
It gets worse. With trans_sid set, the user can ask for:

http://www.example.com/dir/foo.php?P...00000000000000

Now, this isn't absolutely horrible security, because there's no session
file for this, so it starts off fresh with no session variables set.
That's why existing pages check for $_SESSION['user'] or something.
They may also need to have that variable anyway: many pages need to
know which user is logged in to display user-specific information.

The bad part comes when you trick another user into forcing a session day
which you, the bad guy, can guess easily because YOU set it.

Note that for some applications, setting up a session for anyone, no
login required, is desirable behavior for, say, multi-page surveys to
pass information between the pages of the survey. The login model is
not the only use for sessions, although it is a very common one.

Mar 11 '07 #3

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

9
by: Marcus | last post by:
Hello, Currently all of my php pages use SSL, not just my initial login. Originally I thought this would be more secure, but after thinking about things and looking at sites like Amazon and...
5
by: Just D. | last post by:
Do we have any access to the Session object from a different Session? The idea is to save Session of a current user and then if he logs in again then return the Session back. It's not a problem to...
5
by: Steven Blair | last post by:
I have the following code: Session = new CurrentUser("TEST"); When I postback to the server, the Session is null. My guess is a only the refence to my actual class is stored, rather than the...
2
by: Tom | last post by:
I hope someone can help me figure out what's going on here. I've re-read the section on sessions at php.net and Googled this high and low but I haven't found anything that quite explains my...
9
by: forje | last post by:
Hi all, How to make a session "exclusive"? When one attempts to open a new session either he's warned and asked to wait or any other openned session is closed. The need is to force only one user...
16
by: howa | last post by:
1. For example, without SSL, If I capture my local LAN packet and scanned the SESSION ID, is it possible to hijack the session? 2. So any recommendation for web apps session handling without SSL?...
2
by: =?Utf-8?B?YW5vb3A=?= | last post by:
Hello, I am developing a Simple ASP Application with a Login page. I want to know how session ID can be generated after User has authenticated instead of generation along with the Login page...
3
by: laredotornado | last post by:
Hi, I'm using PHP 4.4.4. I have two domains -- www.mydomain1.com and www.mydomain2.com. Both point to the same IP address. I have two pages on that IP -- first.php <?php session_start();...
8
by: pim | last post by:
Dear All, What I was wondering is how safe it is to store user_id or username or anything like that in session. I usualy store a bunch of info in a session so I do not need to search the...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.