Page 1 of 2

Validate user input

Posted: Thu Jul 19, 2007 10:53 am
by Chalks
This thread alerted me to the idea of SQL injection, and I now have a question... but I didn't want to threadjack. So, new thread! :D

My login page has the following protections in place:

sha1 encrypt passwords before sending to database.
limit usernames and passwords to 15 characters (but the database holds more than 40... so that the sha1 works).
use regex to say "if input include ONLY a-z, 0-9 or _ allow it" (using: "#\w+#").
if either username field or password field is blank, don't call any mysql queries.

I don't have a register page (I manually insert 1-2 users... this is small scale) so I only have to worry about invalid data on the main login page.


What should I add/do to prevent sql injection and/or more sophisticated attacks?

Allow 3 login attempts per minute?
Auto logout after x minutes?
Encrypt password using something stronger than sha1 (along those lines... how do you "salt" the encrypt)?
Anything else?

Posted: Thu Jul 19, 2007 11:36 pm
by feyd
  • Why would you make a maximum length for passwords? It's better to require a minimum length.
  • use regex against which input(s)?
  • \w matches far more than [a-z0-9_].
A salt is simply extra, often high entropy, data added to the hash input stream. It's best to make it long enough that the hash will require two internal iterations to complete the hash. That is, the complete input, salt and data are longer than the internal buffer. For SHA1, I believe the internal size is 320 bits (40 bytes); SHA256 requires 512 bits (64 bytes) to fill it's internal buffer past one iteration.

Posted: Fri Jul 20, 2007 7:47 am
by Chalks
feyd wrote:
  • Why would you make a maximum length for passwords? It's better to require a minimum length.
I don't know... I wasn't thinking. That's fixed now.
feyd wrote:
  • use regex against which input(s)?
Against the username field and the password field (the only two fields on this particular form).
feyd wrote:
  • \w matches far more than [a-z0-9_].
Really? According to (a) Regex CRASH Course! (Pt. 1)
d11wtg wrote:

Code: Select all

\w                Any single alphanumeric character (a-z, 0-9) and underscores
If that's not right, could I just use #[a-z0-9_]+# as my pattern instead? Actually, now that I think about it, that (and my previous pattern) could match as little as 1 character, leaving the rest free to be whatever. I was only testing to see if there was a match, if there was... go ahead. So maybe #[^a-z0-9_]# would work better, and if there was a match, DON'T go ahead. I'm not sure.

feyd wrote:A salt is simply extra, often high entropy, data added to the hash input stream. It's best to make it long enough that the hash will require two internal iterations to complete the hash. That is, the complete input, salt and data are longer than the internal buffer. For SHA1, I believe the internal size is 320 bits (40 bytes); SHA256 requires 512 bits (64 bytes) to fill it's internal buffer past one iteration.
Oh! That makes sense now. :D

Posted: Fri Jul 20, 2007 5:27 pm
by feyd
Chalks wrote:Against the username field and the password field (the only two fields on this particular form).
I'll agree username is fine, but that's a personal choice. On passwords, I would not limit them in character choices in any way.
Chalks wrote:Really? According to (a) Regex CRASH Course! (Pt. 1)
d11wtg wrote:

Code: Select all

\w                Any single alphanumeric character (a-z, 0-9) and underscores
If that's not right, could I just use #[a-z0-9_]+# as my pattern instead? Actually, now that I think about it, that (and my previous pattern) could match as little as 1 character, leaving the rest free to be whatever. I was only testing to see if there was a match, if there was... go ahead. So maybe #[^a-z0-9_]# would work better, and if there was a match, DON'T go ahead. I'm not sure.
Yes, really. Unfortunately, d11wtq was misguided at the time. Note the correction here: viewtopic.php?p=245010#245010

Posted: Fri Jul 20, 2007 10:37 pm
by Chalks
feyd wrote:Yes, really. Unfortunately, d11wtq was misguided at the time. Note the correction here: viewtopic.php?p=245010#245010
I see!

And I was thinking... since the only place I would ever possibly use the password in my scripts would be to send it to a mysql database... mysql_real_escape_string() is all I really need to worry about for the password field, right?



Thanks very much for your help, feyd. :)

