Page 2 of 2
Re: Validate user input
Posted: Sat Jul 21, 2007 7:54 pm
by Chalks
The Phoenix wrote:Chalks wrote:I'm not sure I understand. I think what you're saying is to make sure I'm not sending the password from the form to my php script in cleartext. If so, wouldn't that mean that I would have to figure out a way to encrypt it client side first?
Yes. Javascript is the usual method. Google javascript md5, and Paj's work should come up. Very solid js libraries for encryption.
Ok, I have a javscript algorithm for md5 and for sha1. However, if I send the password with the md5/sha1 algorithym, should I rehash it with sha256 in my php script? Or de-encrypt it in the script and re-encrypt into the more secure sha256? Or do I have to find a javascript version of sha256 as well?
Thanks for all the answers I've gotten everyone. They've helped a ton! I'll be posting my Login class once I've got all this figured out (almost done!).
Edit: one more question that goes along with the above ones: How do I salt a password string if I have to encrypt it before I send it to the server?
Re: Validate user input
Posted: Sun Jul 22, 2007 8:45 am
by The Phoenix
Chalks wrote:Ok, I have a javscript algorithm for md5 and for sha1. However, if I send the password with the md5/sha1 algorithym, should I rehash it with sha256 in my php script?
Won't work.
Chalks wrote:Or de-encrypt it in the script and re-encrypt into the more secure sha256?
Can't decrypt it. Hashes are one-way only.
Chalks wrote:Or do I have to find a javascript version of sha256 as well?
If you want to use sha256 instead on the server side, you need to do the same on client side:
http://anmar.eu.org/projects/jssha2/
Chalks wrote:Edit: one more question that goes along with the above ones: How do I salt a password string if I have to encrypt it before I send it to the server?
Remember, the server sent the salt (which is okay, because its one-time use only).
md5 (md5($password) . $salt_from_server);
Then the server is going to do the same thing.
md5 ($md5_password_stored_in_db . $salt_from_server);
Posted: Sun Jul 22, 2007 9:15 am
by Chalks
Ok, I think I've got it:
1. encrypt password client side using javascript.
password -> 5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8
1.5 make sure password got hashed before adding salt... if not, hash it (if javascript wasn't on).
2. send password hash to server and add salt/pepper
$tmp = "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8" . "salt";
3. hash the password with salt
sha1($tmp);
4. dance wildly.
Of course, 2 and 3 can be combined into one step. Also, I have two ideas: Is it a good idea to put my salt into the password at strange intervals? as in:
5baaT61e4Hc9b9E3f3fS0682A250bL6cf8T331bY7ee6!8fd8
Also, to make sure that no password can have the same hash as any other (even if the users have the same password), could I add the username as an additional salt? That way I have my normal salt that should mess up dictionary attacks, and my unique salt that prevents hashes from being the same.
Posted: Sun Jul 22, 2007 5:14 pm
by The Phoenix
Chalks wrote:Ok, I think I've got it:
Very close. The devil is in the details now.
Chalks wrote:1. encrypt password client side using javascript.
password -> 5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8
Hashing is encrypting but not all encrypting is hashing, so lets be specific and say HASH password client side using js.
Chalks wrote:1.5 make sure password got hashed before adding salt...
Yes.
Chalks wrote:if not, hash it (if javascript wasn't on).
If js isn't on, you can't hash it. But yes, you still need to hash before adding the salt.
Chalks wrote:2. send password hash to server and add salt/pepper
$tmp = "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8" . "salt";
Salt isn't pepper.
Don't sent it to the server before adding the salt.
Otherwise, the attacker can get the hash ($tmp up to salt) separately.
Chalks wrote:3. hash the password with salt
sha1($tmp);
Of course, 2 and 3 can be combined into one step.
SHOULD be combined into one step, otherwise it is insecure.
Chalks wrote:
Also, I have two ideas: Is it a good idea to put my salt into the password at strange intervals? as in:
5baaT61e4Hc9b9E3f3fS0682A250bL6cf8T331bY7ee6!8fd8
Doesn't make a difference really, except adding more cycles to both the client and server side for a negligable gain in security. Hashing is going to take care of the potential for sniffing.
Chalks wrote:
Also, to make sure that no password can have the same hash as any other (even if the users have the same password), could I add the username as an additional salt?
You could. There isn't a huge value in ensuring no two users have the same hash, but I can see the theoretical value. So, yes, you could do so.
Posted: Sun Jul 22, 2007 7:18 pm
by Chalks
Sweet! I've got everything finished and set up except for:
The Phoenix wrote:Salt isn't pepper. Don't sent it to the server before adding the salt.
Otherwise, the attacker can get the hash ($tmp up to salt) separately.
But what value is it to add the salt on client side? I mean, if I add it using javascript, the user knows what the salt is. If I send the salt to the javascript using php, that will still be visible:
the source of the page would be
I mean, the whole thing is probably secure enough for my purposes without adding a salt at all, but... if I ever build something that needs higher security, I want to have experience being super paranoid.

Also: that's my final question, promise. Hehe
Posted: Sun Jul 22, 2007 8:31 pm
by The Phoenix
Chalks wrote:But what value is it to add the salt on client side? I mean, if I add it using javascript, the user knows what the salt is. If I send the salt to the javascript using php, that will still be visible:
...
The thing is probably secure enough for my purposes without adding a salt at all, but... if I ever build something that needs higher security, I want to have experience being super paranoid.

Also: that's my final question, promise. Hehe
Completely reasonable question. Remember, the salt is one-time only, and is not intended to be a fully secret item. The intent/purpose is to ensure that what is sent is something other than a reproducible login token (hashed password).
An assumed attacker listening on the line gets the salt, and knows the hash algorithm, but can't derive the password - because the salt was included with the hashed password prior to hashing, prior to sending.
Now, if an attacker had control of the users browser, it would be bad, but then even ssl won't save the user.
Posted: Mon Jul 23, 2007 11:41 pm
by Chalks
feyd | Please use Code: Select all
and [syntax="..."] tags where appropriate when posting code. Your post has been edited to reflect how we'd like it posted. Please read: [url=http://forums.devnetwork.net/viewtopic.php?t=21171]Posting Code in the Forums[/url] to learn how to do it too.[/color]
Ok. everything hard is practically coded now. I'm only having one difficulty:
1. the user clicks on the submit button.
2. before the data is sent to server:
3. the username length is validated
4. the password length is validated
5. I make sure the username only contains a-zA-Z0-9
if everything validates:
6. salt is added to password
7. that is hashed
8. username and hashed password+salt is sent to server.
The problem is at #6. Here's the javascript function:
[syntax="javascript"]
function validate(form, pass, user)
{
if(checkPass(form, pass) & checkUser(form, user))
{
pass = pass.concat("nzuw774lo1t3aml");
pass = SHA256(pass);
form.pass.value = pass;
form.salt.value = "nzuw774lo1t3aml";
}
form.password.value = ""; //so that the plaintext password isn't sent
}
See my salt value "nzuw774lo1t3aml"? That's randomly generated when the page loads, but I can't figure out how to make the salt value the SAME salt value that the user had when he first was registered. Of course, if the salt isn't the same as what it was when first registered, the hash is different, therefore incomparable. I tried doing this:
Code: Select all
function validate(form, pass, user)
{
if(checkPass(form, pass) & checkUser(form, user))
{
pass = pass.concat("<?php $dbf->getUserSalt("?>user<?php");?>"); //$dbf is my DataBaseFunctions class
pass = SHA256(pass);
form.pass.value = pass;
form.salt.value = "nzuw774lo1t3aml";
}
form.password.value = ""; //so that the plaintext password isn't sent
}
but that doesn't work for two reasons (and here's where it gets weird). One, I just think that's bad syntax. Two: to get that javascript function onto my html page I call a function from my Login class called createJavascript(), and that one line would turn into:[/syntax]
Code: Select all
echo " pass = pass.concat(\"<?php $dbf->getUserSalt(\"?>user<?php\");?>\");\n";
which... is... a tad not good (and it doesn't work). What should I do?
So. I'm going crazy.
Oh, and I guess I lied about that other question being my last.
feyd | Please use Code: Select all
and [syntax="..."] tags where appropriate when posting code. Your post has been edited to reflect how we'd like it posted. Please read: [url=http://forums.devnetwork.net/viewtopic.php?t=21171]Posting Code in the Forums[/url] to learn how to do it too.[/color]
Posted: Tue Jul 24, 2007 1:30 pm
by The Phoenix
Chalks wrote:That's randomly generated when the page loads, but I can't figure out how to make the salt value the SAME salt value that the user had when he first was registered.
You don't make the salt the same salt value that the user had when he first registered. During registration, he sends you simply the hashed password.
We didn't really talk about that first part.. just everything that happened after registration.
Yes, that means you store the unsalted hashed password.
Yes, that means that (once) you transmitted the unsalted hashed password.
There are methods to improve both of those issues, but thats a whole different discussion. A much larger one..
Posted: Tue Jul 24, 2007 5:55 pm
by Chalks
OH. so:
register:
send hashed password to database (hash before sending to server).
login:
send hash of (hashed password + salt) and salt to server
SELECT hashed password from database
hash that with the salt which was sent, and check against sent hash.
TADA!
I was trying to make this more complicated than it really was. Thank you very much The Pheonix!
Posted: Tue Jul 24, 2007 10:13 pm
by Chalks
Sorry for the double post, but... I'm excited. I finished building my login page with the following security features:
uses js to make sure that the username and password are at least 6 characters long.
uses js to make sure that the username only contains a-zA-Z0-9.
uses js to hash the password with sha256 before it is sent to the server.
uses js to add a salt to the password as well.
uses js to make sure every single password hash is different (even if different users have same pass).
if js is disabled:
displays a warning before you login ("js is disabled!").
sends username and password to server in plaintext (bad, but... js is disabled).
server does everything that js did client side except for adding the salt (unnecessary now).
classes used:
feyd's sha256 classes (I'm 99% sure I implemented them properly).
Login.php class (created by myself)
LoginDatabase.php class (created by myself)
LoginDriver.php (created by myself)
Get it here!
(You'll also need feyd's sha256 stuff too... see above)
Posted: Wed Jul 25, 2007 9:43 am
by The Phoenix
Chalks wrote:I finished building my login page with the following security features:
Get it here!
(You'll also need feyd's sha256 stuff too... see above)
Seriously impressive.. Fast work.
Congratulations.
P.S. Might want to clarify what kind of license it is under in the file.. i.e. fully free to use in anything, GPL, BSDL, etc.
Re: Validate user input
Posted: Wed Jul 25, 2007 11:27 pm
by Z3RO21
The Phoenix wrote:superdezign wrote:The Phoenix wrote:Make sure you aren't sending the password in cleartext to test it. If you are going to test the password (and there are many good reasons not to), do it client-side via javascript.
Whoa, that is a fantastic suggestion. I've never even considered it before. However, what about when JavaScript is disabled? Do you check against this in PHP (likely in a posted value) to determine whether or not it was processed prior to posting?
Its a tough one! Here's my thinking about it.
If a user comes to my site, and doesn't know better (doesn't manually change his settings),
he/she is the user that needs protecting the most. So, by default, I use javascript to encrypt the password before transmission.
If, on the other hand, a user who knows what he/she is doing, and disabled javascript? Well, they are smart enough to disable javascript, and should be smart enough to avoid the risks of shared passwords.
What I do is I check the length of the password sent. If it encrypted, its 40 or 56 characters or whatever. If its not encrypted, its likely to be limited to the length of the text field (conveniently set smaller than the encrypted length).
If so, I put up a results page that warns that with javascript disabled, the passwords are sent in the clear,
but I still attempt to authenticate the user, by doing the encryption of the submitted password server side.
Best of both worlds, and protects the largest number of users, I think.
I'm welcome to discussion about whether its non-ideal. The one real bummer about it is that you can't (easily/securely) allow users to save their passwords via the browser controls since it replaces the textfield entry with the js encrypted version before submission.
I use the same set up, with OOP I test the input if it is encrypted create a user object based on username and password hash, or if the password is not encrypted create a user object based on the username and a newly created password object.