Suggestions required for rigid security

Discussions of secure PHP coding. Security in software is important, so don't be afraid to ask. And when answering: be anal. Nitpick. No security vulnerability is too small.

Moderator: General Moderators

Roja
Tutorials Group
Posts: 2692
Joined: Sun Jan 04, 2004 10:30 pm

Post by Roja »

neophyte wrote: Not sure how I convert stored db passwords that are already hashed to md5 to sha256. I've seen Feyd's class but I haven't looked at it closely enough to know how to implement it. I suppose for the future I could sha256(md5(password)) passwords. I'm going to take a closer look at his class. Any suggestions on switching would be great!
Ah. Wasn't aware you already had stored passwords.

There are a couple ways you can do it in that situation. You can, as you said, sha256 the md5 hash of the password. Its a bit overkill, but hey, it works.

You can also have two columns per user - sha_pass, and md5_pass. Have your javascript send both hashes of the password - one in md5, and one in sha. Check the md5, and if it matches, store the sha in the new column, and mark the md5 with null or zero. Transparent, the user knows nothing of it happening, and over time, all the active users will be converted. Plus, its more secure than sending the password in cleartext.

As to how to implement sha256, its literally a drop-in replacement for the js md5 function. Just change the names, and you should be all set. On the PHP side, it doesn't use exactly the same references, so you'll have to look at feyd's (extremely well-documented) code.
User avatar
Stryks
Forum Regular
Posts: 746
Joined: Wed Jan 14, 2004 5:06 pm

Post by Stryks »

I was going to bring this up in an earlier post where I was dealing with similar issues actually, but I kind of got sidetracked.

Encrypting the login with javascript before it is transferred for login does pose the question, what about when the user initially joins or changes their password?

Encrypting the password before sending is fine there too I guess, but if you simply store that hashed value, then instead of intercepting the cleartext password they have intercepted the hashed equivalent. Easy work then to make up your own login form and pass the hash across. Only one step harder than the cleartext equivalent.

Perhaps this is why the client-side encryption method is usually attached to one-time-padding for logins, to protect against just this thing.

I realise this is probrably more confusing than clarifying, but I think it's a relevant issue. What is the benefit of securing the login when all anyone needs to do is listen to your password issue / change form?

No just bagging this either ... just genuinely interested.
Roja
Tutorials Group
Posts: 2692
Joined: Sun Jan 04, 2004 10:30 pm

Post by Roja »

Stryks wrote: Encrypting the login with javascript before it is transferred for login does pose the question, what about when the user initially joins or changes their password?
You should use a one-time pad. (ie, send user one-time pad, they send sha256($onetime_pad.$hashed_pass)).
Stryks wrote: Encrypting the password before sending is fine there too I guess, but if you simply store that hashed value, then instead of intercepting the cleartext password they have intercepted the hashed equivalent. Easy work then to make up your own login form and pass the hash across. Only one step harder than the cleartext equivalent.
Thats true even in a standard login. Notice now you are trying to solve a different problem. Hashed logins prevent two issues:

- Cleartext storage of passwords (admins can view, compromised databases can view)
- Cleartext transmission of password across hostile networks

That *is* a security advantage by itself (ie, without one-time pads). It prevents casual sniffing of the network to view passwords, and prevents compromised databases from giving out passwords. However..
Stryks wrote: Perhaps this is why the client-side encryption method is usually attached to one-time-padding for logins, to protect against just this thing.
Correct. One-time pads solve the replay attack issue. In a session replay attack, the attacker takes your session credentials and replays them to the server - getting access as you.

With a one-time pad, the window for him to do so is extremely small, and more complex. (He has to see the traffic in both directions - the one-time pad coming in AND the session credentials going out).
Stryks wrote: I realise this is probrably more confusing than clarifying, but I think it's a relevant issue. What is the benefit of securing the login when all anyone needs to do is listen to your password issue / change form?
Like I said above, it solves two (different) issues from one-time pads: Cleartext password storage, and cleartext transmission of the password. Those are very different problems, and are no more or less important for overall security.

