491

I am working on a project that has to have authentication (username and password)

It also connects to a database, so I figured I would store the username and password there. However, it seems like not such a good idea to have passwords as just a text field in a table sitting on the database.

I'm using C# and connecting to a 2008 express server. Can anyone suggest (with as many examples as possible) what the best way to store this type of data would be?

P.S I am open to the idea that this info not be stored in the database if a good reason can be provided

JDoe
  • 3
  • 2
Crash893
  • 10,590
  • 20
  • 82
  • 118
  • 1
    Whatever you do, if you go with encryption, don't store the key in the code as a previous poster mentioned. That's just poor practice. – Woody Aug 03 '09 at 10:26
  • 12
    'How to do passwords right?' is a vital question. It's a tough problem and mistakes have grave consequences (recall what happened to Tesco and LinkedIn). I think this question should be re-opened at http://programmers.stackexchange.com – Colonel Panic Feb 04 '13 at 14:52
  • 2
    It's better to stick to standards - see http://en.wikipedia.org/wiki/PBKDF2 You only have to find an implementation in your language – Boris Treukhov May 15 '14 at 20:01
  • 5
    This question is extensively answered in the security forum: http://security.stackexchange.com/questions/211/how-to-securely-hash-passwords – gioele Nov 12 '14 at 09:15

8 Answers8

422

You are correct that storing the password in a plain-text field is a horrible idea. However, as far as location goes, for most of the cases you're going to encounter (and I honestly can't think of any counter-examples) storing the representation of a password in the database is the proper thing to do. By representation I mean that you want to hash the password using a salt (which should be different for every user) and a secure 1-way algorithm and store that, throwing away the original password. Then, when you want to verify a password, you hash the value (using the same hashing algorithm and salt) and compare it to the hashed value in the database.

So, while it is a good thing you are thinking about this and it is a good question, this is actually a duplicate of these questions (at least):

To clarify a bit further on the salting bit, the danger with simply hashing a password and storing that is that if a trespasser gets a hold of your database, they can still use what are known as rainbow tables to be able to "decrypt" the password (at least those that show up in the rainbow table). To get around this, developers add a salt to passwords which, when properly done, makes rainbow attacks simply infeasible to do. Do note that a common misconception is to simply add the same unique and long string to all passwords; while this is not horrible, it is best to add unique salts to every password. Read this for more.

Community
  • 1
  • 1
Paolo Bergantino
  • 449,396
  • 76
  • 509
  • 431
  • @Paolo Bergantino: "storing the password in the database is the proper thing to do" - I would disagree with that statement. – Mitch Wheat Jun 28 '09 at 02:00
  • 42
    I meant storing the password in the database as opposed to storing it elsewhere. Taking that sentence out of context makes it seem like I am supporting storing plain passwords, if you read the rest I obviously don't. – Paolo Bergantino Jun 28 '09 at 02:03
  • @Paolo Bergantino: I understood what you meant perfectly. And I did not take it out of context. Best practice is not to store even the ecnrypted password, but to store a salted hash of the encrypted password. – Mitch Wheat Jun 28 '09 at 02:04
  • 16
    Not only is that what I said, I directed him to a plethora of posts that discuss salts and such further... – Paolo Bergantino Jun 28 '09 at 02:06
  • 1
    @Paolo Bergantino: you sure there is not a typo in your post? It says "For most of the cases you are going to encounter (and I honestly can't think of any counter-examples) storing the password in the database is the proper thing to do." ??? It seems to contrdict your comments – Mitch Wheat Jun 28 '09 at 02:13
  • 3
    What Paolo said directly contradicts itself. A salted hash of a password is not a password. Storing a salted hash of the password in the database is not storing the password in the database. The body of the answer is perfectly appropriate, but its first sentence is extremely misleading. – Robert Rossney Jun 28 '09 at 19:14
  • 44
    @Robert: That's getting dangerously close to a petty semantics game, but I'll fix it nonetheless... – Paolo Bergantino Jun 28 '09 at 19:29
  • https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet is a good reference on hashing/salting. – chilladx Jun 06 '17 at 13:54
57

Background You never ... really ... need to know the user's password. You just want to verify an incoming user knows the password for an account.

