This is an extract from the linked article Show archive.org snapshot . It shows an approach on how to implement encrypted passwords with the AWS Key Management Service (KMS).
For most applications it's enough to use a hashed password with a salt (e.g. the gem devise Show archive.org snapshot defaults to this).
Upon password creation
-
Generate hash as hash of password + salt.
-
Encrypt the hash with a public key from KMS (you can store the public key in your server code).
-
In your database store the encrypted hash, the salt, plus some "key ID" that identifies which KMS public key you used (this is so you can rotate keys later).
Upon user login to verify the password
-
Retrieve the user's encrypted password hash, salt and KMS key ID from the database.
-
Make a call to KMS to decrypt the hash (KMS internally stores the corresponding private key but never lets you access it).
-
Then hash the password the user entered + salt and compare it to the decrypted hash to see if there is a match.
Benefits of this are
-
If an attacker steals your database, they can't decrypt any of the passwords or the password hashes.
-
KMS never exposes the private key of the async key pair, so you know this won't get exposed either. The only way to decrypt something is to make an API call to KMS.
-
Thus, the only valid attack really is if the attacker is able to gain the same access privileges as your server. But even then they still need to call KMS one-at-a-time to decrypt hashes, and all of those KMS calls are logged in an audit trail, so it should be much easier to see if you have anomalous calls to KMS. There is a huge benefit here in that it is impossible to do bulk decryption without a giant audit trail.