Security is a process. You work over time to improve the security of each link. Once you secure one part (js login passing hashed logins), another sticks out as being insecure. It was always insecure, its just more obvious now (to you AND to attackers). So then you improve that too (use one-time pads), and suddenly, the weakest link will be the fact that you still use register_globals=on (D'OH!).

It's a process.. there is no quick fix.
User avatar
Stryks
Forum Regular
Posts: 746
Joined: Wed Jan 14, 2004 5:06 pm

Post by Stryks »

I guess my point regarding this is that you can't really one-time-pad the page where the user sets the password. If you were to do that then the password you recieved wouldn't be of much use to you.

You could store it, but then how could you compare it? When you one-time-pad your login, you would have to hash the password with it's original OTP before hashing it with the new one in order to have something to compare it to, and the only way to do that is to put the original OTP client-side.

I do consider the issues linked, although I do take your point. Clearly, a hashed password is going to be much more secure than anything cleartext - *shudder*.

Still, if the issue is to prevent cleartext transmission of the password, surely there must be some reasonably secure method of transferring the password in it's original state at the point where the user actually sets it.

As I mentioned, I don't know the answer to this one (if there is one) ... I for one just do a straight password hash before I send it to be saved, and then use OTP for logins. I just thought it would be worth it for the original poster to keep in mind that logins aren't the only place where cleartext passwords are sent.
Roja
Tutorials Group
Posts: 2692
Joined: Sun Jan 04, 2004 10:30 pm

Post by Roja »

Stryks wrote:I guess my point regarding this is that you can't really one-time-pad the page where the user sets the password. If you were to do that then the password you recieved wouldn't be of much use to you.
Sorry, I misunderstood the situation.

You have two options. First, you can use a two-way encryption/decryption function. (3DES comes to mind). That way, you can send an encrypted key, which they decrypt, and they can send their encrypted password (encrypted using that key).

Thats essentially a true CHAP login.

Or, you can accept that the window of opportunity for an attacker being limited to the (5?) minutes while a user initially logs in is "secure enough".
Stryks wrote:I just thought it would be worth it for the original poster to keep in mind that logins aren't the only place where cleartext passwords are sent.
So very, very true.
User avatar
raghavan20
DevNet Resident
Posts: 1451
Joined: Sat Jun 11, 2005 6:57 am
Location: London, UK
Contact:

Post by raghavan20 »

I already have sha256() in place. Is it necessary to md5(sha256(password))?
I am looking for suggestions.
Roja
Tutorials Group
Posts: 2692
Joined: Sun Jan 04, 2004 10:30 pm

Post by Roja »

raghavan20 wrote:I already have sha256() in place. Is it necessary to md5(sha256(password))?
No!
User avatar
neophyte
DevNet Resident
Posts: 1537
Joined: Tue Jan 20, 2004 4:58 pm
Location: Minnesota

Post by neophyte »

Roja wrote:You have two options. First, you can use a two-way encryption/decryption function. (3DES comes to mind). That way, you can send an encrypted key, which they decrypt, and they can send their encrypted password (encrypted using that key).
What is 3DES?

Thanks
User avatar
shiflett
Forum Contributor
Posts: 124
Joined: Sun Feb 06, 2005 11:22 am

Post by shiflett »

phpScott wrote:store the hash in a hidden field then use that in your php code.
Disclaimer: I didn't read every post, so apologies in advance if I'm misunderstanding something.

If you're suggesting storing a hash in a hidden field and then accepting that same hash as a valid authentication credential, then this is a terrible idea.

If not, perhaps you can clarify what you mean.
Roja
Tutorials Group
Posts: 2692
Joined: Sun Jan 04, 2004 10:30 pm

Post by Roja »

shiflett wrote: If you're suggesting storing a hash in a hidden field and then accepting that same hash as a valid authentication credential, then this is a terrible idea.
I'm very familiar with your background, but I (somewhat) disagree on this point, and I explained the reasons why above. Please read the full thread for clarification.
neophyte wrote:What is 3DES?
Its a two-way (encrypt/decrypt) true encryption function: http://en.wikipedia.org/wiki/3DES
User avatar
Weirdan
Moderator
Posts: 5978
Joined: Mon Nov 03, 2003 6:13 pm
Location: Odessa, Ukraine

Post by Weirdan »

Roja wrote:
Stryks wrote: Encrypting the password before sending is fine there too I guess, but if you simply store that hashed value, then instead of intercepting the cleartext password they have intercepted the hashed equivalent. Easy work then to make up your own login form and pass the hash across. Only one step harder than the cleartext equivalent.
Thats true even in a standard login. Notice now you are trying to solve a different problem. Hashed logins prevent two issues:

- Cleartext storage of passwords (admins can view, compromised databases can view)
- Cleartext transmission of password across hostile networks

That *is* a security advantage by itself (ie, without one-time pads). It prevents casual sniffing of the network to view passwords, and prevents compromised databases from giving out passwords.
Without the OTP this is essentially the same as storage and transmission of passwords in clear-text. If you hash a password at the client side, then compare it to the same hash, stored in your db - that hash effectively becames a clear-text password! And further, suppose your db is compromised (attackers have all of those hashes). And there's OTP used, yeah :). In this case to get logged in, all they have to do is to get OTP from your server, then send sha256($OTP . $hash_they_know) back.

To sum up, storing hashes into DB works only because an attacker has to present clear-text password to your server (which is reasonably hard to derive from a hash they have obtained).
Roja
Tutorials Group
Posts: 2692
Joined: Sun Jan 04, 2004 10:30 pm

Post by Roja »

Weirdan wrote: Without the OTP this is essentially the same as storage and transmission of passwords in clear-text.
Careful on wording - no, its not essentially the same.

Is it still risky? Yes. Is it better than true cleartext storage and transmission? Yes. There *is* a difference between the two, and it is a worthwhile difference.
Weirdan wrote:If you hash a password at the client side, then compare it to the same hash, stored in your db - that hash effectively becames a clear-text password!
Nope. Three differences: Can I take that hash and login to a different website that uses a different hash with it? No. Can I *view* the password and use it to login on a different website that uses a different hash with it? No.

Can I guess that since you use the password "phpdn-pass" here, that you probably use "cnn-pass" on cnn? No. There *is* a difference between the two, and it is a worthwhile difference.
Weirdan wrote: In this case to get logged in, all they have to do is to get OTP from your server, then send sha256($OTP . $hash_they_know) back.
The difference there is that the OTP is short-lived, and thus the danger is limited to a very narrow window. Thats the entire principle of CHAP, which has been in use for over a decade now.
Weirdan wrote: To sum up, storing hashes into DB works only because an attacker has to present clear-text password to your server (which is reasonably hard to derive from a hash they have obtained).
To sum up, there is a difference, and you are ignoring those differences.
User avatar
Weirdan
Moderator
Posts: 5978
Joined: Mon Nov 03, 2003 6:13 pm
Location: Odessa, Ukraine

Post by Weirdan »

Roja wrote: Nope. Three differences: Can I take that hash and login to a different website that uses a different hash with it? No. Can I *view* the password and use it to login on a different website that uses a different hash with it? No.

Can I guess that since you use the password "phpdn-pass" here, that you probably use "cnn-pass" on cnn? No.
And... does it improve the overall security of my web-app. No.

I must admit that your point does make sense. That's up to the programmer to decide if he/she really care about rest of the Web, though.
Roja wrote:
Weirdan wrote: In this case to get logged in, all they have to do is to get OTP from your server, then send sha256($OTP . $hash_they_know) back.
The difference there is that the OTP is short-lived, and thus the danger is limited to a very narrow window. Thats the entire principle of CHAP, which has been in use for over a decade now.
CHAP is aimed against sniffing and replay attacks. The scenario I proposed was quite different: somehow an attacker obtained hash of the password (that very hash your app kept in its database), through SQL injection or some other way. Does client-side hashing offer any protection in this case? Apparently no. Does it reduce security (time to crack, actually) in this case. It appears so. And that's the main issue I would like to discuss.
Roja wrote:
Weirdan wrote: To sum up, storing hashes into DB works only because an attacker has to present clear-text password to your server (which is reasonably hard to derive from a hash they have obtained).
To sum up, there is a difference, and you are ignoring those differences.
Thanks for pointing that out, now I ignore those differences knowingly :).

