3

I'm building a webmail client (like gmail). It allows the user to browse emails and send them. Under the hood, php uses IMAP and SMTP to talk with email server.

user->webserver->mailserver

When user wants to use my webmail, webserver asks credentials for the mailserver. When webserver needs to connect mailserver, the mailserver asks for the credentials user provided.

So with this webmail you can connect to any mailserver you like. Gmail, yahoo, your private mailserver, etc.. It's like Roundcube, Squirrelmail.

So I have two levels of authentification. What concerns user->webserver part, there is a session in place. However, I'm frustrated about webserver->mailserver part. I'm using php's native imap_open() function to connect.

  1. After the user has logged in, he might click on "refresh my emails" button a couple of times. Is it ok if webserver sends username/password EACH TIME it needs to connect to the mailserver (via imap_open)? Since two servers don't have such thing as a session. Is there a better way?

  2. Since user provides this password just once when logging in, and then the session keeps him logged in, I need a way to safely store this password between requests the user can make to my webserver (clicking "refresh my emails" for example). Maybe I could store the password in an encrypted cookie. Is there a better way?

user3702861
  • 419
  • 1
  • 4
  • 8
  • Some services such as gmail offer a "app password" which is limited to a specific app without potentially compromising your account . – Damian Nikodem Feb 11 '15 at 00:04

3 Answers3

4

To ensure only the user has the key for his IMAP-Account, you can save the login credentials in your session symmetrically encrypted by a key, that is stored in a cookie. So the user can unlock the login credentials with his cookie, without that the webserver can't login.

Of course you have to ensure that all occurrences of the credentials are overwritten if not used anymore and are not readable by other processes.

If you have an attacker on the webserver, he will maybe able to read the session details, the encrypted credentials. If he is also able to get the cookie by eavesdropping the connection you have a problem anyway.

sebix
  • 298
  • 3
  • 15
3

Since the author mentions his product is like Roundcube or Squirelmail.. I know how Roundcube works.

Well, Roundcube's webmail DOES NOT have it's own method for logging in users. What I mean is that there is no database which stores anything about the user. Roundcubes takes the credentials user provided and puts them straight in imap_open().

  1. If it establishes connection with mailserver, then Roundcube logs the user in.
  2. If it does not establish connection with mailserver, Roundcube says "incorrect credentials".

Therefore the password in this part: user->webserver. Is the same as in this part: webserver->mailserver.

This makes to proccess simpler. However, as far as I know, plaintext password or encrypted password must be stored between those web requsts, but I am not sure about how it's done in Roundcube.

I guess you could simply store them in session cookie (ecnrypted cookie as you mention in your question). Therefore the password is not saved on server in any way, it only flies between server and user on each web request. Since it's encrypted, it cannot be leaked as far as your secret encryption key on server is not leaked.

user68129
  • 31
  • 1
  • this also limits the end user to attaching to only 1 imap or smtp service at a time (without adding login credentials again. ) It also means that the user may have to enter configuration data multiple times unless it is stored somehow (since some mail servers are configured to use non-standard ports or have different hosts for receiving and sending emails.) one cannot assume that mail. will work. – Damian Nikodem Feb 11 '15 at 11:51
1

ive been thinking about this for a bit due to the fact that you should never store user passwords in plaintext. so I have came up with a possible solution for you.

When a user signs up for a new 'service' to their account (e.g. they add gmail or yahoo, etc. ) what you are going to have to do is:

  1. Ask the user for their site password again (and validate it)

  2. Hash their password again with a new random salt (which you should store) (with a different hash algorythm to what you use for your main password store) DO NOT STORE THIS!! from now on I will refer to this as KEY_A

  3. generate a passworded dsa or rsa key with KEY_A as the password for the keyfile. This will be used as the enctyption key for the next step

  4. Use a Secure encryption method (maybe mcrypt if in php since it is built in) and store their 'encrypted' password

  5. When a user logs in, and a new session is created rehash their password with the same method used in step #2, Encrypt it with a key that is derived from something that is unique to their session but not stored ( Lets say user_agent + session_start_time + their Ip address + a user specific salt ). Store this encrypted value in a http_only cookie, clear said cookie on logout, force them to login again if the cookie is not present.

Now you have a method of storing their gmail/hotmail/etc. credentials in a manner where you have no direct way of knowing how to decrypt them without the password that they use for your service.

It would most likely also be prudent to make sure that you do not store some of the components used in encrypting the cookie ( so at the least disable user agent logging in your webserver config. )

Now in order for you to perform a iMap login (or something similar. you would simply have to decrypt the http_only cookie from step 5 to get KEY_A, use KEY_A to unlock the RSA/DSA key, then use the unlocked key to decrypt the password to their service, then perform the iMap transaction, and just to be paranoid re-zero (in php you can just call unset() )the variables which contain their plaintext password, KEY_A, and their unlocked rsa/dsa key the line of code after they are no longer needed.

In addition to this make sure that your DNS service is also setup securely. (force DNS-SEC, maybe even setup your webservers dns resolution to go via a service network interface and not the web-visible one and perform DNS resolution via a different 'non-related' web visible IP address.) Make sure that your https certificates are completely up to scratch.

Because you will be effectively sending peoples private passwords over the web the last thing that you want is someone flooding your web server's ip address with udp DNS resolution packets redirecting lets say 'mail.google.com' to a custom imap proxy that they have created for the purposes of sniffing passwords.

The only downside to this method (that I can think of) is when the user changes the password to your service they will need to re-enter the password to all the other email providers that they have registered with it. (because the stored encrypted password will be no longer valid. )

And last but not least ( im assuming that this is will be done, but I have no way of being sure. ) delete ALL debug code related to these routines prior to going live!

The whole key to this is ensuring that KEY_A cannot be derived from anything that you store (so dont shortcut by simply re-hashing the hash of their password, hash in a different manner, with a different salt.)

Damian Nikodem
  • 769
  • 4
  • 8
  • Why has this been downvoted without comment? – sebix Feb 12 '15 at 10:20
  • @sebix no idea, I was actually rather happy with this concept as a method of allowing storage without anyone except the actual owner of a given imap account having access to the credentials. I assume it was probably one of the other people answering this question.. While I cannot be sure that the method which I described is perfect (and I am open to suggestions about flaws) but it sits well enough with me that I would implement something like this if needed. – Damian Nikodem Feb 12 '15 at 10:45
  • I really like how this sounds. Have you tried implementing this since you answered this post @DamianNikodem? – Tholle Mar 29 '15 at 09:18
  • 1
    @Tholle No I havn't, but that's because I have never needed to maintain a users third party credentials, but on that note it shouldnt be difficult to implement either. – Damian Nikodem Mar 29 '15 at 13:12
  • @DamianNikodem I see. I will definitely try this. Thanks a bunch! – Tholle Mar 29 '15 at 13:50