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¶m2=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.