Storing passwords in a database when hashing doesn't apply - security

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.

Related

Best practice to encrypt and decrypt passwords between services

So basically I'm developing a service that requires plain text input of user and password from the user.
The main server won't ever need to decrypt the password, so it should encrypt the user password with the public key and store it to DB.
Consuming service, which does web scraping needs the password as plain text to be able to authenticate.
And uses a private key for decryption.
I'm wondering whats the best practice to store the cert, I tried to base64 encrypt the key and use it from env. But something is getting corrupted at times. And being unable to decrypt the password.
Any advice on how to handle it is helpful
Wouldn't worry so much about obfuscating the key. Just make sure the server its on is secured, and limit access to the key via permissions and users which have access to that account. If it were a service account with no login ability, that would be better. If you need to reproduce this concept multiple times, use different key/cert for each unique use of this process to limit the exposure if there is a compromise. I'm sure there will be more good responses... let them stack up and see which mix best suits your use case.
Best practice it to hash passwords and store the hashes. When a user logs in, hash their input and compare its value to the hash you already have stored. In this manner a compromise only reveals the hashes, not the actual passwords. There are rainbow tables to crack hashes, but that's a topic for another day.

Is this a safe way to do two key encryption to store a third party password?

I'm building a system that connects to a third party api, and I have to store passwords for each of our users connected to that api. I need to make sure that the passwords are stored securely, so I don't want to trust the user's password as an encryption key. But I also need to make sure that we need the user to authenticate the use of this password, by entering their password.
I had the idea of creating a key by combining the user's id and password with a secret key on the server (just by concatenating them all). I then use crypto's createCipher with aes256 and the new generated key to encrypt the third party password and send it off to storage.
I noticed the text in the createCipher documentation that says this:
In line with OpenSSL's recommendation to use pbkdf2 instead of EVP_BytesToKey it is recommended that developers derive a key and IV on their own using crypto.pbkdf2() and to use crypto.createCipheriv() to create the Cipher object.
And I read up about IVs and the attacks they are meant to prevent (still pretty confused about how that works, especially with my use case) but I think that since this will technically be using a different key every time, that will be a non-issue.
Is this kosher? Is there some vulnerability of this system that I'm missing?

