Skip to main content
gamedev.net
🔒 Locked 🤖 Godot

[web] PHP, sessions and security

Started by Evil Steve 23 replies 6.7k views
Original Post
Evil Steve
Evil Steve
Hi all, I'm writing my own forum software, and I'm having a few issues with sessions. I'm using PHP sessions for logging users in, and keeping them logged in. The way I do this is, when a user logs in I check username and password, then store their user ID in $_SESSION. On each page, I call session_start(), then check to see if $_SESSION['uid'] is set, and if so then I grab that user from the database and use them as the active user. My questions are: 1) Is this secure? It just seems a bit horrible for me to be storing the user ID and then assuming it's correct. Is there not any way a user can fake the $_SESSION variable and log in as another user? 2) This requires cookies to be enabled, correct? And if so, is it worthwhile implementing some method that doesn't require cookies? 3) I see PHPBB doesn't use PHP sessions, it does it all manually. Anyone know if there's a good reason for this? Cheers, Steve
tstrimp
tstrimp
I'm pretty sure that PHP sessions just store a Session ID in the cookies and pulls the real session data from a database or flatfile of some sort. If someone were to get your Session ID and set it as their own, they might get access to the user secured information. If you're setting this up on a shared hosting environment, I believe session data is stored in /tmp and anyone else on the shared server could potentially get access to your session data. With access to that it would be fairly easy for someone to see what kind of information you're storing in the session and based on that, create or modify their own session on the server in order to log in to your system with false credentials.

As far as doing it without cookies, you'd have to create a hash of some sort based on their IP and browser info, both which are easy to spoof, or keep their 'session id' in the URL which is even easier to read then in a cookie.

All that said, I usually just use the $_SESSION variables.
benryves
benryves
I use your simple $_SESSION['uid'] method, but also keep track of a few bits of information (their browser type and IP address hashed along with a password) and if this changes after they log on then their session is cleared as a crude defense against session hijacking. (Session hijacking is the term you might want to look up - there is a vast amount of information on this topic). IP addresses are not exactly bullet-proof (two people on a work network could share the same IP, or the remote IP might change depending on ISPs).

The only security issue I've had thus far was using a particular page you could view other user's details - and by looking at their details you'd end up logged in as that user. This, however, was simply because register_globals was enabled and setting the local variable $uid was also overwriting the value in $_SESSION['uid'].
[Website] [+++ Divide By Cucumber Error. Please Reinstall Universe And Reboot +++]
Evil Steve
Evil Steve
Awesome, that's all good to know, thanks. Any ideas about #3? One person told me "Because it's a bloated piece of s*it" [smile]
tstrimp
tstrimp
Isn't PHPBB notorious for having security problems? I wouldn't base any decisions on what they have implemented.
intransigent-seal
intransigent-seal
Quote:
Original post by Evil Steve
Awesome, that's all good to know, thanks. Any ideas about #3? One person told me "Because it's a bloated piece of s*it" [smile]

Reasons phpBB might do it are:

  • PHP hasn't always had built in session support; maybe it's a hold-over from an earlier incarnation.

  • If the server is set up wrong, it can break the built in session support (for example, when I tested a PHP based website on the sourceforge project web servers, I found that session support was disabled/broken, so I had to write a session data handler to put all the session data into MySQL instead).

  • For servers that host several sites (ie, most of them), there will only be a single location used to store session data, and it will be readable and writable by the user under which PHP is running (or for slightly less well run web-hosts, it will be world readable/writable). This means that anyone else with hosting on that machine can write a script to access or edit that session data. That is of course a security hazard (although really, it's pretty hard to set up a server to have multiple virtual hosts and maintain security between them - insecure session data isn't really the biggest problem)

  • PHP can be configured to not use cookies to pass session IDs, or to try using cookies and fall back if they don't work. The alternative/fall-back is for PHP to scan the HTML that you're emitting, and modify any tags that contain links so that it can add the session ID to the query string. Personally, I've always found this to be a big pain in the butt, and very unreliable. You have some measure of control over it through the PHP configuration, but you just can't get the same amount of control that you'd get by doing it manually.


So the simple answer is: phpBB includes its own session handling code because PHP sessions are highly dependant on the server being configured correctly for the situation, and that just isn't something that can be relied upon for a piece of software designed to just start up and work correctly on almost any server.

John B
The best thing about the internet is the way people with no experience or qualifications can pretend to be completely superior to other people who have no experience or qualifications.
Evil Steve
Evil Steve
Quote:
Original post by tstrimp
Isn't PHPBB notorious for having security problems? I wouldn't base any decisions on what they have implemented.
Good point [smile]
Sander
Sander
Quote:
Original post by tstrimp
Isn't PHPBB notorious for having security problems? I wouldn't base any decisions on what they have implemented.


phpBB is mostly notorious for older versions being exploited, and vast masses of users not running the latest versions because the modified their forum's code (phpBB 2.x does not have a plugin system for modifications). Someone once wrote a worm that exploited some older versions. If you run phpBB you should upgrade when a new version is released. Collary: don't modify your forum's code (much).
Wan
Wan
Quote:
Original post by Pete Michaud
What you might want to do is store a login hash, that way you don't need to have a password in the session directly, but you can still verify credentials.

You should never store a password in the session.

