5

One particular web service that I am writing interfaces with an API. Each API call requires the user's username and password to be sent, no state is maintained.

Ideally, when using my web service the user will enter his API username and password once, and my web service will store that information until the session ends. I understand that I should not store the API password using PHP sessions nor in a database due to security concerns. Therefore, how can I securely store and access the password for the duration of the session?

Would it be secure to encrypt the password, store the encrypted password in a cookie and the encryption key in a session?

Note that I originally asked the question (without the proposed solution) on SO: https://stackoverflow.com/questions/15084025/storing-third-party-passwords-for-reuse-across-pages Had I drank coffee first, I would have known to post here instead of there. The SO post can be deleted, but not by me.

The answer given there is the one I am now using in production, so if there are flaws in the approach (store encrypted password in PHP session, encryption key in cookie) then I would very much like to know.

$encryptionKey = sha1(microtime(true).mt_rand(PHP_INT_MAX / 10, PHP_INT_MAX));
$encryptedPassword = mcrypt_encrypt(MCRYPT_BLOWFISH, $encryptionKey, $password, MCRYPT_MODE_CFB);
setcookie('atwood', $encryptionKey, 0);
$_SESSION['encryptedPassword'] = $encryptedPassword;

$password = mcrypt_decrypt(MCRYPT_BLOWFISH, $_COOKIE['atwood'], $_SESSION['encryptedPassword'], MCRYPT_MODE_CFB);

1 Answer 1

5

The question to ask is: what is the security model here ?

You apparently need to transmit the user password (a sensitive piece of data) from the user to the back-end servers. But the timing matters: the human user enters his password once, at the beginning of what the user thinks of as "the session", and the password must be transmitted at later times to the back-end (the "API calls"). So there must be some storage somewhere.

PHP sessions are server-side storage, as a collection of small files with time-based expiry. What you write in a "session variable" ultimately goes to the hard disk. Therefore, it could be considered as bad form to store a plain password in a session variable, because hard disk physical contents are not reliably destroyed when the file is deleted (upon deletion, the storage area dedicated to the file is marked as reusable, but the data itself won't be overwritten until the area is indeed reused for another file). But there are details:

  • If you fear a data leak through post-mortem access to an old disk (or a backup tape), then what you want to avoid sending the file to the physical medium. Some people put the PHP session files on a RAM disk: the RAM disk is setup with the OS facilities for such things, and the path to it is adjusted with session_save_path(). Files in a RAM disk never make it to physical storage, so the leak is adverted. On the other hand, all sessions will be lost if the server reboots (this is probably tolerable, but it depends on the setup). Sharing the session across multiple front-ends would also be more complex.

    Note: on Linux systems, there are three ways to create RAM disks: the "true" RAM disks (size up to 16 MB each, adjusted at boot time), "ramfs" and "tmpfs". This last one will use RAM but also swap space, so contents may still hit the disk. See this page for some details.

  • If you fear leakage of session data through a live hack of your server, then consider that someone who could get read access to some OS-protected file is probably not far from taking control of the complete machine as well, at which point he will just plug into the PHP engine and grab the user passwords as they arrive. There is little point in going to that level of protection.

    What you suggest is encrypting the user password, and storing the key in the client browser (as a cookie) and the encrypted password in the session files; or you could do the reverse (key in the PHP session, encrypted password in the cookie). In both cases, the idea is that the attacker needs to grab both the session data and the cookie to unravel the password. This makes sense only if your security model assumes that an attacker would be able to read the session files (even when they are only in a RAM disk) but not the RAM allocated to the PHP engine (through which passwords necessarily travel at some time). This does not seem a very realistic model to me.

If you do want to use encryption, regardless of its apparent uselessness in that specific situation, you may as well do it properly:

  • Generate the (user-specific) key with a cryptographically secure PRNG (openssl_random_pseudo_bytes()).
  • Use proper encryption. This means the usual assortment of encryption mode, random IV (to be stored along the encrypted file), padding... which is easy to get thoroughly wrong. It is possible to do correct encryption with PHP, but you have to understand what you are doing down to the fine details. In that specific case where a new key is generated for each encryption instance, it should be enough to use a strong block cipher in CFB mode and a fixed, conventional IV, although it would leak the password length; and PHP has a habit of doing weird things (e.g. its "CFB" mode is actually CFB with 8-bit feedback, which is slow and of questionable security for long inputs).

but I still recommend not doing that, and instead use RAM-based storage of PHP sessions on the server.

3
  • Thank you Thomas. I understand that you suggest two methods. 1 (more secure): storing the passwords in plaintext on RAM-based PHP Sessions. 2 (less secure): storing the passwords encrypted in PHP Sessions and storing the encryption key in a Cookie (or vice-versa). How can I check which method of storing the PHP Sessions is in use on this server? Even if there exists a ramdisk that does not mean that PHP is using it for Sessions.
    – dotancohen
    Feb 26, 2013 at 16:44
  • Neither method will happen by itself, so if you did not implement anything, then chances are that PHP works with its default behaviour, with session files in a (distribution-dependent) local directory. Feb 26, 2013 at 18:02
  • Of course nothing happens by itself, but I do not administer the server that this application is running on. One could therefore argue that I then cannot trust the machine nor trust that my code won't be modified, but I counter that it is still my responsibility to 1) do the best job that I can given the circumstances, and 2) learn the intricacies of the situation for my own self-benefit and the benefit of future clients.
    – dotancohen
    Feb 26, 2013 at 18:10

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .