3

i'm making a form and i would like to make the submitting PHP page accessible only if the form was submitted, preventing custom requests to my PHP page.

This is my form.html:

<html>
    <head>
        <title>Name/Surname form</title>
    </head>
    <body>
        <form id="form1" method="POST" action="processData.php">
            Name: <input type="text" id="name" name="name"><br>
            Surname: <input type="text" id="surname" name="surname"><br>
            <input type="submit" value="Submit form">
        </form>
    </body>
</html>

and then my processData.php:

<?php
    if(!isset($_POST['name'],$_POST['surname'])) die;

    include ("config.php");

    //connect
    $mysqli = new mysqli($dbhost, $dbuser, $dbpassword, $dbname); //variables from config.php

    //check connection
    if (mysqli_connect_errno()) {
        printf("Connect failed: %s\n", mysqli_connect_error());
        exit();
    }


    if ($stmt = $mysqli->prepare("INSERT INTO name_surname_table (name, surname) values (?, ?)")) {

        //bind
        $stmt->bind_param('ss', $name, $surname);

        //set
        $name=$_POST['name'];
        $surname=$_POST['surname'];

        //execute
        $stmt->execute();

        //close
        $stmt->close();
        }
    else {
        //error
        printf("Prepared Statement Error: %s\n", $mysqli->error);
    }
?>

The problem is that if i do a custom post request without submitting the form in my previous page, the data is submitted to the db, that means that an automated program could just put whatever it wants in my db... How can i prevent this?

Thanks!

BackSlash
  • 21,927
  • 22
  • 96
  • 136

4 Answers4

4

You have many options to prevent the robots from submitting your forms automatically :

  1. Use a Captcha or some easy calculation field (for example What gives 3 + 2 ?)

  2. With a token

  3. Make some check with $_REQUEST variables

A token can be done like this :

session_start();
//generate a unique string
$token = uniqid(rand(), true);
//Store the token
$_SESSION['token'] = $token;
//Store the token_time
$_SESSION['token_time'] = time();

Add an hidden input to your form :

<input type="hidden" name="token" id="token" value="<?php echo $token;?>"/>

And than before submitting the form to the database :

session_start();
//If token exists
if(isset($_SESSION['token']) && isset($_SESSION['token_time']) && isset($_POST['token']))
{
    //If it's the same as the posted one
    if($_SESSION['token'] == $_POST['token'])
    {
        //For example 15 mins ago
        $old_time = time() - (15*60);
        //If token hasn't expired
        if($_SESSION['token_time'] >= $old_time)
        {
           //Do your queries here
        }
    }
}
Community
  • 1
  • 1
soyuka
  • 8,839
  • 3
  • 39
  • 54
  • With a token? How can i do it? – BackSlash Mar 16 '13 at 11:28
  • 1
    edited with a token example, it isn't 100% safe but it's better than nothing :) – soyuka Mar 16 '13 at 11:35
  • Thanks! i don't want to use any captcha so i think i'm gonna use a token :) – BackSlash Mar 16 '13 at 11:45
  • 1
    To break this, the session would need to be hijacked, which is quite a bit of bother just to send spam. Most robots would move on to an easier target. – Marc Audet Mar 16 '13 at 11:46
  • 1
    I also tend to check the IP of the server submitting the form so that I least I know that it is coming from my IP address. I tend to include the host IP as an extra field in my message so I get a warning if a robot is trying to use my processing script. – Marc Audet Mar 16 '13 at 11:49
  • Yeah that's why I added `check some $_SERVER requests` :). – soyuka Mar 16 '13 at 11:51
  • 2
    @MarcAudet All that a bot needs to do to "break" this is load the form containing the new token before each submission. There is no need to hijack a session, as the bot will have its own. – IMSoP Mar 16 '13 at 12:00
1

Fundamentally you cannot prevent a malicious client sending "incorrect" data to your server. It is up to you to detect that situation and handle error cases appropriately.

If only certain users should be able to submit data, then obviously you need some form of login system. Then you can trust any data from a logged in user, and reject everything else.

If you just want to know that the client loaded the form on the previous page, you can add a hidden field containing a "nonce" - a random string whose value you store somewhere on the server such as in the PHP session. If the nonce submitted doesn't match the expected value, reject the input. Note that this does not guarantee that the user interacted with the form in their browser, only that they downloaded it (since a program can still extract the nonce and stimulate submitting the form)

IMSoP
  • 89,526
  • 13
  • 117
  • 169
0

You could have a hidden field in the form that contains a secret code that expires...

When you generate the form, you calculate the code by running a hash on the time or even just picking a random number. Then store that in your session and insert it in the form you send.

When you process the form submission, check to make sure the secret code is the same as what is stored in the session.

Rob Cozzens
  • 136
  • 2
0

You should make a token based authentication for your forms.

In the page where you display form, first set a session variable with a random code.

//generate this using whatever random code generation method you prefer.
$_SESSION["token"] = "your-random-code";

In your forum have a hidden field as below.

<input type="hidden" name="token" value="<?php echo $_SESSION['token'] ?>">

In the submit handler php file, do a check like below.

if(isset($_POST['token']) && $_POST['token'] == $_SESSION['token'])
kavin
  • 1,684
  • 1
  • 11
  • 10