7

I know that storing log-in credentials in plain text is one of the cardinal no-nos of security, but I'm working on something where I can't think of any other solution.

My service connects to a user's e-mail via IMAP. In order to connect to the e-mail server, my service has to know the log-in credentials of the user's e-mail account.

Normally, I would use some sort of encryption or hashing mechanism to store user credentials in the database, but since hashes are (supposed to be) one-way, I can't log in to the e-mail server with the hashed credentials.

How can I create a secure system for my service if the user has to have credentials to connect to a third-party system as well as my system?

Peter Olson
  • 171
  • 1
  • 4

3 Answers3

6

You will need to store the user's email password in a recoverable form. You can still encrypt the passwords, but you cannot hash them.

Storing your users' passwords in recoverable form does entail some security risks. If the database of user passwords is ever leaked, you've got a serious security breach. However, that's just the nature of your service. People normally recommend hashing to try to mitigate this risk, but since you can't use password hashing in your particular application, you'll have to use other measures to mitigate the risk.

Here is my recommendation for how to do it in as secure a way as possible. Set up a separate machine (or VM) that is used solely for the purposes of managing email passwords. It runs a service -- let's call it the password-keeper service -- that exposes a few simple APIs:

  • Register IMAP account. The caller provides information about an email account: e.g., the username and password. Your password-keeper service stores this information.

  • Read email. The caller identifies an IMAP account that was previously registered with your service. Your password-keeper service looks up the username and password for that IMAP account, connects to the IMAP server and authenticates to it, downloads any new email, and returns the desired email messages to the caller.

This password-keeper service is like a Hotel California for email passwords: passwords go in, but they never leave. The password-keeper service is responsible for storing passwords as securely as possible, and never exposing them to others. It might store the passwords in a separate database, encrypted under a special key. The encryption key might be stored in a configuration file that is accessible to this service, but not to anyone else. The password-keeper service can now control access to your users' email accounts. For example, it can perform secure logging (so you can track down intrusions), rate-limiting (to reduce the impact of a breach of your other systems), or other protections. You can also lock down who or what can access it.

Now, write the rest of your system to be a client of the password-keeper service. Configure the password-keeper service so it is only accessible to your code (and not to the public), and use strong authentication for your code's connection to it. Make sure that you never store users' email passwords anywhere else in your system. When the user supplies an email password to your application, you should immediately invoke the password-keeper service's "Register IMAP account" API, pass it the password, and delete all other copies of the password.

This will not provide perfect protection, but it gives you a place to stand: a way to get as much protection as possible, for your users' passwords. With this kind of approach and some diligence, I think you can provide a reasonable level of security to your users.

D.W.
  • 98,420
  • 30
  • 267
  • 572
1

Your service needs to prove to the third-party service that is is authorised to access that service. Whatever credentials it uses to do this must be stored securely. Short of using a HSM to store your key and perform the crypto operations at your end (and having the third-party service participate in a compatible public-key protocol), I think you're stuck with storing a password-equivalent on the box running your service.

If the user has to have (and enter when necessary) credentials for each system involved then you can create a secure system, in that you don't need to store-and-be-able-to-retrieve those credentials. Where such a system misses out is not in security but in user convenience.

mlp
  • 546
  • 4
  • 8
0

When holding credentials for a 3rd party I've seen some applications have a master password that decrypts the credentials. Whenever the user wants to log into the 3rd party they must enter their master (vault) password that will then decrypt their credentials and use them. Your server could then keep these credentials in a memory cache to continue to use and reprompt after they expire. A front end application could use the vault password until the cookie expires then prompt the user for their vault password again. It would also be wise to have a column per user to validate that the vault password is still valid. E.g. column testVault encrypt "test" and decrypt to see if it is successful and matches. While it is still possible to retrieve values from memory, it is much harder than looking through text files or data in a database.

lastlink
  • 101
  • 1