Jump to page: 1 2
Thread overview
Password Storage
Nov 27, 2015
brian
Nov 27, 2015
Alex Parrill
Nov 27, 2015
brian
Nov 27, 2015
Alex Parrill
Nov 27, 2015
H. S. Teoh
Nov 27, 2015
brian
Nov 27, 2015
H. S. Teoh
Nov 27, 2015
Adam D. Ruppe
Nov 27, 2015
H. S. Teoh
Nov 27, 2015
BLM768
Nov 28, 2015
Chris Wright
Nov 27, 2015
BLM768
Nov 27, 2015
Adam D. Ruppe
Nov 27, 2015
Brad Anderson
Nov 27, 2015
Kagamin
Jan 03, 2016
sarn
November 27, 2015
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
November 27, 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
> Brian

Do 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: http://security.stackexchange.com/questions/211/how-to-securely-hash-passwords/31846#31846
November 27, 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:
>> 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
>
> Do 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: http://security.stackexchange.com/questions/211/how-to-securely-hash-passwords/31846#31846

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.


November 27, 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.
November 27, 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
November 27, 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.
>
> --T
So, 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 client

So 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
"I#$%am%^&Random(*&LOL*&"

Then to verify Bob is Bob I need to verify "I#$%am%^&Random(*&LOL*&" against something in the database?
So in my DB I need to store :
"I#$%am%^&Random(*&LOL*&"

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"
"I#$%am%^&Random(*&LOL*&"

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
"I#$%Too$%456^(am(*$&Random(*&LOL*&"

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...
November 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.
>
>
> --T

The 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.
November 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

Most 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.
November 27, 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: ...
> >At no time is the password ever sent over the network, encrypted or not.
> >
> >--T
> So, 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 client
> 
> So 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).

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.


> >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.
[...]

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. -- Anonymous
November 27, 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
> Brian

Botan has well thought out password hashing:

https://github.com/etcimon/botan/wiki/Password-Hashing
« First   ‹ Prev
1 2