Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

php How do you ensure $_POST data is coming from your form and not a outside influence?

Is there a way to ensure the $_POST data my code received came from my form and not an outside influence. Basically I don't want someone to be able to spoof a $_POST to a universally available page such as account creation. The account creation page is accessible by any user, but I want to ensure only the data submitted by my account_creation form is what gets processed.

The only thing I could think of was initiating a $_SESSION, and then supplying the session_id to the form using a hidden input. Upon $_POST the value of the hidden input would then be matched against the current session_id.

If there is a better method to achieve this result? If there is I look forward to hearing it.

like image 217
Brook Julias Avatar asked May 10 '12 03:05

Brook Julias


3 Answers

You cannot ensure that data came from a form. A POST request is just a POST request, it can be generated in any number of ways. An HTML form is just one of those ways that's very user friendly. Your server needs to validate whether the data received via the POST request is valid or not and whether to act on it or not.

Having said that, there are things that can help you to restrict and validate the data that is being submitted. First of all, require that a user is logged in using (session) cookies. That eliminates random requests by anonymous users. Secondly, you can embed a token as a hidden field into the form which you also save into the user's session. The POST request needs to contain that token in order to be valid. The token is simply a pseudo-random string.
You can enhance this by preparing a hash of the form fields that you expect the user to submit. If the form value should be read-only, you can include the value into the hash as well. E.g.:

$rand = md5(mt_rand());
$hash = sha1('lastname:firstname:email:' . $rand);

$_SESSION['rand'] = $rand;
$_SESSION['hash'] = $hash;

// on form submit:

$keys = array_keys($_POST);
$checkHash = sha1(join(':', $keys) . ':' . $_SESSION['rand']);
if ($checkHash != $_SESSION['hash']) {
    die('Form submission failed token validation');
}

That's just a quick example, you'll probably want to sort the keys alphabetically to make sure you'll get the same hash etc. It demonstrates the concept of the user needing to have a unique token for each request though which prevents tempering with forms and submitting more or less data than wanted.

This still does not mean that a user actually used your form to submit the data though.

like image 184
deceze Avatar answered Oct 16 '22 16:10

deceze


$ref = $_SERVER['HTTP_REFERER'];
if($ref !== 'some site path/index.php')
{
    die("Access Denied!");
}

This should prevent most people from posting data to your database from an outside influence.

like image 21
steve Avatar answered Oct 16 '22 17:10

steve


Slightly better is to add additional validation such as user_agent, user_ip and some other $_SERVER vars - those are the two I use.

So, create the unique ID (or Session ID) as you describe, but add a little extra validation that the agent and ip also match. Not fool proof, but adds another little layer of security.

Edit: I should add that you don't send the user agent back; keep that server side and silently validate against the returned session id.

Also, if a submission fails validation, never reveal that back to the user as to why - that way a cheat doesn't know how your tracking them. You can also add "5 invalids and you're out" tracking, but you need to sort of login for that.

like image 45
Robbie Avatar answered Oct 16 '22 17:10

Robbie