Do you need to encrypt session data?

  • I came across a session management class in PHP which encrypts session data in the session storage folder (i.e., /tmp) and can be decrypted later in your script using a key. I was wondering if it's really needed? If you already doing some session hijacking prevention like this (simplified) example:

    session_start();
    
    if (isset($_SESSION['fingerprint']))
        if ($_SESSION['fingerprint'] != md5($_SERVER['HTTP_USER_AGENT'].'SECRETSALT'))          
            exit; // prompt for password
    else
        $_SESSION['fingerprint'] = md5($_SERVER['HTTP_USER_AGENT'].'SECRETSALT');
    

    Do you still need to encrypt your session data? Or is encryption only needed if you are storing sensitive info via sessions (e.g., personal info, cc number, credentials) ?

    Moreover, if you are validating whether a user is logged-in or not in a simple way like this:

    // login.php

    if ($_POST['password'] == $db_password)
    {
        $_SESSION['logged_in'] = true;
        redirect_to_protected_area();
    }
    else
        // show login again
    

    // protected_area.php

    if (!isset($_SESSION['logged_in']) OR !$_SESSION['logged_in'])
        exit; // prompt for password
    else
        // show protected area
    

    What damage can be done if session data is unencrypted and a hacker saw the data in plain sight (i.e., the md5 hash of the fingerprint and the logged_in = true). Can he actually log himself in or he must first "crack" the md5?

    Note: md5 was used to simplify example, a much better hashing algo is used in real life.

    @curiousguy What do you mean? If you mean `/tmp`then `/tmp` is PHP's default session folder in a shared hosting environment.

    Sorry I wasn't clear. Is `/tmp` written on disk storage? Is it a `tmpfs` filesystem?

    @curiousguy I am not sure what `tmpfs` is but `/tmp` is usually just a regular folder in windows or linux. More info about it here: http://www.php.net/manual/en/session.configuration.php#ini.session.save-path

    I think IMB is talking about encrypting session data in `$_SESSION` so that attacks that read files in `/tmp` can't divulge user info.

    @Polynomial That's exactly what I mean. Do you think it's necessary to encrypt it if you're not storing sensitive info in the session data?

  • Polynomial

    Polynomial Correct answer

    9 years ago

    Encrypting your session data in PHP is a bit like locking your car and leaving your keys on the roof. Consider the threat scenarios that apply:

    1. An attacker gains some remote access to the server and attempts to read the session data files.
    2. An attacker steals the server's entire hard disk from the datacenter. This could be through physical theft or through accessing a virtual hard disk file in a virtualised environment.

    In the first scenario, the attacker needs to gain access to the server, then either privilege escalate to root or impersonate the user that owns the session data directory (e.g. www-data for Apache, nobody for nginx). These directories have access controls applied (usually 0600 permissions bits) that prevent users other than the owner from accessing the data.

    If an attacker already has access to the server and can impersonate the user that the web server daemon is running under, then they can by definition access all of the data that the web server process can access, meaning that they by definition would have access to any encryption keys that the web server or the code running under it might be using (with the exception of a HSM, although that it isn't a reasonable assumption that one would be in use here).

    This means that if the attacker can read the session data files, they can also read the encryption keys, which means they can decrypt the session data. The encryption ends up being obfuscation at best.

    In the second scenario, the same issue applies: if the key is on the hard disk along with the session data, an attacker can simply read the keys and decrypt the session data. The way to resolve this problem is by encrypting the session data in such a way that the keys are not stored on disk, and the correct approach is to use full-disk encryption (FDE) and manually enter the password at boot using out-of-band management (e.g. iLO, DRAC, remote KVM, etc.) so that the entire hard disk is encrypted in such a way that does not allow an attacker to gain access to any data on the disk if it is stolen.

    However, even in this scenario, it may turn out that FDE isn't that much of a security gain in terms of protecting session data. The reason is that, on most platforms and configurations, session data is stored in /tmp, which is backed by a tmpfs volume. The whole point of tmpfs is that it is volatile (i.e. the data is lost on reboot) and in most cases the contents are stored in RAM. Data that is not touched for quite some time may be swapped out to disk, which is where FDE does provide a benefit towards securing session data, but the likelihood is that any old sessions will have expired before this happens. That being said, I still recommend the use of FDE on all systems as part of good security practice, because it protects against other types of data theft (e.g. infrastructure credentials, SSL certificate private keys, etc.)

    The only situation in which encrypting session data in PHP makes some sense is if you have session data being stored in a database or key-value store. In this scenario you should expect that the session data will likely be nonvolatile (i.e. stored on disk) and that there might be a situation in which an attacker compromises the database (e.g. getting into an overlooked phpMyAdmin instance) but not the filesystem. In such a case the key would be on the filesystem and inaccessible to the attacker. This is, however, an exceedingly rare case.

    One other argument I hear a lot is that certain data must be encrypted for compliance reasons, e.g. PAN data under PCI-DSS. The solutions here depend upon the exact system architecture, but generally speaking you fix this by either not storing the data in the session data at all, by encrypting/decrypting the data using an external broker/HSM so that the keys are isolated, or simply with FDE if you only require offline encryption of data at rest.

    While I don't generally recommend it for the reasons that are discussed above, if you're set on encrypting session data in PHP for whatever reason, it's actually quite possible to do it within PHP without modifying every use of $_SESSION. You can use the SessionHandler class to override normal handling of sessions. The documentation provides a simple explanation of how you can encrypt session data.

    However, you'll need a way of creating and storing the key across the session. Obviously this can't be done through the session manager itself, otherwise you'd be distributing the key with the ciphertext. My suggestion would to be use an in-memory cache, such as APC or memcache, where the key name in the cache is the session ID.

    Thanks, BTW here's an example of the script I'm talking about http://www.zimuel.it/en/encrypt-php-session-data/ it's unclear what's his purpose. Maybe he's storing sensitive info in sessions? He stores the key in the user cookie and encrypted data remains in `/tmp` (or the designated session path). Regardless, my question is more on why is it necessary to encrypt it? For example, if I don't encrypt data and if `/tmp` was compromised, an attacker really can't do anything with it right as long as there is session hijacking prevention?

    They might still extract personal / sensitive information in `$_SESSION`, and session hijacking prevention isn't 100% effective. For example, if you lock sessions to IP addresses, an attacker could still steal the session from the same network as the user. It's a corner case, but if you're using the `SessionHandler` class there's almost no added complexity.

    Ok you mention `personal / sensitive information`, so if I'm not storing this kind of info (i.e., I only store `loggedin = true`), then there's no need for encryption?

    Sure, it's completely unnecessary in that case.

    +1 It always bugs me when people want to add "encryption" to a system just because it sounds cool or it meets some compliance requirement. Encryption is -- at best -- only as secure as the key management.

    What if the key is stored on the same system in a safer place then for instance the `/tmp/` folder where the `$_SESSION` data might end up? If the for instance sensitive data was stored in the `$_SESSION` it would be potentially much more accessible the the key used for encryption? Aren't there hence cases where encryption of `$_SESSION` helps to protect the data?

    This comment flys in the face of https://owasp.org/www-project-cheat-sheets/cheatsheets/Session_Management_Cheat_Sheet.html which states that if the data which could be stored is in any way sensitive it should be protected.

    @jas- What it actually says is that the *session management repository* should be "encrypted and protected" if it is expected to contain any sensitive information. However, it does not elaborate and leaves you to build your own threat model. In order to get to the session data the attacker must have already compromised the server in some way, so any protection against that is inherently a protection of the session repo. The session directory is owned by the web user (e.g. `www-data` for Apache, `nobody` for nginx), usually with 0600 permissions, which is an additional access control.

    @jas- In terms of the encryption side of the threat model, we've already established that an attacker would need to gain access to the server under the context of the correct user to read the session database. As such, any encryption we would do inside PHP (or whatever other language you're using) would necessarily require that the web server could access the keys, meaning that an attacker who compromised the server would *also* be able to access the keys, rendering the session encryption pointless.

    @jas- Where encryption is useful is in the scenario of disk theft, but encryption *only* works here if you're not storing the keys on the disk too. This means that any encryption you do at the application layer isn't useful, because an attacker who steals the disk can just read the keys off the disk. Instead, you need full-disk encryption (FDE) on the server, with the key being manually entered at boot via remote management (e.g. iLO, DRAC, remote KVM). This is a default recommendation that transcends the issue of session management.

    @jas- That being said, I agree that in hindsight my answer was poorly written (the benefit of 8 years additional experience!) and I'll do a rewrite to cover more of the details.

License under CC-BY-SA with attribution


Content dated before 7/24/2021 11:53 AM