As I continue to build more and more websites and web applications I am often asked to store user's passwords in a way that they can be retrieved if/when the user has an issue (either to email a forgotten password link, walk them through over the phone, etc.) When I can I fight bitterly against this practice and I do a lot of ‘extra’ programming to make password resets and administrative assistance possible without storing their actual password.
When I can’t fight it (or can’t win) then I always encode the password in some way so that it, at least, isn’t stored as plaintext in the database—though I am aware that if my DB gets hacked it wouldn't take much for the culprit to crack the passwords, so that makes me uncomfortable.
In a perfect world folks would update passwords frequently and not duplicate them across many different sites—unfortunately I know MANY people that have the same work/home/email/bank password, and have even freely given it to me when they need assistance. I don’t want to be the one responsible for their financial demise if my DB security procedures fail for some reason.
Morally and ethically I feel responsible for protecting what can be, for some users, their livelihood even if they are treating it with much less respect. I am certain that there are many avenues to approach and arguments to be made for salting hashes and different encoding options, but is there a single ‘best practice’ when you have to store them? In almost all cases I am using PHP and MySQL if that makes any difference in the way I should handle the specifics.
Additional Information for Bounty
I want to clarify that I know this is not something you want to have to do and that in most cases refusal to do so is best. I am, however, not looking for a lecture on the merits of taking this approach I am looking for the best steps to take if you do take this approach.
In a note below I made the point that websites geared largely toward the elderly, mentally challenged, or very young can become confusing for people when they are asked to perform a secure password recovery routine. Though we may find it simple and mundane in those cases some users need the extra assistance of either having a service tech help them into the system or having it emailed/displayed directly to them.
In such systems the attrition rate from these demographics could hobble the application if users were not given this level of access assistance, so please answer with such a setup in mind.
Thanks to Everyone
This has been a fun question with lots of debate and I have enjoyed it. In the end I selected an answer that both retains password security (I will not have to keep plain text or recoverable passwords), but also makes it possible for the user base I specified to log into a system without the major drawbacks I have found from normal password recovery.
As always there were about 5 answers that I would like to have marked as correct for different reasons, but I had to choose the best one--all the rest got a +1. Thanks everyone!
Also, thanks to everyone in the Stack community who voted for this question and/or marked it as a favorite. I take hitting 100 up votes as a compliment and hope that this discussion has helped someone else with the same concern that I had.
From the little that I understand about this subject, I believe that if you are building a website with a signon/password, then you should not even see the plaintext password on your server at all. The password should be hashed, and probably salted, before it even leaves the client.
If you never see the plaintext password, then the question of retrieval doesn't arise.
Also, I gather (from the web) that (allegedly) some algorithms such as MD5 are no longer considered secure. I have no way of judging that myself, but it is something to consider.
After reading this part:
I'm left wondering if any of these requirements mandate a retrievable password system. For instance: Aunt Mabel calls up and says "Your internet program isn't working, I don't know my password". "OK" says the customer service drone "let me check a few details and then I'll give you a new password. When you next log in it will ask you if you want to keep that password or change it to something you can remember more easily."
Then the system is set up to know when a password reset has happened and display a "would you like to keep the new password or choose a new one" message.
How is this worse for the less PC-literate than being told their old password? And while the customer service person can get up to mischief, the database itself is much more secure in case it is breached.
Comment what's bad on my suggestion and I'll suggest a solution that actually does what you initially wanted.
Securing credentials is not a binary operation: secure/not secure. Security is all about risk assessment and is measured on a continuum. Security fanatics hate to think this way, but the ugly truth is that nothing is perfectly secure. Hashed passwords with stringent password requirements, DNA samples, and retina scans are more secure but at a cost of development and user experience. Plaintext passwords are far less secure but are cheaper to implement (but should be avoided). At end of the day, it comes down to a cost/benefit analysis of a breach. You implement security based on the value of the data being secured and its time-value.
What is the cost of someone's password getting out into the wild? What is the cost of impersonation in the given system? To the FBI computers, the cost could be enormous. To Bob's one-off five-page website, the cost could be negligible. A professional provides options to their customers and, when it comes to security, lays out the advantages and risks of any implementation. This is doubly so if the client requests something that could put them at risk because of failing to heed industry standards. If a client specifically requests two-way encryption, I would ensure you document your objections but that should not stop you from implementing in the best way you know. At the end of the day, it is the client's money. Yes, you should push for using one-way hashes but to say that is absolutely the only choice and anything else is unethical is utter nonsense.
If you are storing passwords with two-way encryption, security all comes down to key management. Windows provides mechanisms to restrict access to certificates private keys to administrative accounts and with passwords. If you are hosting on other platform's, you would need to see what options you have available on those. As others have suggested, you can use asymmetric encryption.
There is no law (neither the Data Protection Act in the UK) of which I'm aware that states specifically that passwords must be stored using one-way hashes. The only requirement in any of these laws is simply that reasonable steps are taken for security. If access to the database is restricted, even plaintext passwords can qualify legally under such a restriction.
However, this does bring to light one more aspect: legal precedence. If legal precedence suggests that you must use one-way hashes given the industry in which your system is being built, then that is entirely different. That is the ammunition you use to convince your customer. Barring that, the best suggestion to provide a reasonable risk assessment, document your objections and implement the system in the most secure way you can given customer's requirements.
I implement multiple-factor authentication systems for a living, so for me it is natural to think that you can either reset or reconstruct the password, while temporarily using one less factor to authenticate the user for just the reset/recreation workflow. Particularly the use of OTPs (one-time passwords) as some of the additional factors, mitigates much of the risk if the time window is short for the suggested workflow. We've implemented software OTP generators for smartphones (that most users already carry with themselves all day) with great success. Before complains of a commercial plug appear, what I'm saying is that we can lower the risks inherent of keeping passwords easily retrievable or resettable when they aren't the only factor used to authenticate an user. I concede that for the password reuse among sites scenarios the situation is still not pretty, as the user will insist to have the original password because he/she wants to open up the other sites too, but you can try to deliver the reconstructed password in the safest possible way (htpps and discreet appearance on the html).
open a DB on a standalone server and give an encrypted remote connection to each web server that requires this feature.
it does not have to be a relational DB, it can be a file system with FTP access, using folders and files instead of tables and rows.
give the web servers write-only permissions if you can.
Store the non-retrievable encryption of the password in the site's DB (let's call it "pass-a") like normal people do :)
on each new user (or password change) store a plain copy of the password in the remote DB. use the server's id, the user's ID and "pass-a" as a composite key for this password. you can even use a bi-directional encryption on the password to sleep better at night.
now in order for someone to get both the password and it's context (site id + user id + "pass-a"), he has to:
you can control the accessibility of the password retrieval service (expose it only as a secured web service, allow only certain amount of passwords retrievals per day, do it manually, etc.), and even charge extra for this "special security arrangement".
The passwords retrieval DB server is pretty hidden as it does not serve many functions and can be better secured (you can tailor permissions, processes and services tightly).
all in all, you make the work harder for the hacker. the chance of a security breach on any single server is still the same, but meaningful data (a match of account and password) will be hard to assemble.
How about taking another approach or angle at this problem? Ask why the password is required to be in plaintext: if it's so that the user can retrieve the password, then strictly speaking you don't really need to retrieve the password they set (they don't remember what it is anyway), you need to be able to give them a password they can use.
Think about it: if the user needs to retrieve the password, it's because they've forgotten it. In which case a new password is just as good as the old one. But, one of the drawbacks of common password reset mechanisms used today is that the generated passwords produced in a reset operation are generally a bunch of random characters, so they're difficult for the user to simply type in correctly unless they copy-n-paste. That can be a problem for less savvy computer users.
One way around that problem is to provide auto-generated passwords that are more or less natural language text. While natural language strings might not have the entropy that a string of random characters of the same length has, there's nothing that says your auto-generated password needs to have only 8 (or 10 or 12) characters. Get a high-entropy auto-generated passphrase by stringing together several random words (leave a space between them, so they're still recognizable and typeable by anyone who can read). Six random words of varying length are probably easier to type correctly and with confidence than 10 random characters, and they can have a higher entropy as well. For example, the entropy of a 10 character password drawn randomly from uppercase, lowercase, digits and 10 punctuation symbols (for a total of 72 valid symbols) would have an entropy of 61.7 bits. Using a dictionary of 7776 words (as Diceware uses) which could be randomly selected for a six word passphrase, the passphrase would have an entropy of 77.4 bits. See the Diceware FAQ for more info.
a passphrase with about 77 bits of entropy: "admit prose flare table acute flair"
a password with about 74 bits of entropy: "K:&$R^tt~qkD"
I know I'd prefer typing the phrase, and with copy-n-paste, the phrase is no less easy to use that the password either, so no loss there. Of course if your website (or whatever the protected asset is) doesn't need 77 bits of entropy for an auto-generated passphrase, generate fewer words (which I'm sure your users would appreciate).
I understand the arguments that there are password protected assets that really don't have a high level of value, so the breach of a password might not be the end of the world. For example, I probably wouldn't care if 80% of the passwords I use on various websites was breached: all that could happen is a someone spamming or posting under my name for a while. That wouldn't be great, but it's not like they'd be breaking into my bank account. However, given the fact that many people use the same password for their web forum sites as they do for their bank accounts (and probably national security databases), I think it would be best to handle even those 'low-value' passwords as non-recoverable.