How to validate user input
Is a basic question. You should validate EVERYTHING on your server side. The back-end is the right place to make validations. Of course javascript validations are useful too to drive standard users into the right values, but for hackers (or any advanced user) is very easy to trick.
It's suppossed you have a database on back-end and you know what kind of food is able to be assigned to each user. You should check if the received value is present on the valid recordset. If is ok you can go on with your workflow. If not, you can show an error and stop the proccess.
Another important problem you'll face is not only the logical bypassing. Beware of special chars and filter everything dangerours like single quotes, double quotes, dashes, semicolons, etc... or you'll face too a sql injection or a XSS (cross site scripting) attack. That is another story... but I mention it because is very important too.
Oscar already posted a great answer, but in response to some of your questions:
My first thought was to have some javascript validation, have an ajax call talk to the server to make sure the values requested are valid. This sounds like a great idea, except javascript runs on the client, not the server, so that is also susceptible to attack.
That's overcomplicating things. Like you said, this is susceptible to attack and furthermore, is completely nullified when Javascript is disabled in the browser.
If I let the user submit the form and then handle the submit on the server and do the checking there, the user has already submitted the form so I would need to do some kind of redirect back to their form?
Yep.
Traditionally, if you want to use JS validation, you do it to suggest corrections at the frontend. "Hey, there's no @ in your email address. Please enter a valid email address." This saves you the round trip you describe above. Javascript is not for enforcing security, it's for enforcing a better user experience.
Then, once they enter a valid email address and submitted their content, there's no longer any way for them to bypass your mechanisms. The ball is in your court. On the server you check for the nasty things Oscar mentions, sanitize all the strings and if you detect something amiss, you do return the user back to the input page (and if you want to be nice, you repopulate the form fields using the sanitized values).
So at this point, even if JS were disabled, the user still gets an HTML message explaining they need to enter a valid email address. Yes, this does mean crafting two different sets of error messages-- one for JS, one in HTML (which is why I personally never bother with the JS validation).
Just be careful about redisplaying any of the content they provided you. If they embedded malicious code in the strings, displaying them on the resulting page without sanitizing them first can end badly.
Performing input validation means to check your input to be sure you can process it. The tricky part is that by validating it, you're already doing some minor processing, and that can create a hidden vulnerability.
The first step is usually to validate the length of the input. Most input will temporarily land in a finite buffer. Ensure that the amount of input you copy into the buffer doesn't exceed the length of the buffer - if there's too much input and not enough buffer, this can create a classic "buffer overflow" problem; exploiting these is a staple of hackers.
The next step is to ensure the data is in the format you expect. If you're expecting a number, ensure the bytes contain only digits and permitted number symbols, such as plus, minus, separator, decimal point, currency symbol, etc. Note that these are locale specific: in the US, a million dollars could be entered as 1,000,000.00
, while in Germany a million Euros could be entered as 1.000.000,00
. If you're expecting alphanumeric characters and numbers, use a "white-list" to accept only the characters you expect. It's safer to rely on a whitelist of good characters than a blacklist of bad characters; your blacklist may keep you safe with your configuration as of today, but let's say someone in the future replaces your database with a different database. It's possible one of the unexpected characters permits a SQL injection. Same is true with scripting and HTML.
Note that if you reverse these checks, and test for special characters before checking the input length, your validation code might be vulnerable to a buffer overflow. It's important to do them in the order that keeps you safest.
So the next step is to appropriately encode the input. For example, if you're going to accept <
and >
and put the results on a web page, you'll probably want to make sure you're HTML encoding the symbols so you don't inadvertently create a hole where an attacker can plant a <script>attack!</script>
on the output page.
It's also advised to attempt to protect against SQL injections here (protect someone entering something bad like ' OR 1=1;DROP TABLE STUDENTS--
, but that's a double edged sword, because it doesn't fully guarantee protection. You might try to prevent this by putting in a validation check against accepting the apostrophe character. The next line of defense must be in the code that interfaces with SQL, and that code needs to be responsible for executing the queries safely (using Parameterized SQL queries, ORMs, or other defensive strategy.) You could pen-test your input against the above SQL injection attack, and not find a flaw because you only know about the one kind of injection attack. But let's assume the attacker figures out a new avenue of attack and tries using HTML encoding to get around your check, and it turns out you forgot to test and/or sanitize against that type of input. You could still be vulnerable unless you're careful with the SQL coding. This is a small example of how a defense in depth strategy can help keep you safe.