I wrote up a class for storing sessions in a database. The goal was to make sessions more secure. I focused on the two main session attacks, high-jacking and session fixation. While it is impossible to use sessions that cannot be high-jacked or fixated, simply because you must get the session id from the client, you can make these attacks harder to accomplish. The source code is in the attached zip file, what follows is an explaination of what I've attempted to accomplish and some of my concerns and points for reveiw.
Database Sessions with Improved Security
This class uses a database to store the sessions and implements some security precautions on retrieving/setting the session id as well. A database is used, instead of flat files, in an attempt to avoid performance issues. The security precautions produce a great deal of overhead in starting a session, so optimizing information retrieval becomes paramount in keeping session performance at a maximum.
There are three security precautions enabled.
The first is a session id validation. This means that every session id passed to the system must match. For example if there are session ids passed in the query string and via a cookie, those two session ids must match or the system generates and uses a new session id. This will protect against session fixation, where the user already has a session id stored on their computer.
The second method is an existence check. If the user passes a session id to the system, then a database record should be stored with that id. If there is no database record with that id then the session is reset with a new session id.
The third precaution is a validity check. Every time a user visits a page that uses sessions their ip is recorded and a unique session token is created. The session token is stored in a cookie on the users system as well as in the database. Then the system checks to make sure that the token and the user’s ip are the registered token and ip for this session. If this check fails the session is reset with a new session id.
Whenever a session is reset with a new id an error of level E_USER_WARNING is generated. Any program using this package should trap for this error and respond accordingly, as when a session id is reset any information currently stored in the user’s session is lost.
These measures make session fixation and high-jacking much harder to accomplish.
In a session fixation attack the attacker attempts to provide the session id to the user. Then the attacker can use this session id to high-jack the user’s session. With this system when an attacker provides a session id to the user, if it is not already in the database, the user will be issued a new session id. If the id is already in the database, but they do not posses the correct ip address and session token they will be issued a new session id. This means that session fixation is all but impossible as the attacker would have to spoof their ip to the same as the target’s, create a session, give the target the session token and session id and then high-jack the session. However the token is changed every time a sessioned page is retrieved, therefore the attacker would also have to obtain the new session token before they could high-jack the session.
In a session high-jacking attack the attacker figures out a users session id and then spoofs their session id so that the system thinks they are the target. This system makes this difficult as well. The attacker would have to spoof the target’s ip and gain the current token for the target’s session. However once the attacker high-jacked the target’s session the target’s token would become invalid. Then the next time the target accessed a sessioned page their session would be reset and their session information would be deleted from the database. So while still possible to high-jack sessions it is very difficult and has a limited time frame in which it will work.
User Unfriendliness of This Solution
Most times when you implement security precautions it is done at the expense of user friendliness. This is the case with this solution. User friendliness is negatively impacted in two ways. The first is that the user’s browser must accept cookies or they will end up getting a new session id every time they access a sessioned page. The second way is that if a suspected attack is detected the user’s session is reset and they loose all the data that was in their session. If you have a shopping cart and the user has been in your store for a while this could be a substantial loss of data. However, if the user is made aware of this possibility and that if this happens it means your system successfully prevented an attack against this user, they will probably be willing to forgive you for loosing their data.
Concerns and Points for Review
Concerns:
Reliability – does the system create false positives and/or false negatives? If so how and can you suggest a fix?
Scalability – does the system work as well on large or high traffic applications as it does on small or low traffic applications? If not why and can you suggest a fix?
Compatibility – does the system work under other versions of php & mysql? If not which ones and can you suggest a fix?
Refresh Errors – if you refresh two times before the code can complete it creates a situation where, while you are a valid user your token does not match the database token. This could create problems with people using their back buttons if the site is set up for no cache. If anyone has ideas on how to fix this I would be very grateful.[/list=1]
Points for Review:
User Friendliness – is there solutions to the security problems that have a smaller impact on user friendliness? If so, what are they?
Performance – can this be made to run faster? If so, how?
Ease of use – how difficult (1 – 10) is it to set this up on a new and an existing site? If you have difficulties, what are they and can you suggest corrections?
If you are using different versions of MySQL (4.0.20) and PHP (4.3.8) then I am and this runs on your server please let me know so I can add them to the tested environments list.
[/list=1]
Thank you for taking the time to look this over for me.
Edit: Added AES encryption to the data in the database