为什么阻止直接URL访问也会从Web服务器上的文件中删除Ajax调用?

I want to block Url (external) access to PHP file in the folder "/mi-php/". So I created a .htaccess file within /mi-php folder with the following codes:

<Files *.php>
    Order deny,allow
    Deny from all
    Allow from 127.0.0.1
</Files>

Sure, the php files are blocked from directly url access. However, when I try to call this php (/mi-php/jobdata.php) file using Ajax in one file on the webserver as follows:

$(document).ready( function () { $.getJSON("/mi-php/jobdata.php", function(data){ etc etc

It is also blocked. I thought calling by another file under the same website root directory is considered "localhost" access. I guess I am wrong. But how to make the php file accessible to only my own files under the root directory?

I don't see that there are any bullet proof ways of solving this. The only way I can think of is to see if the call is an Ajax call.

if (empty($_SERVER['HTTP_X_REQUESTED_WITH']) || strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) != 'xmlhttprequest') {
    die();
}

Based on David Walsh blog post here.

You need to add the above snippet in the top of each file you're trying to block. There are two things to consider.

  1. Anyone can modify the header of their call and add the above header.
  2. Some servers/ajax-clients don't send this header (Apache and jQuery does).

There might be more you can check in your script but this would be a start.

The method I suggested in the comment would be like:

RewriteEngine On

RewriteCond %{HTTP_REFERER} !^$ 
RewriteCond %{HTTP_REFERER} !^http://(www\.)?arvixe\.com/ [NC] 
RewriteRule ^mi-php(/|$) - [F,NC]

The above will go in the document root of your httpd server.

Note that a client can send fake headers to bypass these. Also, as Magnus suggests, these values might get removed from the request entirely pertaining to users' firewall/ISP settings. Do not rely 100% on this.


Another method you can try is, right before the AJAX call, store the following piece of value inside a session variable:

<?php $_SESSION['ajax'] = 'allowed';

Now, in the files that will be requested with AJAX call, put the following check at the very beginning of each of them:

<?php
    session_start();
    if( !isset($_SESSION['ajax']) and $_SESSION['ajax'] !== 'allowed' )
        die();
    else
        unset( $_SESSION['ajax'] );
?>