Posted: Fri Jul 20, 2007 10:46 pm
by feyd
mysql_real_esacpe_string() is your last line of defense for database bound data. You should often validate and verify information before escaping it however.

Posted: Fri Jul 20, 2007 10:51 pm
by Chalks
So I'll double, triple, quadruple my defenses, _then_ escape it. It's like I'm kicking the hacker while he's down!

Hehe... I probably enjoy this stuff far too much. :D

Re: Validate user input

Posted: Sat Jul 21, 2007 4:58 am
by The Phoenix
Chalks wrote:limit usernames and passwords to 15 characters (but the database holds more than 40... so that the sha1 works).
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.

Otherwise all the protections you are building can be defeated by a simple network snoop (tcpdump, ethereal, etc).
Chalks wrote:Allow 3 login attempts per minute?
5 is a little more reasonable, but the key isn't just automated lock-out, its also logging. Make sure it is logged, AND that the admin gets a (relatively noticable) notification of those attempts.
Chalks wrote:Auto logout after x minutes?
Yes, but also look at regenerating session ids also.
Chalks wrote:Encrypt password using something stronger than sha1 (along those lines... how do you "salt" the encrypt)?
Feyd's SHA256 class is fantastic.

Re: Validate user input

Posted: Sat Jul 21, 2007 9:47 am
by superdezign
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?

Re: Validate user input

Posted: Sat Jul 21, 2007 10:21 am
by The Phoenix
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.

Re: Validate user input

Posted: Sat Jul 21, 2007 10:28 am
by superdezign
The Phoenix wrote: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).
Instead of limiting the length of a user's password, why not post a variable through JavaScript, or concatenate a string to successfully encrypted passwords that would be stripped away?

Re: Validate user input

Posted: Sat Jul 21, 2007 10:52 am
by The Phoenix
superdezign wrote:
The Phoenix wrote: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).
Instead of limiting the length of a user's password, why not post a variable through JavaScript, or concatenate a string to successfully encrypted passwords that would be stripped away?
Either could work. Of the two, I'd probably do the first.

In my experience, its far less than 1% of users that would need a password longer than 25+ characters, so it was an easy cop out. :)

Re: Validate user input

Posted: Sat Jul 21, 2007 11:42 am
by superdezign
The Phoenix wrote:
superdezign wrote:
The Phoenix wrote: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).
Instead of limiting the length of a user's password, why not post a variable through JavaScript, or concatenate a string to successfully encrypted passwords that would be stripped away?
Either could work. Of the two, I'd probably do the first.

In my experience, its far less than 1% of users that would need a password longer than 25+ characters, so it was an easy cop out. :)
Hehe, I remember reading somewhere that after they studied passwords from a MySpace phishing scam, they found 1 user with a really long password that was about 30-something characters, and was a word repeated like 4 times. And a dozen users had "password" as a password.

Re: Validate user input

Posted: Sat Jul 21, 2007 12:51 pm
by Chalks
The Phoenix wrote:
Chalks wrote:limit usernames and passwords to 15 characters (but the database holds more than 40... so that the sha1 works).
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.
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?

As for testing the password for certain characters, sure I can do that client-side (and do, now). However, is there anything in particular I should look for? I mean, all it does is go into a mysql database... Are there certain keywords to keep out, or would mysql_real_escape_string() take care of those?

Re: Validate user input

Posted: Sat Jul 21, 2007 2:50 pm
by The Phoenix
Chalks wrote:
The Phoenix wrote:
Chalks wrote:limit usernames and passwords to 15 characters (but the database holds more than 40... so that the sha1 works).
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.
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.
Chalks wrote:As for testing the password for certain characters, sure I can do that client-side (and do, now). However, is there anything in particular I should look for? I mean, all it does is go into a mysql database... Are there certain keywords to keep out, or would mysql_real_escape_string() take care of those?
Escaping will take care of that particular concern. If you are testing, you are looking to ensure that it is not just alphabetic and dictionary word based. Having at least one numeral or (better) punctuation mark will increase the difficulty for crackers substantially. Also check that its over seven characters, and you are doing very well.

Of course, password07! isn't the best, but you get the idea.

Password checking via javascript is difficult to do well. Many have tried, including Google, and its not easy to do well.

In many cases, you are better off just letting the user choose their password, and doing your best to ensure it is secure in transit and storage.