How can I detect if my php script is being called from another domain and the other domain is making illegal use of my script? Is there a way to prevent this too?
<
There isn't any absolutely foolproof method to prevent this, since any header information can be spoofed. Session-based tokens are another possible solution, but in that case your javascript is publicly accessible, so anyone who wanted to spend a little time could determine how your token system works and figure out a way around it.
A combination of methods will give you the most wide-ranging protection. You can look for the header, use and .htaccess file, and use tokens. This sort of all-of-the-above approach makes it that much harder to abuse a web server - most abuse comes from people trying to find an easy hole to exploit. The important thing to remember is that you can't become complacent because you've deployed "the best" protection, or because you've got so many layers of protection that it seems impossible to crack. If someone really wanted it bad enough and had the time, they'll find a way. These types of preventative measures are really only deterrents to keep away the lazy, curious, and idly malicious. Targeted attacks are a whole separate class of security, and usually are more centered on server-level security issues.
Sample htaccess. This would not be something you'd put in your root, but rather within a subfolder where you have scripts that should never be called from the address bar:
RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?_YOUR_DOMAIN_NAME_HERE.com [NC]
RewriteRule \.(php)$ - [NC,F,L]
Check out this article for info about using a token system: https://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29_Prevention_Cheat_Sheet
A bit like user3491125 proposed, you could set a $_SESSION in the page where the call is made and check it on the page Ajax called if there is for instance $_SESSION['user'] set.
for user3491125's answer, you could try encrypting the session token. I have one encryption function that can add a unique key based on a users port 80 IP. it's Not foolproof, but it does make it more difficult for hackers.
function encryptString($string, $action, $baseIP = 'false', $extraKey = ''){
global $flag;
$encryptedIP = '';
if($baseIP){
$encryptedIP = encryptString(strip_tags(htmlentities($_SERVER['REMOTE_ADDR'])), 'encrypt', false);
}
$output = false;
$encrypt_method = "AES-256-CBC";
$secret_key = $flag['encrypt-key'].$encryptedIP.'-'.$extraKey;
$secret_iv = $flag['encrypt-secret'].$encryptedIP.'-'.$extraKey;
$key = hash('sha256', $secret_key);
$iv = substr(hash('sha256', $secret_iv), 0, 16);
$output;
if($action == 'encrypt'){
$output = openssl_encrypt($string, $encrypt_method, $key, 0, $iv);
$output = base64_encode($output);
$output = str_replace('=', '[equal]', $output);
}else if($action == 'decrypt'){
$setString = str_replace('[equal]', '=', $string);
$output = openssl_decrypt(base64_decode($setString), $encrypt_method, $key, 0, $iv);
}
return $output;
}
This isn't a problem that can be solved. If you create a website you make it, by definition, openly available.
If you want your data to be private, you need to require some sort of login.
It is impossible to create a system that is open to users but not to scripts without login/annoying captchas.
I know this is an old post but currently THERE IS a "foolproof" method to avoid this and its as simple as hell... First in the page where the ajax call will be made:
<?php
$token = sha1(rand(1000,9999));
$_SESSION['token'] = $token;
?>
Then in the ajax script
var formData = new FormData();
formData.append("token","<?php echo $token;?>");
$.ajax({
url: 'yourfile.php',
type: 'POST',
xhr: function() {
var myXhr = $.ajaxSettings.xhr();
return myXhr;
},
success:function(data) {
alert(data);
},
data: formData,
cache: false,
contentType: false,
processData: false
});
And finally in the php page that will be called:
<?php
$token = $_POST['token'];
if($token === $_SESSION['token'] && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest')
{
//Perform your stuff here...
}
?>
You can manually deny every request whose Origin
header does not match your domain name. However, not all browsers send the Origin
header. In these cases, you can fallback to the Referer
[sic] header, parse it and find out the domain name, and compare it as above.
Some JavaScript frameworks also set an X-Requested-With
header for AJAX requests.
This should reject a significant percentage of users (I'd estimate >95%). Note that due to the Same-Origin Policy, the only thing the guy sending AJAX requests to your domain gets is timing information anyway.