1

I'm building a users system plugin for a framework but the way I've currently set it up does not satisfy me. When the 'remember me' box is checked I create a cookie

setcookie('rmb', md5('salt'.$id), ...);

There are a few things I don't like about this. When I recreate a session from this cookie I do the following

$db->prepare('SELECT id FROM users WHERE md5(CONCAT("salt",id)) = ?')
   ->execute([$_COOKIE['rmb']])
   ->fetch();

Which seems alright but if I explain the query this is what I get

enter image description here

Highly inefficient, may run for hours, potentially. Apart from hashing with md5 being extremely insecure this system really doesn't seem reliable. Could you guys give me some pointers on how I can identify a user from a remember-me cookie hash efficiently and securely?

php_nub_qq
  • 15,199
  • 21
  • 74
  • 144
  • 5
    On a side note: your sql does not produce the same string as your php. – knittl Jan 05 '14 at 14:42
  • `md5(CONCAT("salt",id)) = ?` is going to return _all_ users when any one matches, no? That's equivalent to `WHERE 1=1` when a hash is matched. To identify any one user, you would need to be comparing that hash to a column value rather than a computed scalar. – Michael Berkowski Jan 05 '14 at 14:55

1 Answers1

3

I think you can just create a challenge that the client should send as a cookie in subsequent requests. When the user logs in:

setcookie('username', put_username_here, ...);
setcookie('challenge', long_random_char_sequence, ...); 
// UPDATE users SET challenge = ... WHERE username = ...

When the user connects again something like:

// SELECT ... FROM users WHERE username = $_COOKIE['username'] AND challenge = $_COOKIE['challenge']

This won't compile, there is no input sanitization, etc... It's just the workflow you may try to implement.

If you want to do even better, see this.

Community
  • 1
  • 1
gd1
  • 11,300
  • 7
  • 49
  • 88