P.S. Let's keep this thread technical.
User avatar
Stryks
Forum Regular
Posts: 746
Joined: Wed Jan 14, 2004 5:06 pm

Post by Stryks »

This has become an interesting little thread - one that I think alot of people should be paying attention to, because it is an issue that really bears alot of thinking about.

What I'm interested in at this point, is a suggestion of what you WOULD do Weirdan. I've seen alot of your posts around from a long way back and frankly, as someone who has learned PHP mostly from these forums, I would be foolish not to respect your experience.

What do you think is a viable option?

I've been looking at using encryption for the password transfer, but I just cant see how any symmetrical system (Triple DES, blowfish, etc.) is going to work, as the secret must be shared on the client side, which pretty much defeats the purpose.

I could be wrong there though. It just occurred to me that only an asymmetrical encryption method would work in this situation.

The user is sent a public key which is used to encrypt the password on the client side. The password could not then be decrypted without the private key, even if the public key had been intercepted with the encrypted value.

I've searched high and low though, and I can't seem to find a reliable RSA / ElGamal etc. implementation which produces identical results in both javascript and PHP, so I'm at a loss for how to implement this.

I'd love to find some kind of solution for this, but as I mentioned elsewhere, I'm going to be using SSL (along with alot of application level security) because I'm dealing with sensitive data (not credit card info) and I just can't assess the true threat level.

Damn, looks like I've been reading too much info on this again. Going to have to stop.


:lol:
Roja
Tutorials Group
Posts: 2692
Joined: Sun Jan 04, 2004 10:30 pm

Post by Roja »

Weirdan wrote: CHAP is aimed against sniffing and replay attacks. The scenario I proposed was quite different: somehow an attacker obtained hash of the password (that very hash your app kept in its database), through SQL injection or some other way. Does client-side hashing offer any protection in this case? Apparently no. Does it reduce security (time to crack, actually) in this case. It appears so. And that's the main issue I would like to discuss.
Okay, lets head on that tangent, I'm interested. :)

How does a hashed password *reduce* the time to crack compared with a plaintext password? If anything, I would think it would increase the time, since the hash has far more entropy, and far more possibilities. Even with md5, its 32 digits long, and each is hex (16 possibilities), which is far more complex than the vast majority of passwords. I think it would be fair to say that less than 5% of the population uses passwords with more than 32^16 possibilities.

So, what did I miss, how does it reduce the time to crack? (Or are you comparing *just* having a hashed password versus having a hashed password AND a OTP? Because on that, we'd agree. I'm all about OTP's. They are far more secure.)
Post Reply