1

I have a page called index.php. This contains a form which the user submits. Upon submission, it verifies the input from verify-input.php and returns some key information back to index.php. From there, index.php post requests scanner.php ~100 times. This is all done without refreshing index.php.

My question is, how do I stop other websites or other people from post requesting verify-input.php and scanner.php? I only want people to be able to call these files on my website (essentially, I don't want others using my verify-input.php and scanner.php API's for their own gain.

I've added the code below for these files, but I don't think it matters too much. I'm fairly good in PHP but I am terrible at javascript.


index.php

<script type="text/javascript" src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
<div class="display-error" style="display: none"></div>
<form>
  <label for="fname">Fruit (only correct input is: banana)</label><br>
  <input type="text" id="fruit-name" name="fruit" value="banana"><br>
  <button type="submit" id="submit" value="Submit">Submit</button>
</form>

<div id="results">
</div>

<script type="text/javascript">
$(document).ready(function() {


    $('#submit').click(function(e) {
        e.preventDefault();

        $("#submit").attr("disabled", true);
        $("#submit").html("Verifying Username");
        var fruitName = $("#fruit-name").val();

        $.ajax({
            type: "POST",
            url: "verify-input.php",
            dataType: "json",
            data: {
                fruitName: fruitName
            },
            success: function(data) {
                if (data.code == 200) {
                    $("#submit").html("Running Scan");
                    (async function() {
                        var fruitID = data.fruitId;
                        var min = 1;
                        while (min < 60) {
                            await scan(fruitID, min, min + 30);
                            min = min + 30;
                        }
                    $("#submit").html("Submit");
                    $("#submit").attr("disabled", false);
                    })();
                } else {
                    $("#submit").html("Submit");
                    $("#submit").attr("disabled", false);
                    $(".display-error").html("<ul>" + data.msg + "</ul>");
                    $(".display-error").css("display", "block");
                }
            }
        });


    });
});

function scan(vFruitId, min, max) {

    return $.ajax({
        type: "POST",
        url: "scanner.php",
        dataType: "json",
        data: {
            vFruitId: vFruitId,
            min: min,
            max: max
        },
        success: function(data) {
            data.forEach((item, idx) => {
                $("#results").append(`
                <div class="fruit-item" data-item="${idx}">
                    <div class="f-calories">calories: ${item.sweetness}</div>
                    <div class="f-sweetness">sweeteness: ${item.calories}</div>
                    <div class="f-bitterness">bitterness: ${item.bitterness}</div>
                </div><br>
              `);
            })
        }
    });

}

</script>

verify-input.php

<?php

if (isset($_POST['fruitName'])) {
    echo(is_valid($_POST['fruitName']));
}

function is_valid($fruit) {
    // Verify post data is valid and correct
    $names = ['Banana cake', 'Banana pancake', 'Banana bread'];
    $colors = ['Yellow', 'Blue', 'Green', 'Purple', 'Black'];
    sleep(2);
    if ($fruit == "banana") {
        $result['code'] = 200;
        $result['fruitId'] = rand(1, 9999999);
        $result['msg'] = "YAY SUCCESS";
        $json = json_encode($result);
        return $json;
    }

    $result['code'] = 400;
    $result['msg'] = "ERROR! The correct fruit is banana";
    $json = json_encode($result);
    return $json;
}

scanner.php

<?php
ini_set('max_execution_time', '300');


define('MAX_SCAN', 30);

if (isset($_POST['vFruitId']) &&
    isset($_POST['min']) &&
    isset($_POST['max'])) {

    $result = roomscanner($_POST['vFruitId'], $_POST['min'], $_POST['max']);
    $json = json_encode($result);
    file_put_contents("result.txt", $json);
    echo($json);
}

function roomscanner($fruitId, $min, $max) {

    $result = [];

    $i = $min;
    while ($i < $max) {
        if ($i % 3 == 0) {
            $curr['sweetness'] = rand(20, 29);
            $curr['calories'] = rand(30, 39);
            $curr['bitterness'] = rand(30, 39);

            $result[] = $curr;
        }
        sleep(rand(0, 1));
        $i++;
    }

    return $result;

}
Jackie
  • 372
  • 5
  • 16
  • 1
    Research CSRF tokens – Phil Apr 21 '20 at 22:52
  • @Phil I searched CSRF tokens and it literally says that you shouldn't use just PHP sessions because a hacker can manipulate that? Then the answer in that post you've linked is just using sessions? – Jackie Apr 21 '20 at 22:56
  • Can you please provide a link to that article or wherever you saw it? – Phil Apr 21 '20 at 22:57
  • @Phil https://portswigger.net/web-security/csrf Also another question in regards to the stackoverflow link you gave. In the `Verifying the CSRF Token` section it has this line `if (hash_equals($_SESSION['token'], $_POST['token']))`. This means the `$_POST['token']` is a hidden field in the HTML form? – Jackie Apr 21 '20 at 22:59
  • Correct, but you could also add it as a request header. It just has to accompany any requests _somehow_. I looked through that entire article and it didn't say anything about not using sessions. – Phil Apr 21 '20 at 23:03
  • @Phil if I have `token` as a hidden field in the form which is fully visible if you look at the RAW html code. Can't the person simply `file_get_contents` or `curl` on my website to generate that `token` from my website. Take that token and just submit a post request using that token from their own website? Then they can get information from my `scanner.php` and `verify-input.php`, Technically the session would be the same? The hacker just needs to not close the session – Jackie Apr 21 '20 at 23:07
  • Do you have authenticated user sessions? If not, I can only think of using `Referer` header validation which isn't reliable. Sounds like the duplicate links above aren't quite doing it for you so I'll re-open your question. – Phil Apr 21 '20 at 23:10
  • @Phil but what I said above is right? Because I see so many PHP posts about the honeypot method, but it just seems so unsafe and easy to "hack"? I do not have authenticated user sessions because I don't have usernames/password logins on my site. However, even if I did have authenticated sessions, I can still do the same thing I mentioned above. I can authenticate myself by post requesting the login page. Get that login cookie > generate that `token` > and submit to `scanner.php` with my login cookie and `token` attached. – Jackie Apr 21 '20 at 23:16
  • @Phil And the referer header can be spoofed easily? I do have cloudflare though, not sure if that helps – Jackie Apr 21 '20 at 23:16

0 Answers0