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.


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?

  • 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 0:04

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.

| improve this answer | |

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.

| improve this answer | |
  • 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.<whateveremaildomainIuse> will work. – Damian Nikodem Feb 11 '15 at 11:51

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.)

| improve this answer | |
  • 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 9: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

Why you do not store the mail server credentials as part of the web server session data. Once the user type his mail server username and password in you webmail client application. You keep this information in the web server/user session.

However, this means every time the user login to the webmail he will need to authenticate his identity at least twice one for the web server hosting the webmail client and one for the mail server hosting the user emails. If this the case then you might have a usability issue. Some users will complain about the part where they have to provide the credentials for the mail server every time they login. Why you do not store the mail server credentials in the same database where you store the webmail client credentials?

| improve this answer | |
  • So this way once a attacker breaks into this system instead of having to look up a database all he has to do is scrape the session storage ? ( which is always readable by the web server process ) ? – Damian Nikodem Feb 11 '15 at 0:07
  • No, user don't need to provide his identity twice. Please read the answer by user68129 below. – user3702861 Feb 11 '15 at 8:38
  • @DamianNikodem If the web server process is compromised it is already checkmate. It really does not matter how many encryption decryption operations you are doing. Why do you think any protection technique will stand if the web server process is compromised? – Ubaidah Feb 11 '15 at 9:49
  • @AbuUbaidah because there are plenty of different methods of compromising a web server, as long as you don't have write access to php files(and the ability to make a complex enough change to log end user login details during the login process.) then both of our methods are completely compsimised, if an attacker can gain read access to files (or sql injection if session data is stored in a database, both of which are often significantly easier to get than write access to .php files) then your method falls down whereas my solution will survive both of those. – Damian Nikodem Feb 11 '15 at 11:44
  • @user3702861 you mentioned 'two levels' of authentication in your original post so it is very easy to assume that you require one login for your service and another login for the webmail. Infact my reading of your question was that you were wanting to allow a user to connect to multiple webmail services at the same time. (so for example having a combined hotmail, gmail, and yahoo inbox) – Damian Nikodem Feb 11 '15 at 11:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.