[dba-VB] ASP.NEt 2.0: Forms Authentication: how toprevent using the same login *second* time from another PCwhen this login is in use in active session?

Shamil Salakhetdinov shamil at users.mns.ru
Tue Dec 18 18:48:47 CST 2007


Hi Gustav,

It looks like I have found a rather generic solution - here it's:

Requirements:
-------------
Allow
=====
- to have multiple tabs opened for a browser instance for a logged-in user:
all tabs will share the same login and Session id (this login/sessionId
sharing is a feature by design of browsers, ASP.NET, forms  authentication,
custom functionality)
- a session of an abandoned browser to expire in 15-30 minutes and then
another session can be started with the same login or
- "optionally kill" active login's session - first informing the user trying
to use login, which is currently used in an active session  that his attempt
will "kill" active session, which he probably abandoned (by  mistake)
without explicit logout ...

Prevent
=======
- to use the same login with another instance of a browser running on the
same PC;
- to use the same login on another PC, while this login is active
(logged-in) somewhere else;
- running (loading, rendering web page) by copying & pasting URL from one
tab's window to another tab within one browser instance or to another
browser instance...

To implement above requirements I plan to:
------------------------------------------
Before navigating to a URL with my Web App:
===========================================
- prepare context parameters to put them in the URL's QueryString to keep
initial rendering state/context for a Web Page to be navigated/transferred;
- generate a unique hash for the QueryString using the following values:
   1) Login name;
   2) login timestamp - created on login and stored in Cache using login
name as a key;
   3) The session navigation step Id (navid) - unique sequential number
incremented for every Redirect/Transfer and kept on the Session level;
   4) SessionId (the fact is that Sessionid can be the same for
logins/logouts for the same/other logins when these logins are happening in
one browser instance...)

This hash will be added to the QueryString together with navId;

- make an URL with parameters and navigate/transfer to it;

On page loading/building on server side I will:
===============================================
- use generated hash to create Session[...] item key on page's first load
within given context (!Page.IsPostback);
- if the same query string will be used (copy & paste) on another *tab of
the same browser instance* then I can check that this hash was already used
(by reading Session[...] item) when rendering the first page and I will
cancel rendering of the second's tab page....
- if the same query string will be used (copy & paste) on another *instance*
of a browser then by recreating hash I will see that it will not fit the
SessionId and I will cancel rendering page on the second browser instance...
- IOW this hash will be a good measure to prevent compromising the
QueryString values...
- the Session[....] hash value has to be cleared out/saved in db when
navigating to another URL, that will not always be possible, but that should
be rare occasions and therefore I expect  there will be not be that much
"hanging abandoned hashes"...

Additionally
============
- to prevent copied & pasted URL with QueryString parameters to be used
within the same browser instance when first page is navigated out I can keep
hash saved in the db table and this table's data used for the check
described above. This table's data will be cleared when session ends/expires
or this data can be used as a navigation audit trail...

Summary
======
It looks like I covered all the possible variations - still the above
solution is rather simple to implement and it's scalable...
Currently I will just use QueryString to keep navigation context:
QueryString is known as being an insecure for compromising attempts but
because of the fact that I plan to add a hash to this QueryString in (the
near) future I will keep it secure: and the hash calculation/check will be
done in the generic part of my code as well as mentioned above navId
caluclation, as well as keeping session login timeStamp in Cache[...], as
well as keeping page rendering hash in Session[...], as well as clearing
Session[...] hash/saving it in DB when navigating out or when session gets
expired...

