digitalmars.D.learn - Password Storage
- brian (25/25) Nov 26 2015 I'm starting to build a small web-based application where I would
- Alex Parrill (6/32) Nov 26 2015 Do not use MD5 or SHA for hashing passwords. Use PBKDF2, bcrypt,
- brian (12/51) Nov 26 2015 Thanks for the blatant faux pas.
- Alex Parrill (8/19) Nov 26 2015 Yea. I've used bcrypt a few times; it's usually just using the
- H. S. Teoh via Digitalmars-d-learn (14/41) Nov 26 2015 [...]
- brian (57/65) Nov 26 2015 So, I understand what you are trying to say, but I'm stuck on the
- H. S. Teoh via Digitalmars-d-learn (49/69) Nov 26 2015 In this case, the "client" would be the web browser. I'm not too
- Adam D. Ruppe (3/4) Nov 27 2015 I still wouldn't actually store this, hash it anyway and use that
- H. S. Teoh via Digitalmars-d-learn (6/11) Nov 27 2015 True, so you'd store hash(password01) in the database, and compute
- BLM768 (3/7) Nov 27 2015 Another option is SCRAM:
- Chris Wright (21/34) Nov 27 2015 Alternatively, you could do what's industry standard for non-sensitive
- BLM768 (5/19) Nov 26 2015 The issue I see with this is that the server has to _know_ the
- Adam D. Ruppe (5/8) Nov 26 2015 Most web setups can't rely on that tho cuz of the lameness of
- Brad Anderson (3/9) Nov 27 2015 Botan has well thought out password hashing:
- Kagamin (2/2) Nov 27 2015 Another option:
- sarn (4/6) Jan 03 2016 Sorry to revive an old thread, but I wrote a blog post about this
I'm starting to build a small web-based application where I would like to authenticate users, and hence need to store passwords. After reading this: http://blog.codinghorror.com/youre-probably-storing-passwords-incorrectly/ and many other posts that I zombie-surfed to from that page, I'm now fearful of doing this badly. :( My reading of that post was that I should be storing things as: hash = md5('salty-' + password) So when a user tries to authenticate, I need to: 1) validate the user id 2) find the unique "salt" I generated for that user when they registered 3) pre- or post-pend the salt to the password entered (apparently there is a difference??) 4) md5 the lot 5) check this md5(salt+password) against what I have stored. So for each user, I need to store in my database: UserName/UserID Salt Hashed_Password Can the developers in the room confirm if this is the correct approach? Are there examples of betters ways of doing this? Regards Brian
Nov 26 2015
On Friday, 27 November 2015 at 00:17:34 UTC, brian wrote:I'm starting to build a small web-based application where I would like to authenticate users, and hence need to store passwords. After reading this: http://blog.codinghorror.com/youre-probably-storing-passwords-incorrectly/ and many other posts that I zombie-surfed to from that page, I'm now fearful of doing this badly. :( My reading of that post was that I should be storing things as: hash = md5('salty-' + password) So when a user tries to authenticate, I need to: 1) validate the user id 2) find the unique "salt" I generated for that user when they registered 3) pre- or post-pend the salt to the password entered (apparently there is a difference??) 4) md5 the lot 5) check this md5(salt+password) against what I have stored. So for each user, I need to store in my database: UserName/UserID Salt Hashed_Password Can the developers in the room confirm if this is the correct approach? Are there examples of betters ways of doing this? Regards BrianDo not use MD5 or SHA for hashing passwords. Use PBKDF2, bcrypt, or maybe scrypt. There should be C libraries available for those algorithms; use them. More info:
Nov 26 2015
On Friday, 27 November 2015 at 00:42:09 UTC, Alex Parrill wrote:On Friday, 27 November 2015 at 00:17:34 UTC, brian wrote:Thanks for the blatant faux pas. I wasn't going to use MD5, I just meant "hash it somehow", which was not apparent from my question. My bad. Algorithm aside, the rest of that approach seems sensible then? The hash implementation was probably going to be a part 2 of this question. I'd use dcrypt (https://github.com/puzzlehawk/dcrypt) to keep all the d-goodness, but according to the author, that's not "production ready" yet. In lieu of that, I'll have a gander at those libraries you mentioned.I'm starting to build a small web-based application where I would like to authenticate users, and hence need to store passwords. After reading this: http://blog.codinghorror.com/youre-probably-storing-passwords-incorrectly/ and many other posts that I zombie-surfed to from that page, I'm now fearful of doing this badly. :( My reading of that post was that I should be storing things as: hash = md5('salty-' + password) So when a user tries to authenticate, I need to: 1) validate the user id 2) find the unique "salt" I generated for that user when they registered 3) pre- or post-pend the salt to the password entered (apparently there is a difference??) 4) md5 the lot 5) check this md5(salt+password) against what I have stored. So for each user, I need to store in my database: UserName/UserID Salt Hashed_Password Can the developers in the room confirm if this is the correct approach? Are there examples of betters ways of doing this? Regards BrianDo not use MD5 or SHA for hashing passwords. Use PBKDF2, bcrypt, or maybe scrypt. There should be C libraries available for those algorithms; use them. More info:
Nov 26 2015
On Friday, 27 November 2015 at 00:50:25 UTC, brian wrote:Thanks for the blatant faux pas. I wasn't going to use MD5, I just meant "hash it somehow", which was not apparent from my question. My bad. Algorithm aside, the rest of that approach seems sensible then? The hash implementation was probably going to be a part 2 of this question. I'd use dcrypt (https://github.com/puzzlehawk/dcrypt) to keep all the d-goodness, but according to the author, that's not "production ready" yet. In lieu of that, I'll have a gander at those libraries you mentioned.Yea. I've used bcrypt a few times; it's usually just using the hash function to hash the passwords, then the check function to check them, and that's it (bcrypt stores the salt along with the password). I don't know if I'd trust dcrypt yet. No offence to the authors, but I doubt that it has gone through the review that more popular C libraries have.
Nov 26 2015
On Fri, Nov 27, 2015 at 12:17:32AM +0000, brian via Digitalmars-d-learn wrote:I'm starting to build a small web-based application where I would like to authenticate users, and hence need to store passwords. After reading this: http://blog.codinghorror.com/youre-probably-storing-passwords-incorrectly/ and many other posts that I zombie-surfed to from that page, I'm now fearful of doing this badly. :( My reading of that post was that I should be storing things as: hash = md5('salty-' + password) So when a user tries to authenticate, I need to: 1) validate the user id 2) find the unique "salt" I generated for that user when they registered 3) pre- or post-pend the salt to the password entered (apparently there is a difference??) 4) md5 the lot 5) check this md5(salt+password) against what I have stored. So for each user, I need to store in my database: UserName/UserID Salt Hashed_Password Can the developers in the room confirm if this is the correct approach? Are there examples of betters ways of doing this?[...] For authentication, the password shouldn't even be sent over the wire. Instead, the server (which knows the correct password) should send a challenge to the client (i.e., a large random number produced by a good RNG -- which is different each time the user authenticates). The client should then prepend this challenge to the password typed in by the user, and compute the hash of the result. This hash is sent back to the server, which does the same computation on its own, and checks whether the two hash values match. Provided you're using a good cryptographic hash, the only way the client will be able to provide the right answer is if the user actually knows the password. At no time is the password ever sent over the network, encrypted or not. --T
Nov 26 2015
On Friday, 27 November 2015 at 02:05:49 UTC, H. S. Teoh wrote: ...At no time is the password ever sent over the network, encrypted or not. --TSo, I understand what you are trying to say, but I'm stuck on the specifics of implementation, if you'll bear with me.For authentication, the password shouldn't even be sent over the wire. Instead, the server (which knows the correct password) should send a challenge to the clientSo my app is web based, so I don't really have a "client-server" model you are suggesting. I'm building it using Vibe.d with a mongodb backend, so hopefully the "client" will be a web-browser (or in future iterations, a mobile device - let's ignore that for now).random number produced by a good RNG -- which is different each time the user authenticates)I'm not sure why I need this, so I'm going to break down and example. Bob comes in with password "Password01" Once he enters "Password01" I want to: Add a string to it: "StaticRandomString~Password01" Then hash it: hash("StaticRandomString~Password01") which gives me Then to verify Bob is Bob I need to verify So in my DB I need to store : If *this* is the scenario, then the "StaticRandomString" needs to be the same all the time, so I need to store that in the DB too, no? So now my DB contains: "StaticRandomString" Your solution was to random generate the random string at verification time. If I do that I have: "RunTimeRandomString~Password01" Then hash that to get However I can't store that in the DB, because the "RunTimeRandomString" which will produce a different hashed value. Sooo, I need to change this scenario to: Get the Password from the client/user and hash it. Then add on the randomness: "RunTimeRandomString~hashed(clientEntered-Password01)" Get that answer back. Get the password from the server/database and hash it. Add on the same randomness. "RunTimeRandomString~hashed(actualPassword-Password01)" Thus in my db I only need to stored hashed(Password01) Compare results. ... Profit. Am I correct in these descriptions? Which is better? I know this is pedantic and not very language specific, but this is the crux of what I want to know. Doing it is easy. The "making sure I'm doing it right" bit is hard...
Nov 26 2015
On Fri, Nov 27, 2015 at 03:09:38AM +0000, brian via Digitalmars-d-learn wrote:On Friday, 27 November 2015 at 02:05:49 UTC, H. S. Teoh wrote: ...In this case, the "client" would be the web browser. I'm not too familiar with what a web browser might provide javascript on the page, but if javascript has a standard hashing function that could be used for this purpose.At no time is the password ever sent over the network, encrypted or not. --TSo, I understand what you are trying to say, but I'm stuck on the specifics of implementation, if you'll bear with me.For authentication, the password shouldn't even be sent over the wire. Instead, the server (which knows the correct password) should send a challenge to the clientSo my app is web based, so I don't really have a "client-server" model you are suggesting. I'm building it using Vibe.d with a mongodb backend, so hopefully the "client" will be a web-browser (or in future iterations, a mobile device - let's ignore that for now).[...] Based on others' reply, maybe the approach I'm suggesting may not be the best implementation for your case, but in any case, here is how it would work: 1) The server stores password01 in the user database. 2) A client (browser) connects to the server and claims to be a valid user. 3) The server generates a random number, let's call it X, and sends X to the client. (X is the "challenge".) This is done each time somebody tries to authenticate with the server (the value of X will be different each time). 4) The client receives X, prepends it to the password that user types in (presumably the same as password01). The client then computes hash(X + pasword) and sends the result, let's call it Y, back to the server. 5) Meanwhile, the server also computes hash(X + password01), and obtains a value Z. 6) The server receives Y from the client, and compares Y with Z. If Y==Z, then it proves that the client knows the correct password, even though the password itself is never transmitted over the network, because the only way the client can know the value of Z is if it knows the correct password (the user entered the correct password) and does the same computation as the server. If Y!=Z, then the password is incorrect and the server rejects the login attempt. The reason for step (3) is to prevent replay attacks: if the challenge is always the same, then a man-in-the-middle attacker can capture the packets between server and client, and replay the packets containing the client's response to the server later, thus obtaining access to user's account. Since the server's challenge is a random number that's different every time, the attacker won't be able to provide the correct response by replaying a previous correct answer. The reason for step (4) is to prevent an eavesdropper from recovering the password by man-in-the-middle attacks. If the password is sent in plaintext, an attacker that compromised a router between the client and the server (or runs a transparent proxy masquerading as the real server) would be able to read the password off the packet while it's in transit. Even if the password is sent in encrypted form, an attacker who obtains a copy of the ciphertext could run brute-force attacks to recover the plaintext password. By only transmitting a hash (presumably a 1-way hash) back to the server, even if an attacker somehow manages to get a hold of the hash value, it won't actually reveal the password. T -- The irony is that Bill Gates claims to be making a stable operating system and Linus Torvalds claims to be trying to take over the world. -- Anonymousrandom number produced by a good RNG -- which is different each time the user authenticates)I'm not sure why I need this, so I'm going to break down and example.
Nov 26 2015
On Friday, 27 November 2015 at 07:46:33 UTC, H. S. Teoh wrote:1) The server stores password01 in the user database.I still wouldn't actually store this, hash it anyway and use that as the new "password".
Nov 27 2015
On Fri, Nov 27, 2015 at 02:51:30PM +0000, Adam D. Ruppe via Digitalmars-d-learn wrote:On Friday, 27 November 2015 at 07:46:33 UTC, H. S. Teoh wrote:True, so you'd store hash(password01) in the database, and compute hash(X + hash(password)) during authentication. T -- It is of the new things that men tire --- of fashions and proposals and improvements and change. It is the old things that startle and intoxicate. It is the old things that are young. -- G.K. Chesterton1) The server stores password01 in the user database.I still wouldn't actually store this, hash it anyway and use that as the new "password".
Nov 27 2015
On Friday, 27 November 2015 at 16:14:06 UTC, H. S. Teoh wrote:True, so you'd store hash(password01) in the database, and compute hash(X + hash(password)) during authentication. TAnother option is SCRAM: https://en.wikipedia.org/wiki/Salted_Challenge_Response_Authentication_Mechanism
Nov 27 2015
On Fri, 27 Nov 2015 08:09:49 -0800, H. S. Teoh via Digitalmars-d-learn wrote:On Fri, Nov 27, 2015 at 02:51:30PM +0000, Adam D. Ruppe via Digitalmars-d-learn wrote:Alternatively, you could do what's industry standard for non-sensitive sites: * Always use TLS. * Send passwords to the server. Memory regurgitation attacks can reveal these passwords, which allows attackers to reuse those credentials on other sites to impersonate people. * Store salted hashes of passwords rather than the passwords themselves. * Hope that your certificate authority is secure. Actually, hope that *every* certificate authority is secure. Otherwise, MITM attack. Or you can take a slightly more paranoid approach: * Use certificate pinning to prevent MITM attacks. * The client sends a salted hash of their password. You store a salted hash of that. This saves users from their password reuse habits if someone finds an arbitrary code execution flaw or memory regurgitation attack in your server. This approach is at least marginally more secure than yours (if your server randomly generates the same nonce twice for the same person, I can use a replay attack, for instance) and is better vetted. Security is hard.On Friday, 27 November 2015 at 07:46:33 UTC, H. S. Teoh wrote:True, so you'd store hash(password01) in the database, and compute hash(X + hash(password)) during authentication. T1) The server stores password01 in the user database.I still wouldn't actually store this, hash it anyway and use that as the new "password".
Nov 27 2015
On Friday, 27 November 2015 at 02:05:49 UTC, H. S. Teoh wrote:For authentication, the password shouldn't even be sent over the wire. Instead, the server (which knows the correct password) should send a challenge to the client (i.e., a large random number produced by a good RNG -- which is different each time the user authenticates). The client should then prepend this challenge to the password typed in by the user, and compute the hash of the result. This hash is sent back to the server, which does the same computation on its own, and checks whether the two hash values match. Provided you're using a good cryptographic hash, the only way the client will be able to provide the right answer is if the user actually knows the password. At no time is the password ever sent over the network, encrypted or not. --TThe issue I see with this is that the server has to _know_ the password in order to hash it with the challenge. If the server is compromised, guess who else knows the password now? Some kind of public-key encryption/signing might work, though.
Nov 26 2015
On Friday, 27 November 2015 at 02:05:49 UTC, H. S. Teoh wrote:For authentication, the password shouldn't even be sent over the wire. Instead, the server (which knows the correct password) should send a challenge to the clientMost web setups can't rely on that tho cuz of the lameness of client side scripting... But at least if the password is sent over https you don't have to worry too much about the wire.
Nov 26 2015
On Friday, 27 November 2015 at 00:17:34 UTC, brian wrote:[snip] Can the developers in the room confirm if this is the correct approach? Are there examples of betters ways of doing this? Regards BrianBotan has well thought out password hashing: https://github.com/etcimon/botan/wiki/Password-Hashing
Nov 27 2015
Another option: http://forum.dlang.org/post/lts93o$2fr0$1 digitalmars.com
Nov 27 2015
On Friday, 27 November 2015 at 00:17:34 UTC, brian wrote:3) pre- or post-pend the salt to the password entered (apparently there is a difference??)Sorry to revive an old thread, but I wrote a blog post about this question: https://theartofmachinery.com/2016/01/03/What%20Difference%20Can%20Order%20Make%20When%20Hashing.html
Jan 03 2016