how to store username/passwords securely (hash won't do) on a DB

Imagine this situation: your users give you their credentials (username/password) to access a third party service. So you have to produce those credentials when connecting to the service, you cannot just store a salted hash.
The environment is Grails, with psql as DB. From the programmer point of view, ideally the user/password would still be part of the domain objects (so they are easy to use).
What would be the best practice to securely store them?
*(I'm not a security or crypto expert; this is my understanding based on my reading and research, but is very far from authoritative advice. Get the advice of web-app security professionals and get a proper security audit.)*
The best you can really do is have your app unable to decrypt them when the user isn't actively logged in.
Encrypt the credentials with a key based partially on the user's raw, unhashed password. You never store the user's password to log into your service on your systems, of course, so you only have access to it for a brief moment during authentication (and only then because the web hasn't caught up with the mid-90's and adopted sane challenge-response authentication schemes). You can, at the moment of user log-in, decrypt the saved credentials for the 3rd party services and store them in the volatile server-side session for the user.
For the encryption key you might hash the username and user raw password with a large-ish salt value you generate randomly for each (user,3rd-party-credential) pair and store alongside the encrypted credentials. The salt should be different to their salt used for their stored hashed password.
This is far from ideal and has all sorts of problems - but the credentials won't be accessible after the user's session expires or they log our and you purge their session.
It also means your app cannot act on their behalf when they aren't actively logged in, a limitation that may be a showstopper for you depending on your requirements.
A weaker option is to have a key for all user credentials that's manually entered by the sysadmin when the app is re-started. This key has to be stored in memory, but it's at least not sitting on the disk or in the database, so someone stealing a dump of your database will have a much harder time decrypting the stored credentials.
Neither option will help you if the attacker finds a way to trick your app into revealing those domain objects after decryption - or getting it to let them impersonate that user, getting it to perform actions on the 3rd party service on behalf of another user, etc. It'll at least protect against theft of database dumps and similar attacks, though.
One further recommendation: Rather than using pgcrypto to the crypto in the DB, do it on the application side. This means the DB never sees the key material required to decrypt the data; it can never be leaked into database logs, sniffed out of pg_stat_activity, etc.

How to obtain two independent passwords from a single string?

I'm not sure the title is accurate, please feel free to rename the question if appropriate.
I'm thinking about a service that stores sensitive data on a remote server. For maximum privacy, the data would be encrypted on the client (using AES) and the encryption key not stored in any place, so that should the server be compromised, sensitive data would still be relatively safe.
Now the problem is, I need a second password to access the service, but this second password must be stored somewhere on the server.
This would be what happens when a user registers:
user picks a username/password (Password A) and an encryption key (Password B).
hash(Password A) is stored on the server
Password B isn't stored anywhere.
then:
user enters Password A => Password A is transmitted to the server
server checks hash(Password A) against the user db, grants access
client downloads preferences and encrypted data
User enters Password B -> encrypted data is decrypted (locally).
This looks good to me, but the drawback is that the user needs two distinct passwords. This is impractical and also carries the risk that users pick the same string for both, strongly reducing the model's effectiveness.
What I would like is to use two independent passwords but only ask the user a single one.
First attempt
The first idea I had is to ask the user a password, then split it in two and use the first part as service credentials (Password A) while the second part would be the encryption key (Password B).
This has the drawback of reducing the strength of the passwords: if the user-provided string is already weak/short, Password A and Password B would be even weaker.
Second attempt
Another option: use the user-provided password as encryption key (Password B) and use a hash (SHA-256) of that password as service credentials.
Registration:
user picks a single password PASS
hash(PASS) is transmitted to the server
server stores hash(hash(PASS)) with username in the user db
Then:
user enters PASS
service sends Password A = hash(PASS) to the server
server checks hash(Password A) against the user db, grants access
client downloads preferences and encrypted data
client decrypts encrypted data with Password B = PASS.
This means that
a hash of the encryption password travels over the network 2) a
a hash(hash(encryption key)) is now stored on the server, i.e. alongside the encrypted data
Does this significantly reduces the security of the system? I.e. when an attacker gains access to the server, is it easier to decrypt the sensitive data when knowing hash(hash(encryption key))?
Is there another (better) way to get two independent passwords starting from a single string?
I would go a different approach. Using openid to authenticate to your system. This way you do not have to transmit a password to your server at all.
On your first approach, you should only transmit the hash.
If I remember correctly, LastPass uses this system:
User enters email address and password
Password is hashed and the hash used as key to encrypt the user's sensitive data
Password hash + email is hashed into a second password which is used to log into the server and upload the encrypted data blob
I may have it backwards which hash is used for which, but it sounds like you want something very similar. The whole thing was explained in detail in Security Now #256, if you're interested.
The advice to use a secure password scheme is correct. What you might want to do is to make a small change before passing the user's text to the password scheme. If the user enters "password" then pass "passwordLOCAL" to the local password scheme and "passwordREMOTE" to the remote password scheme.
That allows the user to enter a single password yet still have two different local and remote passwords. Don't actually use "LOCAL" and "REMOTE" of course, far too insecure. Use two different random strings, much like two different salts.
As suggested by #Tim in his answer - do not create a new user authentification scheme (your own user-id & password combination).
Based on what you are building this for, you basically have 2 options:
If this in an corporate internal application just integrate to Active Directory or whatever internal user database and authentication backend you have
If this is public, use OpenID (if you need just authentication) or OAuth if you also need authorization.
Please note that your application does not have to be web based in order to use them. (You do need internet access, though). See this question for details
For the encryption keys, use some sort of Key Derivation Function (also known as PRF+) for the key derivation - preferably with other components as well. Feed the PRF/KDF for example the following (concatenated):
User's unique identifier from the authenticator (OpenID, AD, whatever)
a system-wide application identifier string (e.g Francescos secureapp keypad)
per user random data stored with the user information (e.g. 16 bytes from the system random source)
user's encryption password - this is the single password you have to care about.
This is somewhat similar to AUTH payload calculation in the IKEv2 protocol
This way the potential attacker would need to access bits of information from various locations in order to be able to decrypt user's sensitive data.
Also, don't store the user's encryption password on the server side. The client should always ask it (or cache it for certain amount of time) from the user and send it (in plain or hashed) over an encrypted channel to the server whenever requesting something that needs [en|de]cryption.
Furthermore, if you want to enforce some sort of a password policy on the encryption passwords, see this comic and this answer for reference how it should be done.
You could generate and store an IV (or two, if needed) on the server, and send it to the client to HMAC. This produces the encryption keys that are needed.

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