Final note:
===========
Originally I planned to stop using QueryString because it's commonly
accepted as insecure but the solution above allows me (?) to continue using
it (QueryString) without that much additional efforts and having it good
enough secured (I have a Web app under development, which has different user
contexts depending on roles and these contexts' can be dynamically changed
without logging-out/-in, and users are rather inexperienced, and this
application have to communicate with external credit card processing server,
and this application should have easy navigation, and this application
should place consistent orders, which are generated from shopping cart(s)'
items, which in turn are collected in different contexts in which e.g. a
user can be an admin making an order for a customer who in turn purchases a
service for another customer who should be able to see this to be purchased
service as owned by his account when purchase completes but the first
customer should have this service paid from his accountetc...

Because of this relative complexity of the app I looked for a solution,
which is presented above, which isn't contradictory (?) and which is not
that a big issue to implement generic way....

Being here now I will probably even weaken the requirement stating to not
let an URL with QueryString parameters to be copied & pasted and activated
(corresponding page loaded/rendered) within tabs of one browser instance: I
will let to do that except just one case when application redirects to an
external credit cards processing service - this service should be redirected
only once within check-out process and until it calls back transaction is
not finished...


--
Shamil
 

-----Original Message-----
From: dba-vb-bounces at databaseadvisors.com
[mailto:dba-vb-bounces at databaseadvisors.com] On Behalf Of Gustav Brock
Sent: Tuesday, December 18, 2007 8:27 PM
To: dba-vb at databaseadvisors.com
Subject: Re: [dba-VB] ASP.NEt 2.0: Forms Authentication: how toprevent using
the same login *second* time from another PCwhen this login is in use in
active session?

Hi Shamil

Oh, that is a nightmare. I just opened three tabs (it's me at 213.150.48.58)
and the only parameter changing is Page View Count. And that counts up also
if the user requests a refresh of the browser window! And it counts down as
the sessions time out. Not very useful.

So now what? Could a client side GUID be generated that was recorded at
server side? 

Sadly, I have little time to work intensively with this right now - a web
session on the new MySQL Falcon engine is approaching - but count me in if
you need further testing - it would be really nice to find out how to deal
with this issue which will pop up again and again.

/gustav

>>> shamil at users.mns.ru 18-12-2007 18:02 >>>
Hi Gustav,

OK, killing session when simultaneous FormsAutentication login with the same
credentials happens or wait 20 minutes this is one "programmers' nightmare"
issue, and here is another one:

- in IE7 (or FireFox 2.x +) you can open several tabs in one browser
instance and then all these tabs' windows will share the same session...

How about that "nightmare"?

I have got deployed here 

http://shamils-4.hosting.parking.ru/Sessions 

a sample from this article

http://www.stardeveloper.com/articles/display.html?article=2002102501&page=1



by setting session time-out for three minutes

    <sessionState  
      mode="InProc"
      cookieless="AutoDetect"
       timeout="3" />

just for testing purposes to see how sessions expire and how one browser's
instance tabs share the same session ID...

Now imagine a Web app having context (i.e. some internal state) and a user
opening several tabs in one browser instance and copying and pasting URL "to
see what happens" or to maybe do several tasks with the same Web app having
issues the *same* session Ids for one login, which could be working on one
task when this user switches and prepares another. When FormsAuthentication
added then user *will not* need to login again if he copy and paste URLs in
windows of the different tabs of the same browser instance...

Server side app will not be aware how many windows are opened on client side
without special measures...

What those measures should be to differentiate calls coming from different
windows having the same URL, same session Id, same Forms Authentication
cookie?

I currently see the only "simple" solution to have hidden HTML field(s) with
some IDs for every page returned from server to browser, and when browser
posts back such page then this ID expires and is changed to another, and
server side app has to keep track of these custom IDs, and when they are
sent via callback remove them etc.

...

--
Shamil
 

-----Original Message-----
From: dba-vb-bounces at databaseadvisors.com 
[mailto:dba-vb-bounces at databaseadvisors.com] On Behalf Of Gustav Brock
Sent: Tuesday, December 18, 2007 7:21 PM
To: dba-vb at databaseadvisors.com 
Subject: Re: [dba-VB] ASP.NEt 2.0: Forms Authentication:how to prevent using
the same login *second* time fr

Hi Shamil

That was my thoughts and conclusion.
And it does have that complication. However, at _any_ time the user can
"pull the plug" - in many ways with or without intention. I think that's the
programmer's nightmare all the time to consider "what happens at this point
if the user session is killed?". The user may loose data typed in, but the
app should not crash and stored data should not get corrupted.

Further, you cannot educate users to always logout clicking a button. As the
good guy I am I always try to do so, but in Hotmail you are redirected to
msn.com which I hate, thus I always close a Hotmail session by clicking the
close button of the window, and most users will do as well as they forget or
don't understand why not to do so.

Also, your client must be really nice and patient! Keeping a user logged out
for about 20 minutes if something happens will not raise popularity among
users. Again, users are impatient and will not understand why they can not
just log in again.

/gustav

>>> shamil at users.mns.ru 18-12-2007 16:52 >>>

<snip>

...the most user-friendly looks like to "kill" existing session when a login
with the same FormsAuthentication credentials happens - this should be a
rare occasion after all and this will not force users to wait until session
time-out expires...

...the only complication for the latter approach is that  Web application
keeping some state information should be ready to be "killed" any time - I
mean when they get "killed" they shouldn't leave the system  and back-end
database in inconsistent state - the "killer: should be able to "catch-on"
on the session it "kills"...

...yes, I know web applications should be better programmed completely
stateless - trying to achieve that here but not yet there - have to convince
customer to change the ways they usually work with desktop apps - I mean to
not expect the same "stateful" behavior from Web apps because "it's all two
blades sword" - you gain in one feature/functionality/usability issue - you
loose in another...

</snip>

_______________________________________________
dba-VB mailing list
dba-VB at databaseadvisors.com
http://databaseadvisors.com/mailman/listinfo/dba-vb
http://www.databaseadvisors.com




More information about the dba-VB mailing list