Securing my Users Login

Hi All,

I have recently been looking at the way that some of my systems handle doing a user login, and I have been cleaning them up to make them a little quicker, using less database queries where only one would do, and generally giving it a bit of a spring clean. However, in doing so, I am trying to find a way of securing the actual login mechanism - and me being overly paranoid was wandering how everybody else goes about securing these sessions, and checking if they are valid. My solution was pretty poor - relying on one hash that somebody could copy. So, I’m coming up with different ideas at the moment, and am taking a read of PHP Architects Guide to PHP Security for starters - but how does everyone else go about doing this - and what comes from the user, for example a cookie, and what is this checked against?

or just a man-in-the-middle attack.

You develop your own mechanism hash technique. Here is an example:

  1. Grab the user id, make a constant key, and maybe something else.

  2. Concatenate all those together and hash it (basically you would be creating a salted hash).


class User {
  private $id;
  const KEY = '[\\ewf|446#$#$#F$184/*//d3./.s"[';
  const WE = 'w4334ER*G#E!R@G5wd*5(7_8d=/eklej';

  public function createToken() {
    return md5($this->id . self::KEY . self::WE);
  }
}

It’s just a basic token logic. An outside user would need to know the constants/order/etc in order to get the same exact token.

You can’t reply on an IP as a user’s ISP will/may travel through a set of clusters and take a different route of clusters in their next request, giving them a new IP.

User agent is another common pitfall. It pretty much goes through the same mechanism as the IP issue although less common.

Your best shot is a cookie. You can set a cookie with an encrypted token and it must match based on your application/DB/etc. You can have it expire after a certain amount of time (if the user goes idle for example).

If you do continue to use sessions, you need to take care of session fixation. It’s simple enough to take care of, by using the session_regenerate_id() function.

The problem with a cookie is that it can be spoofed as easily as the rest of the request. In fact IP is the only part which cannot be easily faked. The correct way to handle the case where their ip changes, is a) to use only the first 2 or 3 octects and b) present them with a password box to get them confirm when they change, and inform them why they’re being asked. They should appreciate the level of security.

So, whilst cookie seems to be the best way, how should I look into doing this? Is one cookie enough based on a random hash of a set of components - and should my application be able to make this again on the fly, or does that leave it more insecure than a key that can be made once, thrown away, and then just queried against the database? I’m just worried of somebody taking the cookie with them - or am I missing the point of a cookie? Basically, I’m just concerned that Fred is going to somehow find a hash in a cookie that makes him become Joe.

Nope, it’s not that much of a concern - I just wanted to make sure I had my understanding correct before I imparted further information, and they learnt it wrong and so forth - as well as for my own peace of mind. I know that once we have a hash that is randomly generated the risk of somebody taking control by guessing is again minimized, and is pretty much almost there security wise apart from end users and their pesky machines. Whilst projects I am working on now don’t require a high degree of security - I’m not handling anything sensitive - I wanted to make sure I was correct for any future projects. Thanks everyone for their guidance. It seems my paranoia was a little off, in all then!

Yes, you are correct. If packet sniffer is a concern and such a level of security is needed, then you would need to run it through an SSL gateway.

But, what I’m getting at, and please correct me if my understanding is wrong, which it sounds like it me: Malicious user Joe may sniff Freds hash and create his own cookie / edit one (as browser cookie files are clear text files) for the site, giving him access to whatever it is Fred was doing - therefore how it was made is regardless, if he has a hash, and the authentication says, great, it exists - then it should be going ahead. Perhaps the issue is not creating the cookie - but in doing the check that the cookie is valid?

I’m probably way out of my league on this question, but here’s what I do…


$uniqueID = md5(uniqid(rand(),true));
$_SESSION['uniqueID'] = $uniqueID;

Add $uniqueID as a hidden field on the form.

In your code that handles the form submission, check to make sure $_SESSION[‘uniqueID’] equals the hidden field POST value.

If a user has a Trojan, that account is pretty much compromised as they can install a key logger and track down the user’s password.

With a packet sniffer, you’re not sending your hash technique back to the user, you are only sending the required hash.

It’s not the same salt. The id is suppose to represent an unique way of identifying the user (such as a primary key in a database).

