SitePoint Sponsor

User Tag List

Results 1 to 10 of 10
  1. #1
    SitePoint Wizard wheeler's Avatar
    Join Date
    Mar 2006
    Location
    Gold Coast, Australia
    Posts
    1,369
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Cookie / Remember Me logic

    just thinking about having a "remember me" option on a login form for the first time. Let me see if I have this right (and whether it will work):

    1. user logs in with correct details and selects "remember me"
    2. run login script, set $_SESSION and $_COOKIE (for say 1 year)
    3. add to cookie a hash (probably md5 + salt) of the username and password, which will be stored in the user table for future reference
    4. if the person logs out, do not clear the cookie
    5. upon returning to site, IF a session is not set:
    a) check for existence of cookie
    b) if cookie exists, check database for corresponding value
    c) if match found, set $_SESSION as usual
    d) if no cookie or no match, do not login.

    Sound good?
    Studiotime - Time Management for Web Developers
    to-do's, messages, invoicing, reporting - 30 day free trial!
    Thomas Multimedia Web Development

  2. #2
    SitePoint Enthusiast
    Join Date
    Sep 2001
    Location
    California
    Posts
    29
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    4. if the person logs out, do not clear the cookie
    Most people assume that when they log out all cookies are being cleared.

  3. #3
    Worship the Krome kromey's Avatar
    Join Date
    Sep 2006
    Location
    Fairbanks, AK
    Posts
    1,621
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Agreed, an explicit logout should delete any "remember me" settings.

    Also, never put sensitive information into a cookie, even encrypted. Encryption of any kind, even one-way hashes like MD5, can be broken and the underlying data retrieved. Better would be to store a random token that you store in your database and in the cookie. Compare this token with the database when the user returns, and log them in if they match.

    Also, you may want to set up a table to deal solely with "remember me" tokens. Because unless you want to restrict each user to being remembered on a single machine only (which users are not going to expect and will thus be confused when saying "remember me" at work logs them out at home and vice versa), you're going to have a many-to-one relationship of tokens to users. Unless you use the same token for each user's "remember me" cookies, which is a bad idea because if a user decides to be "forgotten" at a computer (maybe their work computer is being reassigned to someone else) then all you really have to do is delete the token from your database and that token is securely destroyed. This makes things more secure, because it reduces the possibility of someone acquiring this "remember me" token and using it to log in.

    This also brings up another point: "remember me" settings are inherently insecure, and thus you should always revalidate your users (i.e. ask them to confirm their password) before even showing options such as changing password or e-mail or really anything else related to the user's account settings.
    PHP questions? RTFM
    MySQL questions? RTFM

  4. #4
    SitePoint Wizard wheeler's Avatar
    Join Date
    Mar 2006
    Location
    Gold Coast, Australia
    Posts
    1,369
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    ok thanks for the (very speedy) advice. so:

    - clear the cookie on logout (they have to navigate away or close browser to retain cookie)

    - store a random token rather than user/pass hash (makes sense if i'm going to store the hash anyway)

    - store tokens in a remember me table, potentially storing more than one per user (although they will initially still need to "remember me" on the first instance of using a different machine)

    - possibly use the cookie to give 'half-way' access so they will have to enter a password before doing anything important. In which case, perhaps I could just store the username in plaintext, and automatically fill out the username field for them? (unless I consider a username sensitive, hmmm)

    and what would you recommend I use to generate a unique token for everyone? The username and user_id are the only guaranteed unique fields for each user.
    Studiotime - Time Management for Web Developers
    to-do's, messages, invoicing, reporting - 30 day free trial!
    Thomas Multimedia Web Development

  5. #5
    Worship the Krome kromey's Avatar
    Join Date
    Sep 2006
    Location
    Fairbanks, AK
    Posts
    1,621
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by wheeler View Post
    - possibly use the cookie to give 'half-way' access so they will have to enter a password before doing anything important. In which case, perhaps I could just store the username in plaintext, and automatically fill out the username field for them? (unless I consider a username sensitive, hmmm)
    The way I (and most sites I've used that do this double-level of validation) implement this is to keep a short timeout "verified" flag. That is, any time the user directly enters their password (on login, on verification), start a 15-minute window where they are treated as "verified" and thus allowed to do anything you deem "sensitive", e.g. change e-mail address or really even view account settings. When that 15-minute window expires, they have to again re-enter their password to get to their account settings. (If 15 minutes is too short, lengthen it; the point is that it is a limited window, thus preventing someone who manages to steal the "remember me" token from completely hijacking your user's account.)

    Quote Originally Posted by wheeler View Post
    and what would you recommend I use to generate a unique token for everyone? The username and user_id are the only guaranteed unique fields for each user.
    Code PHP:
    $uniqid = sprintf( "%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
           mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),
           mt_rand( 0, 0x0fff ) | 0x4000,
           mt_rand( 0, 0x3fff ) | 0x8000,
           mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ) );
    Credit for this code snippet belongs to someone on SitePoint, but I can't recall for sure. This follows the standard for universally unique identifers (UUID), hence the strange bitwise ORs in there (the '|' characters). This string is 36 bytes long, only 4 bytes longer than an MD5 hash. The randomness involved is such that there is a virtually 0% probability of this string ever being identical to a previously generated string (hence the usage as a UUID). Generate this token, store it in your database along with the userid (or username, whatever you use for the primary key in your user table), and then put it in the cookie.
    PHP questions? RTFM
    MySQL questions? RTFM

  6. #6
    SitePoint Wizard wheeler's Avatar
    Join Date
    Mar 2006
    Location
    Gold Coast, Australia
    Posts
    1,369
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    thanks kromey, that code snippet is really something!

    For me, I tend to rely on the sessions expiration (usually set to around 15 minutes) to do the timeout stuff. That is because in most cases, the user requires to stay logged in as the navigate around the site and do various things. It is not a case that they will quickly do one sensitive action and then leave.
    Studiotime - Time Management for Web Developers
    to-do's, messages, invoicing, reporting - 30 day free trial!
    Thomas Multimedia Web Development

  7. #7
    Worship the Krome kromey's Avatar
    Join Date
    Sep 2006
    Location
    Fairbanks, AK
    Posts
    1,621
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    The problem with the session timeout is that it is regenerated on each page load. The timeout I'm referring to would only regenerate when the user enters their password. You could easily do this by storing a session variable when the user enters their password:
    PHP Code:
    $_SESSION['auth_until'] = time() + 15*60//15 minutes from now 
    Then simply check if $_SESSION['auth_until'] > time(); if it is, then the user is still verified.

    Since you're using "remember me" functionality, the standard rules for session expiration break horribly (i.e. there effectively is no expiration) and thus you can't rely upon them. Although in point of fact I do use a similar 15-minute window on sites that don't use a "remember me" feature to help mitigate the damage of a successful session hijacking (that is, even after a user logs in they have to effectively log in again to do anything with their account settings).

    Edit: I'm not at all advocating that you log a user out when the auth_until timeout is reached, merely that you block access to sensitive information such as account settings until the user re-enters their password, at which point you refresh their auth_until timeout.
    PHP questions? RTFM
    MySQL questions? RTFM

  8. #8
    SitePoint Wizard wheeler's Avatar
    Join Date
    Mar 2006
    Location
    Gold Coast, Australia
    Posts
    1,369
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I guess what your speaking of is similar to the premise of for example, going to edit-account-details.php and that page requiring the current password be entered before the changes are saved.

    I guess this whole scenario of session security is a fine line between keeping members happy (not annoyed at frequent password prompts) and verifying that they are who they say they are....

    the $_SESSION['auth_until'] example is an interesting prospect, especially for something like preventing bid flooding in an auction scenario or perhaps brute force login attempts...
    Studiotime - Time Management for Web Developers
    to-do's, messages, invoicing, reporting - 30 day free trial!
    Thomas Multimedia Web Development

  9. #9
    Worship the Krome kromey's Avatar
    Join Date
    Sep 2006
    Location
    Fairbanks, AK
    Posts
    1,621
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by wheeler View Post
    I guess what your speaking of is similar to the premise of for example, going to edit-account-details.php and that page requiring the current password be entered before the changes are saved.
    That is in fact exactly what I'm referring to. Since you are in effect allowing users to log in without ever verifying who they are (okay, they happen to have the proper "remember me" cookie, but cookies can be stolen quite easily), you do need to verify who they are before you offer up sensitive information. Users are quite used to this kind of thing, so I highly doubt you'll drive anyone away, especially if when ask you them to verify who they are you include a "Why?" link/button that tells them that you care about their security and privacy; check out Yahoo's "Why am I being asked for my password?" when you try to access your account settings.
    PHP questions? RTFM
    MySQL questions? RTFM

  10. #10
    SitePoint Member
    Join Date
    Nov 2005
    Location
    Sweden
    Posts
    1
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kromey View Post
    Compare this token with the database when the user returns, and log them in if they match.
    What is the best way to compare the tokens an let the user in if they match?


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •