Store email account's password - security

I'm developing an email client in PHP for IMAP accounts. Which would be the most secure way to store the account's password being able to retrieve it afterward to check emails?
I guess I should encrypt it somehow. However, how can I make sure that only my app will be able to decrypt it?

If you require login without any user interactions, then there is no secure solution. You'll need to rely on your OS's storage options which might prevent hostile unprivileged applications from reading the password.
If the user entering a single password on startup is fine, then you can encrypt the other passwords with symmetric encryption, and then use a KDF, such as scrypt or PBKDF2 to derive the master key from the password (and a salt).

Store the passwords in an encrypted file; require the decryption key when starting the app.

Related

Most secure way to temporarily store a password

I have the following use case:
My web application is used for creating prescriptions. When I send the prescription creation request to the government API it is signed with the current user's certificate. The certificate is stored on the application server and is encrypted with a password which only the user knows.
Users want to be able to store their password in my app temporarily so that they don't need to paste it in for each prescription they create.
What would be the most secure way to store this password? Couple of ideas:
Local storage in the browser.
Bad because anyone with an access to the user's device can see the
password even if they're not logged in. Also if the app is not running I have no way to clear the password if the desired storage time expires.
Frontend app memory.
Bad because if user refreshes the page or opens another tab the stored password is gone.
Backend, in database
This sounds like the best option because I can encrypt the password. Is it even worth encrypting though? I would have to encrypt it with some key stored on the same machine so if someone gains access to this machine the encryption doesn't matter because they would be able to decrypt it quite easily.
Separate the password encryption key and the encrypted password:
Generate and store a random key (and nonce / salt)
Encrypt the password (e.g. AES-256-GCM) with the random key
Store the encrypted password on your backend
Send the random key with the request to temporarily decrypt the password
Delete the encrypted password on the backend when the session expires
That way:
The random key stored in the browser can only be used within the current user session and is useless on its own
The encrypted password on your backed can only be used with the random key stored in the browser and is useless on its own

Can you send a hashed password back to the user in plain text?

So I am dealing with a website concern, I am a intermediate level programmer and I was shopping on a website that I have heard other friends use. When I signed up for my account, they sent me my password back in plain text to my email. I always thought that in a html form, if you hashed a password and sent it to the server, there would be no way of sending a password back in plain text. I am assuming the website I made the account is hashing the password, but I have no way of knowing. I'm not a security expert or anything, but I am pretty sure they aren't hashing the password and probably storing my data in plain text on their servers. Is my conclusion correct?
If your password is sent to you during the registration process, it can be that it's sent right when the server receives it and still has it plaintext, and then it gets hashed and stored properly.
This would still not be the best practice though, cleartext passwords should not be sent over insecure channels, like in email.
Of course in this case it's not possible for them to send it again in another request. If that happens, that really means they are not storing it hashed.
If it's properly hashed and secure they should not be able to see it in plaintext. If they could access it easily then so could hackers.
There is another way to store the passwords, encryption. In this way, the application server stores an encryption key to encrypt users' passwords and store them on the database.
When users try to login, they encrypt the new incoming password of the login attempt to see that it is matching.
In case of lost of the passwords, they can send users' password back to them by decrypting it using the key on the application server.
If the application server is compromised, the attackers can access all passwords as the same way the application server does.
By no means, they should send back to users, their passwords. If users don't remember, they have to force users generate into a new one.
For more discussion see Difference between Hashing a Password and Encrypting it

How to best encrypt data-at-rest for users logging in with SAML?

I have a web application which allows SAML authentication by users using their own identity provider. I have fields in a database in my application which I want to ensure that only authorized users can decrypt (and developers/administrators of the system are NOT implicitly authorized). For users logging in with a password this is easy - make an RSA keypair where the private key is encrypted with their login password, and update a keychain if the password ever changes. But how can this be done when there is no login password, because the user has been authenticated with SAML?
I hate to tell you this, but I don't consider your secure option (derived key) all that secure either.
The reality is that an admin can do very bad things here...including:
Inject code on the f/e and steal passwords in flight
Steal the data and do a dictionary attack against the db directly, guessing many possible keys to unlock the data (knowing that the password set is relatively small)
IMO just deriving a key from the password isn't enough. You need to raise the bar materially higher if you want to consider it "best practice." Ideally you could solve both problems with one solution but if you use password as a source (or derived password hashes) then it might not be possible.

Storing passwords in a database when hashing doesn't apply

There are a lot of questions on Stack Overflow about how to store user passwords, and the general advice of course is to hash the passwords and compare hashes.
However, imagine you are building a shrinkwrap intranet application (like SharePoint) that people deploy in their own environments. And suppose it requires a username/password combination to access an external service via HTTP (solutions that rely on API keys or federated security aren't supported).
In this case, we can't hash the password because we will need to pass the original password to the web service that we call. Encrypting would be the second best solution, but what would we use for the encryption key? If an attacked compromised the database, presumably they would have access to whatever key is used to encrypt the data in the first place?
If it was really a requirement for you to get the plain-text version of a stored password, how would you approach the problem in the most secure way?
This is actually a really interesting question. I'll join in.
You should encrypt it when storing it. No matter how you look at it it's better than storing it in plain text. Let's say an attacker finds an sql injection ad dumps the db, he still don't hold the encryption key. On the other hand, if he gets access to the server he will probably also find the encryption key.
To improve it a bit, you could store the encryption key in the server configuration. Assuming you are using Apache, you could use SetEnv.
I in my environment are required to enter the encryption key when Apache starts, this is then stored as en environment variable, so the key isn't really stored anywhere on my server.
There is no way, unless you require the user to enter a key to decrypt the password that you will be 100% safe.
You could generate the encryption key from the user's password. (Not their password for the external service—their password for your service.) Since you're not storing their password in plain text, an attacker who compromised your database wouldn't be able to decrypt the passwords. The downside is that you have to ask them for their password (for your service) whenever you need their external password.
You have the question inverted. The problem is not how to let the consumer "view" the password; the problem is how to let the consumer verify authentication.
In your implementation provide a means by which the consumer can provide a password and a username and get either a yes or a no. Then you continue to store encrypted (not hashed) passwords in the database.

Using AES to store passwords

So I need to be able to actually decrypt the password because some old websites don't use OAuth and I need to have some of my users have access to them through there API. Therefore one way hashing does not work for me. I have been told that the best way to store the passwords with AES and using the salted hash of the passwords as the key. How do I store all the keys and where do I store the salt? Basically how would I exactly implement this.
Thank You
If I understand you correctly you have the following situation. Users log in to your system with a username and password. Your system then needs to impersonate these users by logging into another system that you do not control using the user's username and password for that system which they have given to you.
If that is correct, then it might be reasonable to encrypt their credentials for the other websites using AES. In this case, I would not store the key used to encrypt those crendentials. The password that the user uses to access your system should be used as the key, and it should not be stored anywhere. In this way, you have a chance of protecting your users privacy (depending on the design of the rest of the system, of course).
Since you are encrypting rather than hashing, and the encryption key would be differnet for each user, salting is not necessary.
Also, I would encrypt the full credentials, not just the passwords. Your users are showing an incredible amount of trust by giving you their credentials in the first place, so I would do everything possible to justify that trust!
Your approach is essentially to use AES as a hash function but this will not allow you to decrypt the passwords (short of brute force or some yet-to-be-discovered vulnerability).
You might want to consider asymetric key encryption instead (e.g. RSA). You'll need to encrypt the passwords with the public key of each person you expect would need to decrypt it (which would include the user).

Resources