19

I am in need of storing password and use it again. I think this is not at all safe.

Scenario:

I want to create a webmail program where user login with username and password, then check their emails. This tool does not intend to store passwords on db. But in PHP we need to connect to the mail server in each page the user navigates to. So username and password is needed to connect to mail server. How can this be done in the safest way?

ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
Kiran
  • 919
  • 6
  • 8
  • To clarify, you are creating a set of PHP web pages that will be accessed by a browser, correct? And these pages will provide access to some other mail server, which it will need the username and password for? Do you need to store a single username/password that the user will enter and keep that associated with their session? More details would make it more likely that you get a useful answer. – David Schwartz Jan 12 '13 at 13:40
  • Yes David. There are many pages. Each page requires the previous username and password for connection. Php cannot pass connection handler among pages . So i need to keep username and password somehow for connection on many pages. Since this tool is used by many users, we cannot store their password , it is against their privacy . Hope i am saying right .. – Kiran Jan 12 '13 at 13:43
  • Is the client-side UI in Javascript? If not, it probably should be. And it can trivially store the password for you. – David Schwartz Jan 12 '13 at 13:45
  • I guess the question is, can you cache the mail session after the user gives you the login info and you connect to the mail server? – Jared Farrish Jan 12 '13 at 13:46
  • Daivd, my UI in php and html only. No javascript . When user first login, we makes connection to mail server . And on navigating to each other pages, use the same details for connection . SO Is it possible to store the password in session with higher security ? or any other options available ? – Kiran Jan 12 '13 at 13:48
  • Jared, i am sure we cannot cache the connection to a pop/imap server using php . So next is how to make connection on other pages without asking login details on each page user navigates to . – Kiran Jan 12 '13 at 13:49
  • So it seems I didn't understand this right. You basically just want to **forward** the username and password that someone provides to log in at your site to a mail server? What's the hindrance to just keeping it cached in the session then? Sure enough, someone with access to your machine can just read the session store, but there's no way you could protect that kind of data (encryption won't do anything). – Damon Jan 12 '13 at 13:49
  • @Kiran: Are you planning to replace the whole UI with a brand new web page any time the user does anything? You realize that will make an application that's, by modern standards, unusable. – David Schwartz Jan 12 '13 at 13:56
  • 1
    You can always look at how [SquirrelMail does it](http://squirrelmail.org/docs/devel-code/__filesource/fsource_squirrelmail_imap_functionsimap_general.php.html#a783). – Jared Farrish Jan 12 '13 at 14:21

1 Answers1

25

Since storing the password is not intended, but also having to re-enter the password many times is not desirable either, the only solution I see is this:

  • Encrypt the password (using e.g. AES) with a random key of sufficient length
  • Store the encrypted password and username in the session
  • It's probably no mistake to encrypt the username and mail server too, just in case. It won't hurt, and a presumed attacker doesn't have a known username on a server.
  • Store the encryption key in a cookie

This is not perfect, but it should work reasonably well, and it is probably as good of a trade-off as you can get.

With each request, the user's browser will send the cookie, the PHP script can use the cookie to decrypt the data stored in the session and do a request on the IMAP/POP server.

Someone exploiting your server and gaining access to the session store will be able to steal encrypted passwords, but if your random keys are of sufficient length and good random quality, this is pretty futile.

The point is, you can only really secure something with a secret that you don't know. If you have the necessary information to decrypt some information (IMAP password in this case) on your server, for example in the session store, everyone exploiting your server can do the same. No matter how strong your encryption is, it doesn't make any difference.
The only way to make sure secrets remain secret is by encrypting them with something you don't know, something only the user (or in this case the user's browser) knows.

Which leads to the unsolvable problem that at some point in time, you obviously have to know, at least for a fraction of a second. That's the time between the web server receiving the cookie and the PHP script exiting. In theory, if someone with root access was reading the process memory during that time, he would know the secret, too. But alas, that is something you really cannot prevent.
As long as the information is never stored anywhere (not even in the session) it should be reasonably safe, though.

Of course all of this assumes that at least the login page on your site (preferrably all) is served via https://, and you use TLS/SSL to communicate with the mail servers. Otherwise, you're open to much more trivial attacks.

Damon
  • 67,688
  • 20
  • 135
  • 185
  • Hello,This explains a lot about my issue and the security . Thanks a lot for sharing this valuable information. – Kiran Jan 12 '13 at 14:31
  • 1
    Great answer, but the storing shuld be in reverse of what you are suggesting. The encryption key should be stored in session and the encrypted username and password should be store in the cookie. If anyone gain access to the session store they will have lots of keys, but not any usernames and passwords they could try to brute force. – user3332631 Aug 22 '14 at 18:40
  • @user3332631: That's generally correct, and it sure doesn't hurt to eliminate every _possible_ leak. Though realistically, if you choose a non-trivial key length such as 128 bits then brute-forcing is impractical. It is hardly feasible even for someone as big as an US espionage agency to brute-force just a single 128-bit key for thermodynamic limitations (regardless of CPU power). They could probably do _one_ key if the outcome of World War III depended on it, but it's impractical for any key on your server (not to mention many of them). You're not important enough for brute forcing 128 bit. – Damon Aug 23 '14 at 14:48
  • Just to make clear what I'm talking about when I say "impractical" and "not being important enough", counting through 128 bits (key setup and 16 rounds of AES is yet another story!) would consume several years worth of the USA's total uranium production in electric energy, assuming a perfect CPU. This means that you have to have a _very_ important secret before this is going to happen (and then they'll rather use the [wrench attack](http://xkcd.com/538/) on you). It's not a routine thing you do on some random server just to read someone's unimportant e-mails. – Damon Aug 23 '14 at 14:55
  • Ok, so brute force is out of the question. Just want to mention that other systems that does this stores the key in the session and password in cookie. Ref: http://squirrelmail.org/docs/devel-code/squirrelmail/_functions---strings.php.html#functionOneTimePadCreate Dont know if there would be any other reasons for this other than avaoiding brute force on the session store. Maybe it just comes down to what you are comfortably with. – user3332631 Aug 24 '14 at 14:01
  • @Damon: I have another question. Why would we use this scheme instead of Basic access authentication? Does it not in theory do the same thing, or is BA inconvenient since it can time out any time? – user3332631 Aug 24 '14 at 20:01
  • @user3332631: Basic access authentication is for giving you access to a particular page, it does not help for what the OP wants to do (at least I couldn't imagine how it would help). The problem was stated as how to store username+password without storing it in a database, and keeping it secure. The only way of keeping it secure is if you don't know the password, or if you don't know the encryption key. The safest thing would be to never send it to the server at all. Howver, the server must eventually possess the key, temporarily since it makes the request on behalf of the user. – Damon Aug 24 '14 at 21:04
  • @Damon: "You can only really secure something with a secret THAT ONLY YOU DON'T KNOW". Actually, "You can only secure something ONLY YOU KNOW" (Just my 2 cents). But in a real (e.g. commercial) app, you also need some other user-data (like card#, id#, address etc.) and hence the username/passwords table of MySQL is not enough anyway. And if you need to encrypt AND DECRYPT that data, I guess Server Security is still paramount in the real world, becuse you have to keep your decryption key someplace on it. – Mikey Dec 18 '16 at 10:48