What would be the point of that anyway? You only log in once, after that the newly created session can be identified using its session id (which in turn can be stored in the database together with other information like the user's ip address, to increase security).
markadrake
markadrake
Since I'm commonly setting up web sites with a CubeCart installation for e-commerce (not all the time, but CubeCart gets the job done for 85% of anything you need to sell) I've incorporated the same session administration feature into the web site and the content management / backend of the web site as well - so if the need arises, logged in users to the web site will not have to re-register at the store section.

They handle it the same way as you, however they regenerate the session id at login.You also want to look into using mysql_real_escape to prevent sql injection attacks.

There's a lot more you can do to 'be on the safe side'. Give your sessions a timeout variable and update it each time they hit the next page and the timeout hasn't occured.

http://phpsec.org/projects/guide/4.html

http://www.devshed.com/c/a/PHP/Creating-a-Secure-PHP-Login-Script/
markadrake
markadrake
Oh, use the md5 or sha1 function on the password before storing it in the database, then compare passwords by applying the function before the sql syntax. It computes the given password to a hash value. The point? You're database is leaked and they get a large list of hashes and usernames instead of usernames and passwords. It'll provide you the time to go through and change all the passwords quickly so that your customer's information is not leaked.
Evil Steve
Evil Steve
Yeah, I've been storing SHA-1 hashes in my database, and I'm sure to escape strings properly before putting them anywhere near the DB.

I might do the session timeout, but I think that might be a bit annoying for some users. My forums don't need to be ultra-secure and I think it's unlikely that anyone will try session hijacking.
Sander
Sander
Quote:
Oh, use the md5 or sha1 function on the password before storing it in the database


I recommend something tougher. MD5 hashes for (short) passwords are easily recoverable with the help of rainbow tables. Take a look at the hash functions to see what's available. MD5's good enough for e.g. a blog or a forum which are not interesting for a hacker to steal and run through rainbow tables, but you should push for the best when dealing with e-commerce or other sensitive (private) data.
deadimp
deadimp
One thing about storing session ID's in the URI: What happens when a malicious user links to the site, and gets the ID using the referrer? Though, it'd be unlikely someone would go through the trouble to do this, and unlikely that they'd be monitoring the data gathered from potential victims.

I'm currently designing a CMS, Thacmus, and the user security is very basic - essentially what markadrake and others have stated: I just store the username and password (hashed with md5) in the session. However, looking at Sander's suggestion, I might change that some.
I can't say the security's really been tested in the real world, I've only released it recently, and there's been only a couple or so unique visitors to the website running the CMS.

I might be designing a forum using Thacmus later, but I don't think I'd worry about users with cookies disabled. Not every user base can be covered.
Projects:> Thacmus - CMS (PHP 5, MySQL)Paused:> dgi> MegaMan X Crossfire
Sander
Sander
Quote:
I just store the username and password (hashed with md5) in the session.


Listen to benryves and also store the user's IP address and user-agent string in the session table. When you get a session ID simply check that the first 3 parts of the IP address(*) and the user-agent string are still the same as what you stored in your session table. If not, silently destroy the session and create a new one.

(*) Matching only the first 3 parts, e.g. 192.169.1.* ensures that people using a broken ISP that reroutes traffic through different proxies on each request (e.g. AOL, some dial-in ISP's) can still match their sessions.
markadrake
markadrake
I noticed everyone's replies hit all of my points except session regeneration at login.

Sander - thanks for the link. But it doesn't necessarily say which is strongest of the available types. It's also 3 am and I'm feeling the inevitable keyboard / face-smack that will occur soon.
demonkoryu
demonkoryu
Ok, here is how you do a secure login without HTTPS:

0. Use session_set_save_handler() to implement secure session storage (maybe in a database) or session_save_path() to use another directory than /tmp.
1. In the login form, have a hidden field with some random value set by the server.
2. The client will use hex_md5(key) on the password and then hex_hmac_md5(hiddenkey, crypted_password) on the result and send it to the server.
3. The server uses the same algorithm to validate against the database of login users.
4. (Assuming validated) Set $_SESSION['login_user'] to the value of the logged in user and don't care anymore. Use session_regenerate_id() to invalidate the session id.
5. ...
5. Profit! =)
Nice Coder
Nice Coder
Quote:
Original post by Sander
Quote:
Oh, use the md5 or sha1 function on the password before storing it in the database


I recommend something tougher. MD5 hashes for (short) passwords are easily recoverable with the help of rainbow tables. Take a look at the hash functions to see what's available. MD5's good enough for e.g. a blog or a forum which are not interesting for a hacker to steal and run through rainbow tables, but you should push for the best when dealing with e-commerce or other sensitive (private) data.


Unsalted md5 can be recovered quickly through rainbowtables, usually within a few minutes. (maybe hours)

However, store a salt value, and use it.

ie. caluclate sha1(salt ^ md5(password)) with a 128 bit salt. You store the salt as an additional field.

This is surprisingly secure against attack. (brute force/dictionary attacks are the ony things that can put a dent in, however any precomputed attack (time/memory tradeoffs like rainbowtables, ktables, etc.) are foiled.)

Also, you could create a derived key from the password and username (ie. sha1(md5(username) ^ md5(password)))), and encrypt your sensitive data with that when needed. (if you have anything that sensitive).
Click here to patch the mozilla IDN exploit, or click Here then type in Network.enableidn and set its value to false. Restart the browser for the patches to work.
AndreTheGiant
AndreTheGiant
Im just beginning with PHP so this topic is pretty interesting to me. Forgive me if this is naive, but what is wrong with the following security model:


1) On the login page, gather their username and password.
2) Compare these with the USERPASS table in the database.
3) If the login is valid, generate a Big Random String (BRS) and store it in the SESSION table in the database. Also return the BRS to the login page.
4) For every secure page on your site, check that the BRS (passed on GET or POST) is in the SESSION table. If it is, you know its a valid user.
5) When the user logs out, or times out or whatever, remove the BRS from the SESSION table.

This doesnt use Cookies, or the Session PHP utility, but It does of course use mySQL.

Comments?

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.