2

I'm currently writing a web application which uses forms and PHP $_POST data (so far so standard! :)). However, (and this may be a noob query) I've just realised that, theoretically, if someone put together an HTML file on their computer with a fake form, put in the action as one of the scripts that are used on my site and populate this form with their own random data, couldn't they then submit this data into the form and cause problems?

I sanitise data etc so I'm not (too) worried about XSS or injection style attacks, I just don't want someone to be able to, for instance, add nonsense things to a shopping cart etc etc.

Now, I realise that for some of the scripts I can write in protection such as only allowing things into a shopping cart that can be found in the database, but there may be certain situations where it wouldn't be possible to predict all cases.

So, my question is - is there a reliable way of making sure that my php scripts can only be called by Forms hosted on my site? Perhaps some Http Referrer check in the scripts themselves, but I've heard this can be unreliable, or maybe some htaccess voodoo? It seems like too large a security hole (especially for things like customer reviews or any customer input) to just leave open. Any ideas would be very much appreciated. :) Thanks again!

flukeflume
  • 707
  • 1
  • 6
  • 14

6 Answers6

3

There exists a simple rule: Never trust user input.

All user input, no matter what the case, must be verified by the server. Forged POST requests are the standard way to perform SQL injection attacks or other similar attacks. You can't trust the referrer header, because that can be forged too. Any data in the request can be forged. There is no way to make sure the data has been submitted from a secure source, like your own form, because any and all possible checks require data submitted by the user, which can be forged.

The one and only way to defend yourself is to sanitize all user input. Only accept values that are acceptable. If a value, like an ID refers to a database entity, make sure it exists. Never insert unvalidated user input into queries, etc. The list just goes on.

While it takes experience and recognize all the different cases, here are the most common cases that you should try to watch out for:

  1. Never insert raw user input into queries. Either escape them using functions such as mysql_real_escape_string() or, better yet, use prepared queries through API like PDO. Using raw user input in queries can lead to SQL injections.
  2. Never output user inputted data directly to the browser. Always pass it through functions like htmlentities(). Even if the data comes from the database, you shouldn't trust it, as the original source for all data is generally from the user. Outputting data carelessly to the user can lead to XSS attacks.
  3. If any user submitted data must belong to a limited set of values, make sure it does. For example, make sure that any ID submitted by the user exists in the database. If the user must select value from a drop down list, make sure the selected value is one of the possible choices.
  4. Any and all input validation, such as allowed letters in usernames, must be done on the server side. Any form validation on the client, such as javascript checks, are merely for the convenience of the user. They do not provide any data security to you.
Riimu
  • 1,427
  • 8
  • 12
2

Take a look @ nettuts tutorial in the topic.

Just updating my answer with a previously accepted answer also in the topic.

Community
  • 1
  • 1
fabrik
  • 14,094
  • 8
  • 55
  • 71
  • While form keys are an effective way to protect against XSS posts, they do nothing against specifically forged requests, which, I believe, is the main issue here. (Not to belittle the importance of XSS protection, especially in a shopping application) – Riimu Mar 24 '11 at 08:45
  • @Rinuwise: sorry, it's my fault because i didn't read again the whole tutorial (i recalled it touch the referer thing too) – fabrik Mar 24 '11 at 08:51
2

The answer to your question is short and unambiguous:

is there a reliable way of making sure that my php scripts can only be called by Forms hosted on my site?

Of course not.

In fact, NO scripts being called by forms hosted on your site. All scripts being called by forms hosted in client's browser.
Knowing that will help to understand the matter.

it wouldn't be possible to predict all cases.

Contrary, it would.
All good sites doing that.
There is nothing hard it that though.

There are limited number of parameters each form contains. And you just have to check every parameter - that's all.

Your Common Sense
  • 156,878
  • 40
  • 214
  • 345
-1

As you have said ensuring that products exist in the database is a good start. If you take address information with a zip or post code make sure it's valid for the city that is provided. Make countries and cities a drop down and check that the city is valid for the country provided.

If you take email addresses make sure that they are valid email address and maybe send a confirmation email with a link before the transaction is authorised. Same for phone numbers (confirmation code in a text), although validating a phone number may be hard.

Never store credit card or payment details if it can be avoided at all (I'm inclined to believe that there are very few situations where it is needed to store details).

Basically the rule is make sure that all inputs are what you are expecting them to be. You're not going to catch everything (names and addresses will have to accept virtually any character) but that should get most of them.

I don't think that there is any way of completely ensuring that it is your form that they are coming from. HTTP Referrer and perhaps hidden fields in your form may help but they are not reliable. All you can do is validate everything as strictly as possible.

Belinda
  • 1,230
  • 2
  • 14
  • 25
-3

I dont see the problem as long as you trust your way of sanitizing data...and you say you sanitize it.

You do know about http://php.net/manual/en/function.strip-tags.php , http://www.php.net/manual/en/function.htmlentities.php and http://www.php.net/manual/en/filter.examples.validation.php right?

Quamis
  • 10,924
  • 12
  • 50
  • 66
  • 1
    Thanks all!@FractalizeR - much obliged, I'll check this out. @fabrik, Thanks, I'll read this this morning. @Rinuwise - thanks, I do make sure I clean all data, but it's mainly forged requests I'm worried about. @Quamis thank you, I do sanitize data at the moment it's purely regarding fake, but not dangerous, user input. @ Col. Shrapnel - Ah, of course about browser hosted forms (duh me), thanks for pointing that out. As for predicting all cases, I can verify data that is stored in the db, but I'm unsure about people adding nonsense user details with valid products for pure mischief. – flukeflume Mar 24 '11 at 09:56
  • @user674512 You just won't process anything not belongs to your database structure, would you? NB, it's bad idea to answer everyone at once. – Your Common Sense Mar 24 '11 at 13:17
  • @Col. Shrapnel - oops, sorry, I'm new to stack overflow, I'll split them up in future. But no, I didn't mean that, just tht it'll be easier to process that data; I'm going to put other things in place for data not occuring in the db strcuture – flukeflume Mar 24 '11 at 16:57