0

I'm currently doing this:

function setlogincookie($user_id) {
    $user_id = $user_id;

    $day = new DateTime('+1 day');
    setcookie('session','1',$day->getTimestamp(), $user_id, null, null, true);
}

But it stores the User's ID as plain text. How can I make it show a random integer but can be still read as logged in as user 1? Could I use a password_hash for it then verify it later on in the code? Or is there a better method.

Gumbo
  • 594,236
  • 102
  • 740
  • 814
Sam Carre
  • 1
  • 1
  • Why not use sessions rather than cookies? This will store a cookie on the browser to the session data on the server. The user id won't be on the client's computer, just the ID to the data on the server. – chris85 Oct 25 '15 at 17:36
  • What you want is called `encryption`. – Federkun Oct 25 '15 at 17:36
  • Do it this way: When a user logs in, generate a random hash and save this hash in your DB. In the cookie, you save the same hash. Now you can check, which user just tries to access your website and you don't have to store the userid in a cookie – Reeno Oct 25 '15 at 17:37
  • That's what I want! Alright thanks for the help! :D – Sam Carre Oct 25 '15 at 17:38
  • No, they aren't deprecated. If you mean brute forcing them though then take a look here, http://security.stackexchange.com/questions/81519/session-hijacking-through-sessionid-brute-forcing-possible. – chris85 Oct 25 '15 at 17:39
  • Sessions aren't deprecated and probably never will be. And if you implement them in the right way, they aren't insecure. – Reeno Oct 25 '15 at 17:40
  • Maybe this will help: http://stackoverflow.com/questions/549/the-definitive-guide-to-form-based-website-authentication – Reeno Oct 25 '15 at 17:40
  • Thank you all for your help but I'm going for Reeno's method. – Sam Carre Oct 25 '15 at 17:42
  • Do you *really* need to stop the user from ever finding out their own ID? Or do you just need to stop them from changing it? If you only need to authenticate and not encrypt then this is all much easier, you can just sign the ID with a server-side secret key and HMAC. Either way, there are some other things you should consider putting in your signed (and possibly encrypted) token, such as expiry and user password status, so you can revoke a token when the user changes their password or after a certain amount of time. Otherwise the cookie is valid forever, which is risky. – bobince Oct 26 '15 at 14:14

2 Answers2

1

You mean like a long-term "remember me" authentication cookie? A random token and a lookup table is generally the best way to approach that. (The linked article also delves into some "proactively secure" strategies.) I made a similar argument in favor of random tokens rather than cryptography features when discussing URL parameter encryption, and touched on it when discussing PHP session security.

Let's look more broadly: You want to store information in a cookie (which the user can spoof/tamper with as they please). You don't want the user to be able to, upon changing the cookie, get any meaningful/useful result. (Ideally, your code would just go, "This isn't right," and treat them as unauthenticated.)

The answer is to use authenticated encryption. There are two libraries that offer a simple and easy way to satisfy this (disclaimer: I contribute to both, so you should ask a cryptography expert before thinking about using either).

Halite

Halite (first stable release coming soon) is a PHP library that wraps the PHP bindings for libsodium to make it easier to use. One of the classes it comes with out of the box is, quite simply, \ParagonIE\Halite\Cookie.

Note that Halite requires the PHP extension for libsodium (available in PECL). If that's a no-go, then you probably want...

Defuse Security's PHP Encryption Library

Most commonly known by its name on Packagist, defuse/php-encryption, this works out-of-the-box with PHP 5.4+.

Version 2 is coming out soon, but if you need a solution today, grab version 1.2.1 and simply do this:

$enc_key = Crypto::CreateNewRandomKey(); // Store me!

// Storing a cookie:
setcookie(
    'name', 
    Crypto::binToHex(Crypto::encrypt($value, $enc_key))
    // other parameters
);

// Reading a cookie
try {
    $cdata = Crypto::decrypt(
        Crypto::hexToBin($_COOKIE['name']),
        $enc_key
    );
} catch (Exception $e) {
    $cdata = null;
}
Scott Arciszewski
  • 30,409
  • 16
  • 85
  • 198
0

Use JSON Web Tokens.

This will enable whatever is in the token to be authenticated by a MAC with a private key only stored server side. Encryption is not necessary, as the MAC will prevent the User ID from being changed as an attacker will not have the private key in order to authenticate their own changes.

Ensure that the "payload data" contains enough about the user session and its intention of use to make it meaningful. That is, do not simply store the User ID in isolation, as an attacker may be able to use a JWT from elsewhere in your app to impersonate the User ID if all you were storing was a number. Always include an expiry date to prevent a JWT being saved indefinitely.

SilverlightFox
  • 28,804
  • 10
  • 63
  • 132