15

There are some scripts that I use only via ajax and I do not want the user to run these scripts directly from the browser. I use jQuery for making all ajax calls and I keep all of my ajax files in a folder named ajax.

So, I was hoping to create an htaccess file which checks for ajax request (HTTP_X_REQUESTED_WITH) and deny all other requests in that folder. (I know that http header can be faked but I can not think of a better solution). I tried this:

ReWriteCond %{HTTP_X_REQUESTED_WITH} ^$
ReWriteCond %{SERVER_URL} ^/ajax/.php$
ReWriteRule ^.*$ - [F]

But, it is not working. What I am doing wrong? Is there any other way to achieve similar results. (I do not want to check for the header in every script).

Vikash
  • 989
  • 2
  • 9
  • 28
  • 2
    "(I do not want to check for the header in every script)" - could you explain why not? I'd say making a general include file or a seperate class for all your ajax requests would make perfect sense. – Jasper De Bruijn Dec 14 '10 at 16:09
  • The scripts are already written and they are large in number. – Vikash Dec 15 '10 at 07:15
  • 1
    I seen a similar post on here before, I would question (like I did before) WHY you are trying to limit people accessing the AJAX files directly? What is the concern? Sensitive data that non-logged in users will get? I'm honestly baffled by the reasoning for securing ajax files unless called by javascript. – Jakub Dec 15 '10 at 20:05

5 Answers5

25

The Bad: Apache :-(

X-Requested-With in not a standard HTTP Header.

You can't read it in apache at all (neither by ReWriteCond %{HTTP_X_REQUESTED_WITH} nor by %{HTTP:X-Requested-With}), so its impossible to check it in .htaccess or same place. :-(

The Ugly: Script :-(

Its just accessible in the script (eg. php), but you said you don't want to include a php file in all of your scripts because of number of files.

The Good: auto_prepend_file :-)

  • But ... there's a simple trick to solve it :-)

auto_prepend_file specifies the name of a file that is automatically parsed before the main file. You can use it to include a "checker" script automatically.

So create a .htaccess in ajax folder

php_value auto_prepend_file check.php

and create check.php as you want:

<?
if( !@$_SERVER["HTTP_X_REQUESTED_WITH"] ){
        header('HTTP/1.1 403 Forbidden');
        exit;
}
?>

You can customize it as you want.

Ehsan
  • 1,937
  • 1
  • 17
  • 30
18

I'm assuming you have all your AJAX scripts in a directory ajax, because you refer to ^/ajax/.php$ in your non-working example.

In this folder /ajax/ place a .htaccess file with this content:

SetEnvIfNoCase X-Requested-With XMLHttpRequest ajax
Order Deny,Allow
Deny from all
Allow from env=ajax

What this does is deny any request without the XMLHttpRequest header.

dyve
  • 5,893
  • 2
  • 30
  • 44
1

There are only a few predefined HTTP_* variables mapping to HTTP headers that you can use in a RewriteCond. For any other HTTP headers, you need to use a %{HTTP:header} variable.

Just change

ReWriteCond %{HTTP_X_REQUESTED_WITH} ^$

To:

ReWriteCond %{HTTP:X-Requested-With} ^$
Jonathan Amend
  • 12,715
  • 3
  • 22
  • 29
0

Just check for if($_SERVER['HTTP_X_REQUESTED_WITH']=='XMLHttpRequest'){ at the beginning of the document, if it's not set, then don't return anything.

edit Here's why: http://github.com/jquery/jquery/blob/master/src/ajax.js#L370

edit 2 My bad, just read through your post again. You can alternatively make a folder inaccessible to the web and then just have a standard ajax.php file that has include('./private/scripts.php') as your server will still be able to access it, but no one will be able to view from their browser.

Robert
  • 21,110
  • 9
  • 55
  • 65
  • I like the idea. However, I have to pass a parameter to the ajax call to distinguish which 'private' script to call. Since the ajax calls are spread in number of files, this is not practical in my particular case. – Vikash Aug 12 '10 at 11:22
0

An alternative to using .htaccess is to use the $_SERVER['HTTP_REFERER'] variable to test that the script is being accessed from your page, rather than from another site, etc.

Brian H
  • 833
  • 1
  • 5
  • 12