Hash It: Store user passwords hashed (one-way encryption) via a strong hash function. A search for "c# encrypt passwords" gives a load of examples.

See the online SHA1 hash creator for an idea of what a hash function produces (But don't use SHA1 as a hash function, use something stronger such as SHA256).

Now, a hashed passwords means that you (and database thieves) shouldn't be able to reverse that hash back into the original password.

How to use it: But, you say, how do I use this mashed up password stored in the database?

When the user logs in, they'll hand you the username and the password (in its original text) You just use the same hash code to hash that typed-in password to get the stored version.

So, compare the two hashed passwords (database hash for username and the typed-in & hashed password). You can tell if "what they typed in" matched "what the original user entered for their password" by comparing their hashes.

Extra credit:

Question: If I had your database, then couldn't I just take a cracker like John the Ripper and start making hashes until I find matches to your stored, hashed passwords? (since users pick short, dictionary words anyway ... it should be easy)

Answer: Yes ... yes they can.

So, you should 'salt' your passwords. See the Wikipedia article on salt

See "How to hash data with salt" C# example (archived)

drac_o
  • 161
  • 1
  • 11
joej
  • 1,013
  • 6
  • 8
  • 15
    Nice post, except for one thing: md5 and sha1 have both been broken. You should probably go with a stronger algorithm, such as maybe the SHA2 family. – Paolo Bergantino Jun 28 '09 at 02:27
  • 3
    Thanks Paolo -- you are correct. As the use of SHA2 is as easy as using MD5 & SHA1, please use the stronger hash algorithm. – joej Jun 28 '09 at 16:52
  • 5
    SHA-1 hasn't been broken. But to paraphase Bruce Schneier: Walk, don't run, to SHA-2. – Ian Boyd Feb 24 '10 at 19:20
  • 3
    "So, you should 'salt' your passwords"... But the salt is usually stored in the database along with the password, so how does that help? Te attacker simply has to add the salt to the dictionary attack phrases he is testing against. How is that more secure other than it won't reveal duplicate passwords? – trusktr Nov 17 '13 at 21:13
  • 4
    @joej "You never ... really ... need to know the user's password" - that's a very short sighted assumption. There are many kind of applications where having a password stored in a way that can be retrieved is genuinely necessary. For example, an application that needs to frequently login to another system with stored credentials, supplied and updated by a user. – Francisco Zarabozo Sep 21 '15 at 02:15
  • @FranciscoZarabozo that's bad design of the both systems, because when my system is compromised, now my users on your system are too. oAuth and the like get around this, but you need the "other system" to support it. You should never reversibly encrypt a users password. – thinkOfaNumber Jun 01 '16 at 04:19
  • @thinkOfaNumber Again saying "you should never"... Tell me, how would you store the credentials to access an API like a REST API for PayPal or Twilio or any other system that provides you with a user and key (that acts as a password)? What if your system interfaces with those APIs not only for you but for several clients? You NEED to find a way to secure such data and that way exists. Two way encryption methods serve a purpose, they are not there as a "bad choice". Bad choices come from how you decide to implement it. – Francisco Zarabozo Jun 01 '16 at 16:38
  • @FranciscoZarabozo PayPal uses OAuth 2.0 as the auth mechanism. If PayPal allowed you to store my PayPal pwd in a 3rd party app, it would be a disaster, as they have little control over every unrelated app's security. An OAuth token gets around this, and is not the password, so it's ok to store in a reversibly encrypted form. Nor is my PayPal pwd _ever_ made available to the third-party system, as when I log into PayPal I'm on their website, not the third parties. That's how your system should interface with them. This discussion might warrant it's own question to ask if it's "ever OK"! – thinkOfaNumber Jun 02 '16 at 03:23
  • @thinkOfaNumber: you should have a look at POP and IMAP and come back with the right way to authenticate on these services. Also ping Google about that as they are storing these credentials in gmail (when you need to access mail systems via IMAP or POP). Seriously - saying this just shows that you have not worked about real life APIs. – WoJ Nov 02 '16 at 17:39
  • 1
    @WoJ Let's keep this technical and leave the guesses about my personal history for the pub. I admit that webmail is one case I never thought of, but POP and IMAP date back to the 80's when security was a different thing. Just because you can do it doesn't mean you should do it however, and I used to forward my POP mail to gMail so that I could avoid this very situation. PayPal would block your system from accessing them if you did the same, for good reason. A modern API developer should ensure that storing passwords is not necessary (or possible) by providing oAuth and other mechanisms. – thinkOfaNumber Nov 07 '16 at 03:52
31

As a key-hardened salted hash, using a secure algorithm such as sha-512.

nilamo
  • 1,904
  • 13
  • 22
  • 7
    In my opinion, you should always use slow algorithms (like Blowfish, for example) to store passwords. This writeup is a much better answer: https://security.stackexchange.com/questions/211/how-to-securely-hash-passwords. Just putting it here, because this page still appears high in the search results. – Dynom Jun 03 '14 at 11:21
  • 2
    Following this advice for password storage would be doing it woefully wrong. – mlissner May 29 '15 at 00:51
27

The best security practice is not to store the password at all (not even encrypted), but to store the salted hash (with a unique salt per password) of the encrypted password.

That way it is (practically) impossible to retrieve a plaintext password.

Mitch Wheat
  • 280,588
  • 41
  • 444
  • 526
  • 11
    Wayne, by salting before computing the hash, the rainbow table is effectively defeated, provided the salt is of sufficient size. – Mike Rosenblum Jun 28 '09 at 02:32
  • 12
    @Wayne Hartman: Not so. If the salt value is exposed, then you must generate a new rainbow table for that specific salt value. The point of a rainbow table is to have hash values calculated beforehand. And nobody will have a rainbow table for his specific salt. – Ian Boyd Feb 24 '10 at 19:16
10

I'd thoroughly recommend reading the articles Enough With The Rainbow Tables: What You Need To Know About Secure Password Schemes [dead link, copy at the Internet Archive] and How To Safely Store A Password.

Lots of coders, myself included, think they understand security and hashing. Sadly most of us just don't.

gioele
  • 8,311
  • 4
  • 49
  • 75
zebrabox
  • 5,556
  • 25
  • 32
  • 1
    @Johan Looks like the link is now broken which is a shame. Here's an alternative http://codahale.com/how-to-safely-store-a-password/ – zebrabox May 26 '11 at 12:23
6

I may be slightly off-topic as you did mention the need for a username and password, and my understanding of the issue is admitedly not the best but is OpenID something worth considering?

If you use OpenID then you don't end up storing any credentials at all if I understand the technology correctly and users can use credentials that they already have, avoiding the need to create a new identity that is specific to your application.

It may not be suitable if the application in question is purely for internal use though

RPX provides a nice easy way to intergrate OpenID support into an application.

Crippledsmurf
  • 3,874
  • 1
  • 27
  • 49
  • I agree that openID rocks peoples faces off but for this application it is a in house database for a company I doubt they would like any old person coming in to log on. also web access is not needed for this app to work correctly so i would hate to require it. – Crash893 Jun 29 '09 at 01:38
3

In your scenario, you can have a look at asp.net membership, it is good practice to store user's password as hashed string in the database. you can authenticate the user by comparing the hashed incoming password with the one stored in the database.

Everything has been built for this purposes, check out asp.net membership

Ray Lu
  • 24,557
  • 12
  • 57
  • 59
1

I would MD5/SHA1 the password if you don't need to be able to reverse the hash. When users login, you can just encrypt the password given and compare it to the hash. Hash collisions are nearly impossible in this case, unless someone gains access to the database and sees a hash they already have a collision for.

waiwai933
  • 12,962
  • 20
  • 61
  • 82
  • 2
    I wouldn't use MD5 for hashing - it's basically broken http://www.mscs.dal.ca/~selinger/md5collision/ – zebrabox Jun 28 '09 at 15:04
  • 3
    Actually, it's not that broken. What they can do is find the same hash value for two different files. What they can't do is reverse the MD5 and get a working password. – waiwai933 Jun 28 '09 at 19:43
  • 2
    Well, wouldn't that be broken too then? You just enter the other password that generates the same hash, and you're in. You don't need to know the original password. The way to fix this is if you salt the password before hashing. – mjuarez Feb 10 '13 at 13:39
  • 3
    @mjuarez if you add a salt to the password befor you use MD5 the collision doesn't matter because you can't use the other password – WiiMaxx Oct 11 '13 at 13:38