Prevent direct access to php page that is called by ajax

I welcome any comments on this as I have not found a good answer on the internet to properly solve this.

This solution is based on having a php page that included a js file using

<script src="js/testimonialDisplay.js" defer></script>

The beginning of the php looks like this:


// allow access to header and footer

$randomPass = substr(strtoupper(md5(rand())), 0, 9);

var randomPass="<?=$randomPass?>";

<html lang="eng">
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="font-awesome/css/font-awesome.min.css">
  <link rel="stylesheet" href="/css/header.css">
  <link rel="stylesheet" href="/css/footer.css">
  <link rel="stylesheet" href="/css/main.css">
  <link rel="stylesheet" href="/css/frontPageFirstSection.css">
  <link rel="stylesheet" href="/css/testimonialsDisplay.css">
  <link rel="stylesheet" href="/css/stickyfooter.css">
      <script src="js/testimonialDisplay.js" defer></script>
        <script src="js/frontPageBackgroundImage.js" defer></script>
        <script src="js/keyboardReturnActivatesButton.js" defer></script>
        <script src="js/frontPageSearch.js" defer></script>

On the top of this page we generate a random key and put this in a $_SESSION variable

$randomPass = substr(strtoupper(md5(rand())), 0, 9);

We then put this variable in a javascript variable

var randomPass="<?=$randomPass?>";

In the file js/testimonialDisplay.js looks like this (partly shown with key bits)

  let formData = new FormData();
      formData.append ('task', "testimonialsDisplay");
      formData.append ('randomPass', randomPass);

      var  xmlhttp;
        xmlhttp = new XMLHttpRequest();
      }else if(window.ActiveXObject){
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP")
        xmlhttp.setRequestHeader("X-Requested-With", "XMLHttpRequest");

The key points are:

Adding the randomPass to the form data to get sent in the ajax & adding the header “xmlhttp.setRequestHeader(“X-Requested-With”, “XMLHttpRequest”);”

Now at the “testimonialsDisplayProcessing.php” page we use the following:

&& strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest'
&& $_POST['randomPass']==$_SESSION['randomPass']);
if(!AJAX_REQUEST) {die(); unset($_SESSION['randomPass']);}

In the code above we look to see if the header is there from the ajax, this is the solution that we see on the internet, but this can be spoofed therefore adds little security but will prevent genuine users accidently ‘viewing’ this processing page.

The key here is that we also check the randomPass sent through the ajax request with the $_SESSION[‘randomPass’]. If they don’t match, we die();

In either case we unset the session variable because it’s not needed any more.

So with this technique, on every ajax call, there is a temporary variable that is created each time and this is sent with the ajax call but also saved in a session variable. On the page we wish to protect (the php page that is called by the ajax), we check to see if the sent variable is the same as the session variable.

If this ajax is also only accessed by for example a logged in user, we need to add something like the following as well.

if (isset($_SESSION['id']))
  header("Location: /index.php",TRUE,301); // Permanent

Leave a Reply