Monday, November 20, 2006

Multiple Tabs and Windows with session_regenerate_id()

I was asked a week ago to improve the security of the login system used for one of the sites I manage. Prior to being asked the data displayed on the site was not of a sensitive nature - but a recent project I have been working on requires a little more security.

I decided to do two things:
  1. I added a Javascript to MD5 hash strings. Within the login form a random string is placed in a hidden field. This is stored in the server side session. Upon pressing the submit button this is concatenated to the password and the entire string it Md5 hashed.
    • This first ensures the password is not sent in plain text across the unsecured connections.
    • Second, it ensures that an intercepted Md5 string cannot be used again to logon. As it is generated using of the password and the random string fixed to the users session.
  2. Additionally I decided to use session_regenerate_id() with every single request. This would mean the session ID is only ever good for one request. Upon changing the session ID, the old session was of course deleted.
The first change worked fine and for those who don't have Javascript enabled, the unencrypted password and login string is used. However, a couple of days after sending out the update for the site I started getting complaints from some users that they had to keep logging on.

Upon viewing the logs, it was clear that some users were having to logon several times during their session. I did some investigation and came up with the following cause.
  • It was clear from the logs that the cookie being sent contained the old session ID that had not been updated on the users PC after the call to session_regenerate_id().
  • As the old session had been deleted it appeared as if the user had attempted to request the service without even starting a session and logging on.
  • The previous valid request was at exactly the same time or less than 2 seconds before the failed request.
After servicing a request, I have set the application up to dispatch the request to another script (designed only to display the result) via an HTTP redirect using the Location header. I concluded that the redirect was taking place before the web browser had a chance to update the cookie and as such sent the old session ID.

The reason for this? - being unable to replicate the error on my system I concluded that the users PC was not fast enough to update the cookie before redirecting. Therefore I modified the application to ensure that session_regenerate_id() is only used on a request that has not been redirected. I sent the update and hoped this would fix the problem.

Today however, I checked the logs and it was clear that a number of users were still experiencing the same problem despite the modification. I needed to revisit the problem!!

I trawled the logs again and after some time noticed the previous request was within a second of the failed request again. How was this possible? How can one person make two requests in such quick succession? After some thought it came to me - it is just possible that the user has multiple windows/tabs open on their desktop. They are typing in the data (in this case a single order number) and clicking the submit button in each window, one after the other. So, I opened a few windows in Firefox and entered a few order numbers. Then clicked the submit button in each window at a modest speed. Unsurprisingly, this replicated the error and is the most likely cause of the problem the users are experiencing.

I have temporarily disabled the call to session_regenerate_id() while I come up with a solution. It demonstrates once again the varying ways in which your users will use your application and how crucial the logs were (in this scenario) to solving the problem. An example of which is posted below:

Mon, 20 Nov 2006 08:04:38 +0000 123.123.123.123 /ordersearch_display.php
User agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727)
Get Variables: Array()
Post Variables: Array()
Cookies: Array( [sid] => 5442a47367571d58101184c1c71df2c4)
User Authenticated: USERNAME
Module: ordersearch loaded.
Module: ordersearch executed for output.
Regenerating Session ID old=5442a47367571d58101184c1c71df2c4 new=5e507a0b72f3dc47501f60316721e48
--------------------------------------------------------
Mon, 20 Nov 2006 08:04:40 +0000 123.123.123.123 /ordersearch_input.php
User agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)
Get Variables: Array()
Post Variables: Array( [order] => Array ( [ordernr] => 12345 [ord_seq] => ) [submit] => Retrieve Order Data)
Cookies: Array( [sid] => 5442a47367571d58101184c1c71df2c4)
User Not Authenticated

Friday, November 03, 2006

A Piece of Information I'd like to have!!

I have my own home server which runs on the Linux Operating System. I use it to store the music and documents for the whole family as well as host a web, FTP and SSH server and act as a development platform for my web applications.

While I have put the time and effort into ensuring the server is as secure as possible. I am none too aware that there could and probably are security holes and vulnerabilities exposed by services that could be exploited by an attacker. I would like to know how many times (if any), my server has been compromised and by whom.

If I were to have this information, I would first find the vulnerability or hole the perpetrator used to gain access and secure it to ensure it is not exploited again. Secondly I would seek to learn some of the skills employed by the perpetrator that were used in order to gain access and use this knowledge to hole foresee other possibly holes a vulnerabilities in my setup and configuration.

What would you do?