11

Disclaimer: I know I should use bcrypt to securely store user's passwords. Please, keep reading.

I want to store credentials for several email services for each user. So if I log in with my username and password (which is properly hashed), then I can access several emails, including 2 @hotmail, 1 @gmail, my university one and several others through imap. I'm using imap to read the emails, which requires the email and password in plain text. So, how do I securely store these passwords?

What I've thought of:

  • Some services offer an API. Use them whenever possible.

  • Encrypt each user's credentials with their login passwords, so only a user that knows his login details can decrypt his credentials and thus access the emails. I'm not sure of how to properly do this, so here's where I need help. I'd use mcrypt_encrypt() from PHP with MCRYPT_RIJNDAEL_256.

  • Request the password each time the user logs in. Not practical if the user has more than 2 services connected.

TL;DR

How do I store passwords in a db so I can use them with imap later on?

Francisco Presencia
  • 685
  • 1
  • 6
  • 20

3 Answers3

8

You face the problem every password manager faces. I believe that their solution is to use a symmetric algorithm to encrypt the sensitive data, and use a master password for each user to derive a decryption key for all his/her saved passwords. This master password will have to be entered every time your script/application is restarted or, in the case of a web application, every time the user logs in.

This is basically what you describe in your second bullet point. The cryptographic tool you need is PBKDF2: use this on the user's login password when it is sent. The resulting key should be suitable to encrypt/decrypt passwords in the database using MCRYPT_RIJNDAEL_256.

On a side note : make sure you use different initialization vectors each time you encrypt new data !

executifs
  • 4,792
  • 4
  • 24
  • 25
2

You might consider deploying your own SSO environment (notice I didn't say to "roll your own").

One I've personally contributed to is Jasig's Central Authentication Service (http://www.jasig.org/cas) which serves as a centralized authentication platform for your users to login to. Your "client" applications then would need to be "CAS-ified" (integrated) with CAS so that it authorizes the user's access if they've already been authenticated by this third-party software.

Pertaining to your question, the component I contributed to was their ClearPass extension (here) which, while increasing security risk as in any application that utilizes encryption over hashing, allows you to proxy for clear-text credentials (here).

Purpose (ClearPass): To enable single sign-on into some legacy application it may be necessary to provide them with the actual cleartext password. While such approach inevitably increases security risk, a number of institutions found it to be a "necessary evil".

Upon successfully completing the ClearPass transaction, you end up with the user's login and password. Note that this would be the user's application login credentials; what the user uses to login to your application which handles authentication to third party email services on their behalf.

Login credentials in hand, you could then re-request their application password via ClearPass over and over again to decrypt service passwords on-demand which you originally encrypted with their login password so as to address the "Password Manager" problems described by @executifs. Storage of the user's application password is handled by ClearPass, encrypted by the EncryptedMapDecorator, and stored in memory (or in memcached, etc).

As an aside, here's a quick wiki page on crypto implementation I wrote up not too long ago back when I was working with encryption and ClearPass (and yes, it has been submitted to ##crypto on Freenode for mass-criticizing and revised as needed) in case it helps any.

For actual code, here are some examples in Java, Node., and yes, even C#. Notice the last two are essentially my ports of the EncryptedMapDecorator.java with respect to Password Based Key Derivation (deriving a secret key based on your passphrase), Initialization Vector (secure random bytes), and even packing. After studying the resources I've outlined assembled here, and these code examples, you should have enough knowledge to be able to port this over to PHP, or at least get started anyways :)

Hope some of this helps!

Matt Borja
  • 267
  • 1
  • 11
0

I felt it's worth sharing my answer to this question, which is marked as a duplicate of this question.

I think credential storage is best for storing cryptographic secrets. You can choose among the following choices depending on your security need -

  • A software-based credential storage
  • A system-managed credential storage
  • A hardware-based credential storage

I would recommend you to read this blog, Cryptographic Key Storage Options & Best Practices. In most cases, system-managed credential storage is a good choice. Many operating systems provide system managed credential storage, for example, Windows Certificate Store, Mac OS Keychain. You can also see my answer on Android Keystore System to get an idea. Depending on your platform I can give you the following solutions for storing secret credential,

Roaim
  • 291
  • 2
  • 5