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 that it won’t take much for the culprit to crack the passwords as well—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 questions 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 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.
- @Michael Brooks - I want you to know that I am absolutely in agreement with CWE-257 and would love to just quote that verbatim each and every time I am asked to make passwords recoverable as plaintext. However, in reality, clients and users are rarely interested in NIST regulations and just want me to do it anyway. 90% of the time I can convince them otherwise but in that 10% of time when I can't I am trying to determine the best course of action--in those cases CWE-257 is ashes in my hand (unfortunately).
- @AviD: The "low value" of the system has absolutely no bearing on this issue because people reuse their passwords. Why can't people understand this simple fact? If you crack the passwords on some "low value" system, you will likely have several valid passwords for other "high value" systems.
- Is it ironic that the most ethical solution here is to lie and tell the client passwords cannot be stored securely and be recoverable? Offer a more secure solution at the same time, and maybe you'll have convinced someone that passwords must be irreversibly encrypted.
You can not ethically store passwords for later plaintext retrieval. It’s as simple as that. Even Jon Skeet can not ethically store passwords for later plaintext retrieval. If your users can retrieve passwords in plain text somehow or other, then potentially so too can a hacker who finds a security vulnerability in your code. And that’s not just one user’s password being compromised, but all of them.
If your clients have a problem with that, tell them that storing passwords recoverably is against the law. Here in the UK at any rate, the Data Protection Act 1998 (in particular, Schedule 1, Part II, Paragraph 9) requires data controllers to use the appropriate technical measures to keep personal data secure, taking into account, among other things, the harm that might be caused if the data were compromised — which might be considerable for users who share passwords among sites. If they still have trouble grokking the fact that it’s a problem, point them to some real-world examples, such as this one.
The simplest way to allow users to recover a login is to e-mail them a one-time link that logs them in automatically and takes them straight to a page where they can choose a new password. Create a prototype and show it in action to them.
Here are a couple of blog posts I wrote on the subject:
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).
Pursuant to the comment I made on the question:
One important point has been very glossed over by nearly everyone… My initial reaction was very similar to @Michael Brooks, till I realized, like @stefanw, that the issue here is broken requirements, but these are what they are.
But then, it occured to me that that might not even be the case! The missing point here, is the unspoken value of the application’s assets. Simply speaking, for a low value system, a fully secure authentication mechanism, with all the process involved, would be overkill, and the wrong security choice.
Obviously, for a bank, the “best practices” are a must, and there is no way to ethically violate CWE-257. But it’s easy to think of low value systems where it’s just not worth it (but a simple password is still required).
It’s important to remember, true security expertise is in finding appropriate tradeoffs, NOT in dogmatically spouting the “Best Practices” that anyone can read online.
As such, I suggest another solution:
Depending on the value of the system, and ONLY IF the system is appropriately low-value with no “expensive” asset (the identity itself, included), AND there are valid business requirements that make proper process impossible (or sufficiently difficult/expensive), AND the client is made aware of all the caveats…
Then it could be appropriate to simply allow reversible encryption, with no special hoops to jump through.
I am stopping just short of saying not to bother with encryption at all, because it is very simple/cheap to implement (even considering passible key management), and it DOES provide SOME protection (more than the cost of implementing it). Also, its worth looking at how to provide the user with the original password, whether via email, displaying on the screen, etc.
Since the assumption here is that the value of the stolen password (even in aggregate) is quite low, any of these solutions can be valid.
Since there is a lively discussion going on, actually SEVERAL lively discussions, in the different posts and seperate comment threads, I will add some clarifications, and respond to some of the very good points that have been raised elsewhere here.
To start, I think it’s clear to everyone here that allowing the user’s original password to be retrieved, is Bad Practice, and generally Not A Good Idea. That is not at all under dispute…
Further, I will emphasize that in many, nay MOST, situations – it’s really wrong, even foul, nasty, AND ugly.
However, the crux of the question is around the principle, IS there any situation where it might not be necessary to forbid this, and if so, how to do so in the most correct manner appropriate to the situation.
Now, as @Thomas, @sfussenegger and few others mentioned, the only proper way to answer that question, is to do a thorough risk analysis of any given (or hypothetical) situation, to understand what’s at stake, how much it’s worth to protect, and what other mitigations are in play to afford that protection.
No, it is NOT a buzzword, this is one of the basic, most important tools for a real-live security professional. Best practices are good up to a point (usually as guidelines for the inexperienced and the hacks), after that point thoughtful risk analysis takes over.
Y’know, it’s funny – I always considered myself one of the security fanatics, and somehow I’m on the opposite side of those so-called “Security Experts”… Well, truth is – because I’m a fanatic, and an actual real-life security expert – I do not believe in spouting “Best Practice” dogma (or CWEs) WITHOUT that all-important risk analysis.
“Beware the security zealot who is quick to apply everything in their tool belt without knowing what the actual issue is they are defending against. More security doesn’t necessarily equate to good security.”
Risk analysis, and true security fanatics, would point to a smarter, value/risk -based tradeoff, based on risk, potential loss, possible threats, complementary mitigations, etc. Any “Security Expert” that cannot point to sound risk analysis as the basis for their recommendations, or support logical tradeoffs, but would instead prefer to spout dogma and CWEs without even understanding how to perform a risk analysis, are naught but Security Hacks, and their Expertise is not worth the toilet paper they printed it on.
Indeed, that is how we get the ridiculousness that is Airport Security.
But before we talk about the appropriate tradeoffs to make in THIS SITUATION, let’s take a look at the apparent risks (apparent, because we don’t have all the background information on this situation, we are all hypothesizing – since the question is what hypothetical situation might there be…)
Let’s assume a LOW-VALUE system, yet not so trival that it’s public access – the system owner wants to prevent casual impersonation, yet “high” security is not as paramount as ease of use. (Yes, it is a legitimate tradeoff to ACCEPT the risk that any proficient script-kiddie can hack the site… Wait, isn’t APT in vogue now…?)
Just for example, let’s say I’m arranging a simple site for a large family gathering, allowing everyone to brainstorm on where we want to go on our camping trip this year. I’m less worried about some anonymous hacker, or even Cousin Fred squeezing in repeated suggestions to go back to Lake Wantanamanabikiliki, as I am about Aunt Erma not being able to logon when she needs to. Now, Aunt Erma, being a nuclear physicist, isn’t very good at remembering passwords, or even with using computers at all… So I want to remove all friction possible for her. Again, I’m NOT worried about hacks, I just dont want silly mistakes of wrong login – I want to know who is coming, and what they want.
So what are our main risks here, if we symmetrically encrypt passwords, instead of using a one-way hash?
- Impersonating users? No, I’ve already accepted that risk, not interesting.
- Evil administrator? Well, maybe… But again, I dont care if someone can impersonate another user, INTERNAL or no… and anyway a malicious admin is gonna get your password no matter what – if your admin’s gone bad, its game over anyway.
- Another issue that’s been raised, is the identity is actually shared between several systems. Ah! This is a very interesting risk, that requires a closer look.
Let me start by asserting that it’s not the actual identity thats shared, rather the proof, or the authentication credential. Okay, since a shared password will effectively allow me entrance to another system (say, my bank account, or gmail), this is effectively the same identity, so it’s just semantics… Except that it’s not. Identity is managed seperately by each system, in this scenario (though there might be third party id systems, such as OAuth – still, its seperate from the identity in this system – more on this later).
As such, the core point of risk here, is that the user will willingly input his (same) password into several different systems – and now, I (the admin) or any other hacker of my site will have access to Aunt Erma’s passwords for the nuclear missile site.
Does anything here seem off to you?
Let’s start with the fact that protecting the nuclear missiles system is not my responsibility, I’m just building a frakkin family outing site (for MY family). So whose responsibility IS it? Umm… How about the nuclear missiles system? Duh.
Second, If I wanted to steal someone’s password (someone who is known to repeatedly use the same password between secure sites, and not-so-secure ones) – why would I bother hacking your site? Or struggling with your symmetric encryption? Goshdarnitall, I can just put up my own simple website, have users sign up to receive VERY IMPORTANT NEWS about whatever they want… Puffo Presto, I “stole” their passwords.
Yes, user education always does come back to bite us in the hienie, doesn’t it?
And there’s nothing you can do about that… Even if you WERE to hash their passwords on your site, and do everything else the TSA can think of, you added protection to their password NOT ONE WHIT, if they’re going to keep promiscuously sticking their passwords into every site they bump into. Don’t EVEN bother trying.
Put another way, You don’t own their passwords, so stop trying to act like you do.
So, my Dear Security Experts, as an old lady used to ask for Wendy’s, “WHERE’s the risk?”
Another few points, in answer to some issues raised above:
- CWE is not a law, or regulation, or even a standard. It is a collection of common weaknesses, i.e. the inverse of “Best Practices”.
- The issue of shared identity is an actual problem, but misunderstood (or misrepresented) by the naysayers here. It is an issue of sharing the identity in and of itself(!), NOT about cracking the passwords on low-value systems. If you’re sharing a password between a low-value and a high-value system, the problem is already there!
- By the by, the previous point would actually point AGAINST using OAuth and the like for both these low-value systems, and the high-value banking systems.
- I know it was just an example, but (sadly) the FBI systems are not really the most secured around. Not quite like your cat’s blog’s servers, but nor do they surpass some of the more secure banks.
- Split knowledge, or dual control, of encryption keys do NOT happen just in the military, in fact PCI-DSS now requires this from basically all merchants, so its not really so far out there anymore (IF the value justifies it).
- To all those who are complaining that questions like these are what makes the developer profession look so bad: it is answers like those, that make the security profession look even worse. Again, business-focused risk analysis is what is required, otherwise you make yourself useless. In addition to being wrong.
- I guess this is why it’s not a good idea to just take a regular developer and drop more security responsibilities on him, without training to think differently, and to look for the correct tradeoffs. No offense, to those of you here, I’m all for it – but more training is in order.
Whew. What a long post…
But to answer your original question, @Shane:
- Explain to the customer the proper way to do things.
- If he still insists, explain some more, insist, argue. Throw a tantrum, if needed.
- Explain the BUSINESS RISK to him. Details are good, figures are better, a live demo is usually best.
- IF HE STILL insists, AND presents valid business reasons – it’s time for you to do a judgement call:
Is this site low-to-no-value? Is it really a valid business case? Is it good enough for you? Are there no other risks you can consider, that would outweigh valid business reasons? (And of course, is the client NOT a malicious site, but thats duh).
If so, just go right ahead. It’s not worth the effort, friction, and lost usage (in this hypothetical situation) to put the necessary process in place. Any other decision (again, in this situation) is a bad tradeoff.
So, bottom line, and an actual answer – encrypt it with a simple symmetrical algorithm, protect the encryption key with strong ACLs and preferably DPAPI or the like, document it and have the client (someone senior enough to make that decision) sign off on it.
I am currently using this approach for most of my projects,
$public_key = sha1("mysite.com"); //While Registration $user_salt = sha1(uniqid(time()).$public_key); //Time Based Unique ID $user_name = "helloworld"; //Entered by user $user_pass = "123456"; //Most novice users will use this. $secret_pass = sha1($user_pass . $user_name . $user_salt); In DB Store, $user_name, $secret_pass, $user_salt //While Login $user_name = "helloworld"; $entered_pass = "123456"; Find $user_name from DB If $user_name found than get $secret_pass and $user_salt from DB corresponding to that user $current_pass = sha1($entered_pass . $user_name . $user_salt); if($current_pass === $secret_pass) User is Authenticated
- You must login to post comments
If you can’t just reject the requirement to store recoverable passwords, how about this as your counter-argument.
We can either properly hash passwords and build a reset mechanism for the users, or we can remove all personally identifiable information from the system. You can use an email address to set up user preferences, but that’s about it. Use a cookie to automatically pull preferences on future visits and throw the data away after a reasonable period.
The one option that is often overlooked with password policy is whether a password is really even needed. If the only thing your password policy does is cause customer service calls, maybe you can get rid of it.