Depending on the need of application, it may or may not require random hash.

You could create one long string constant to achieve the same affect. The name of the constants have no bearing in what the main example was to prove. In fact, I used WE as a shorthand of “whatever”.

Hashing it multiple times with an algorithm such as md5 can lead to vulnerabilities.

The amount of abstraction and security is up to the developer. At the end of the day, this is a BASIC example, as I posted above.

I’m not 100% sure I follow your reasoning here, but this shouldn’t be a concern. An IP won’t change during a session (a new source IP automatically requires a new TCP session negotiation, due to the way TCP works), and you shouldn’t care about IP addresses between sessions.

This is bad design. What you’re encouraging here is using the same salt for every user, which is a bad idea. If you have your heart set on multi-session authentication, a user’s salt should be randomly generated at the user’s first login, and stored in the database. Secondly, there’s no security benefit to having the WE and KEY constants set. Both are effectively serving the same purpose, and you could do the same thing simply by simply making those two one long string. Additionally, KEY is misleading, because it is in fact not the key to your encryption algorithm. The user ID is the key, what you’re calling a key is actually salt.

Finally, if you’re going to be doing something like this, you should probably (a) run the hashing function multiple times, appending the salt to the output of the function each time, and (b) be using something that isn’t as weak or fast as MD5.

Not true, in fact, quite the opposite; it’s the recommended action.

See http://en.wikipedia.org/wiki/Key_strengthening for more details. Not that you should be using MD5 anyway, it’s a much better idea to use an algorithm that isn’t on its death bed.

As for it being a simple example: just because it’s simple doesn’t mean it needs to be wrong. In fact, I’d go so far as to say that it should be the easiest type to get right.

Changing the hash associated with the session every page request coupled with a low expiration time would make the most predominant security issues non-existent.

If you create a sessionID and store it in the user’s record in the database, you can store it in a cookie and then check the cookie each time someone requests a page. In most cases, I don’t need to change the hash everytime, I simply set an expiration time (as appropriate for the site, but as short as possible) and save that in the database record with the sessionID. After a sessionID expires, the user will need to log in again, so you simply balance the convenience of long expirations against the security of short expirations and choose the right time for your site. This is a nice simple way to ensure a reasonably secure session for your users. Someone would need to guess one of your sessionIDs, or another user would need to get access to the same computer within the expiration window in order to compromise the site or gain access to anyone’s account.

If even that is not enough security (or if you are playing with long expirations), you store a random hash in the database along with the ID and the expiration, and then store it in the cookie with the sessionID. Now you not only check the sessionID to identify the user, but check the random hash. Now someone not only needs to locate a sessionID that exists and is in the window before its expiration, but you need to supply a random key (which functions like an automated random password).

That’s usually enough power for almost any scenario, however Cerium is right. This is completely useless against packet sniffing where the hacker has intercepted the HTTP request with the cookie contents inside. The only way to shut that down (as Cerium said) is to use SSL, this is the only way to encrypt the request itself. In that event a packet sniffer won’t read anything but gibberish.

The first two aren’t entirely usable for me: I hit a brick wall when one of my applications is in use behind two internet connections which are not persistant throughout the users session, logging them off. I also read somewhere that a proxy or people behind AOL (can’t remember which) masks the User Agent into something uniform (I’m sure I read something about User agents not being reliable). I’m not trying to say all your advice is rubbish, and I will take it on board and take another look at the U A stuff, seeing if I can source the article I first found / give it a test, but IP is a no no for me. I’ll take a look into suhoshin.

To help prevent session hijacking, you can check the consistency of the IP/Useragent for the user or install something like suhosin which does this for you and regenerate the session id on successful login. I’m sure there are others but these are the common methods :slight_smile:

SSL is probably the single best enhancement you could make, but it’s obviously not always feasible.

Yep. I’m doing something a little bit similar, in bringing together some random numbers, etc. so that even I do not know the key - which is where it can’t be recreated back on the fly. That looks like what I’ll be trying next, thanks for the inspiration and I’ll have a play. The only place it leaves a security issue now is the users machine - in case some form of Trojan / pack sniffer knows what my cookie hash is? In which case, theres nothing I can do about the end users security.