8

For example, when I want to update a part of my page with AJAX I would normally make the appropriate call to getPost.php which would return the markup to be inserted into my page. Is there any way to prevent a user from accessing this page directly (eg: example.com/getPost.php with the appropriate GET or POST arguments) and getting only part of the page since this should be used with AJAX as part of a whole, not alone?

I don't think permissions can be set on the file since it's the client requesting the page but is there a way to do this by passing an extra argument that can serve as a check digit of sorts.

alexcoco
  • 6,657
  • 6
  • 27
  • 39
  • No particular reason. Not something that should be super secure but enough so that a user won't stumble across a piece of a web page instead of the whole. Or at least so someone doesn't send requests to a php page that sends information to a database. – alexcoco Aug 26 '10 at 23:10

6 Answers6

8

You could take a look at the request headers and enforce that a header must be set for AJAX requests (often people use X-Requested-With with a value like XMLHttpRequest). Be aware that this header won't be set unless you set it yourself when you make your AJAX request (or use a Javascript library that does it automatically). However, there is no way to guarantee that someone wouldn't add in that header on their own if they wanted to.

The X-Requested-With header value can be found in $_SERVER['HTTP_X_REQUESTED_WITH'].

Daniel Vandersluis
  • 91,582
  • 23
  • 169
  • 153
3

You can check the $_SERVER['HTTP_X_REQUESTED_WITH'] header. It should be equal to the value 'XMLHttpRequest' if it is an Ajax request.

Edit - like Daniel Vandersluis said, there is no way to fully enforce this. You can spoof user agent, referrer - anything that comes in with the request.

efritz
  • 5,125
  • 4
  • 24
  • 33
2

what ever you request to server, it store the information in $_SERVER variable

to check what information this variable stores try this

print_r($_SERVER);

//you will see the difference in http and ajax request 

use this variable to check as bellow

if(isset($_SERVER['HTTP_X_REQUESTED_WITH']) &&
    strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
   //ajajx request
}
else {
   //not an ajajx request
}
Peter Ajtai
  • 56,972
  • 13
  • 121
  • 140
1

Since there's no way to be 100% sure who is asking the question, you can restrict the question itself.

The implementation of this will depend on the page of course.

For example let's say you're running curl command on a url, you can restrict the incoming variable to only a certain domain.

<?php
if (substr($_GET["url"], 0, 19) !== "http://example.com/")
{
    die();
}
// otherwise carry on
?>
Peter Ajtai
  • 56,972
  • 13
  • 121
  • 140
1

shouldn't this work?

if(preg_match("/getPost\.php/", $_SERVER['PHP_SELF'])){
     // Access to file directly, quit..
     die();
}
cragiz
  • 453
  • 2
  • 5
  • 8
  • From the manual: `$_SERVER['PHP_SELF'] in a script at the address http://example.com/test.php/foo.bar would be /test.php/foo.bar.`... which doesn't really help, since it just gives the AJAX page. The script being called is the AJAX page, not the original requesting page. – Peter Ajtai Aug 26 '10 at 23:40
0

I think you can (at least partially) solve your problem with cryptography.

Say you have a page main.php which includes JS to call another page called ajax.php. When the page main.php is accessed, use a $browserKey and a $salt to create a $_SESSION["tempHash"]. (You also need to store the salt.) Then, give the key to the JavaScript making the request to your page ajax.php, and check that the key and salt give the same hash as before. On main.php, do something like this:

<?php
session_start();
// authorize user here
$salt = time();
$browserKey = mt_rand();
$hash = sha1("$browserKey$salt");
$_SESSION["tempSalt"] = $salt;
$_SESSION["tempHash"] = $hash;
// ... code ...
?>
<!doctypehtml>
<html>
<!-- html -->
<script>
// ... ajax call ...
var params = "param1=val1&param2=val2&...&browserKey=<?= $browserKey ?>";
request.send(params);
</script>
</html>
<?php session_write_close(); ?>

Then, on ajax.php, simply do

<?php
$validated = false;
if(sha1($_POST["browserKey"] . $_SESSION["tempSalt"]) === $_SESSION["tempHash"]) {
    $validated = true;
}
// and unset the salt and hash
$_SESSION["tempSalt"] = $_SESSION["tempHash"] = null;
if(!$validated) {
    // taken from another SO answer: 
    // http://stackoverflow.com/a/437294/2407870
    header('HTTP/1.0 404 Not Found');
    echo "<h1>404 Not Found</h1>";
    echo "The page that you have requested could not be found.";
    exit();
}
// else, continue normal processing here
?>

I'm not an expert in this domain, so take my advice with a grain of salt. (Heh, cryptography joke.)

One potential vulnerability with this approach is that the person may load page main.php and then wait five hours and call page ajax.php. It will still only allow them to access it once though. And you can do other things to prevent this. E.g, check the salt (which was obtained with time()) to verify that not too much time has passed. Or even send periodic heartbeats to the server, which generate a new hash, salt and key, returning the new key to the browser.

Chris Middleton
  • 5,654
  • 5
  • 31
  • 68