making action for ajax only, and blocking direct url visit - php

I have an action that's meant to be accessed only through ajax. How can I make it give blank output when someone visits the url directly as http://site.com/controller/action? Is there a way that Zend can tell if it's an ajax call or direct url visit?
Edit: I found out about Zend's $this->getRequest()->isXmlHttpRequest(), but I wonder if this can be trusted enough?

There's no way of reliably telling an AJAX request and any other kind of request apart, so no you can't block non-AJAX access.

If you're using jQuery, you can check it like:
if(empty($_SERVER['HTTP_X_REQUESTED_WITH']) || strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) != 'xmlhttprequest') {
return die('No direct access allowed.');
}

Related

Is there a way to protect direct access to pages - but allow ajax requests?

I have some pages that return a JSON request that are used in jQuery via AJAX. What I need to do is somehow block direct access to the file. So only allow JSON (AJAX) requests but not direct access to the file.
So if I have the following jQuery code:
$.getJSON("ajax/returnDate.php", {
id: $(this).val()
},function (data) {
//more code
}
)
An unauthorized user can see this code. This will allow them to go to the following url and obtain the data they need.
domain.com/ajax/returnDate.php
So I need to write code to not allow direct access to returnDate.php but allow json request to be made.
How can I handle this?
Thanks
Get Operations are never secure and are subject to "get replay attacks",CSRF, and XSS.
HTTP headers can be easily spoofed if your concern is unauthorized access.
I suggest the following:
changing to a "POST" operation from a "GET" operation
When you serve the page, place an antiforgery token into the URL for the AJAX POST operation
Check the antiforgery token on every ajax request POST operation
Generate a new Antiforgery token on every page.
Ask yourself : would Sabu code it that way?
Ajax requests should have an extra header HTTP_X_REQUESTED_WITH and the value would be xmlhttprequest, so you can add a check
$_SERVER['HTTP_X_REQUESTED_WITH'] == 'xmlhttprequest'
Please note that this can still be imitated by an curl library, It's just an extra line of security
When ever you use jQuery to make ajax calls it sets the a header HTTP_X-Requested-With. You can check for that and redirect the user if its false using the header(Location: anything.php) function
$isXhr = isset($_SERVER["HTTP_X_REQUESTED_WITH"])
AND strotlower($_SERVER["HTTP_X_REQUESTED_WITH"]) == "xmlhttprequest";
please note to ensure proper security becaause this header can be injected manually in the header and access the page by some mallciuos user.

ajax- if I send an ajax request on a url, can i check in the php page if it is a request or the page has been opened?

For security purposes, I want to stop the users from being able to view or send anything to the php pages I am going to use for ajax purposes.
So is there any way by which I can check whether a page has been called because of an ajax request or the page has been opened?
Does self=top consider ajax request or not?
/* AJAX check */
if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
/* special for ajax here */
}
else
{
//its a page request
}
this will only work when using JS frameworks that send this header :-by Bergi
No, you will need an other security model.
Of course you could set custom http headers (like X-Requested-With) or such when you are doing Ajax requests (many libraries do that automatically), and tell them apart from normal "view" requests. But everything can be faked, so there can be no security through determining that.
Even if you do stop people not using a ajax request, what's stopping people from changing the ajax request in the first place?
This would add little to none added security in my opinion especially with the ease this can be done with firebug for example.

How do I denied user access script directly in URL

I have a jQuery script using .live() to load it's page content.
$('#content').load("content.php?" + id);
Question: How can I deny a user from accessing the file content.php directly via a URL?
I tried to put this code on top of content.php but Access Denied appear in my #content div
if (!empty($_SERVER['SCRIPT_FILENAME']) && 'content.php' == basename($_SERVER['SCRIPT_FILENAME']))
die('Access Denied');
What is the correct way to make sure users can't access my content.php file using a URL?
You could use some sort of hashing. For example if content.php has the parameter id; you add an additional parameter hash which contains the MD5 hash of "'some random string' + id*15". In content.php you check if the hash & id match; if not access denied.
The computation has to be done in PHP (not ajax) because the user must not know the hashing algprithmus.
With this method the user can look up the source code and access the page directly but you can't disallow that completly because the browser need to access the page to show it. But the user can't access pages he hasn't accessed through ajax before. You could use some headers (HTTP_X_REQUESTED_WITH) to prevent most internet users to access the page directly but experienced users will change the header and access it anyway.
If you want to protect the usage you can use a one time key algorithm. Have the server generate a key that the page will contain in a variable or attribute somewhere. Then on the load command you pass the key to content.php like this:
key = $("{some selector to get the key}")
$('#content').load("content.php?id=" + id + "key=" + key);
Once the page makes the call to server using the key the server will expire the key making it unusable. This way only active page requests will have access to your content.php file.
This method is still not bullet proof but would make it more difficult to access the content.php by the user.
Since you're calling a resource via ajax a possible solution is sending a particular header into the request like HTTP_X_REQUESTED_WITH and then detect the header server side like so:
/* AJAX check */
if(empty($_SERVER['HTTP_X_REQUESTED_WITH']) ||
strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) !== 'xmlhttprequest') {
die($content);
}
I suggest reading this: Detecting Ajax Events on the Server.
Is there other content on the mainpage that you could reference from the content.php file to verify that you are loading it as part of the mainpage and not a stand alone page? You could also pass something via a session from the mainpage into the content.php page and then remove the item at the end of loading of the content.php.
If the URL is accessible with AJAX request then it can be accessed directly and there is not much you can do about it. You can try to detect if a request is the AJAX request with:
function isAjaxRequest() {
return array_key_exists('HTTP_X_REQUESTED_WITH', $_SERVER) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest';
}
and check for it in the beginning of the script:
if (!isAjaxRequest())
die('Access Denied');
but you shouldn't rely on this check too much because it's rather easy to bypass.

encrypting jquery .load() function

I'm calling a php page using .load()
.load('page.php?user='+user+'&page='+page)
if you go to the actual page.php and type page.php?user=1&page=2
you get the same result, how could I stop this from happening?
encrypting data maybe?
Could someone point me in the right direction, cheers.
#lonesomeday,
this answer works for me, yours was correct though:
if(isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') { it's an ajax request validate id and continue! } else { this is not an ajax request, get out of here! }
submitted by "ifaour"
Ultimately, anything that is accessible using AJAX is accessible without using AJAX. That's the nature of the web.
You can try to ensure AJAX by checking for the XMLHTTPRequest header, but be aware that it can trivially be spoofed by a user who wants to:
if ($_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHTTPRequest') {
// is probably an AJAX request
}
If you are making your request with jQuery, this should be safe, because jQuery adds this header itself. Be aware, though, that some browsers do not add it automatically if you are creating the XMLHTTPRequest object yourself.

How to detect if file is being accessed or requested?

A I have a PHP file that if the user access it directly he should be redirected to another location, but if my script call it through ajax, it should do nothing special.
For example, if a user access
/site/page.php
he should be redirected to
/index.php?view=page
But if he is on the index.php?view=page the file should load without redirects.
How can I do that?
EDIT: If you want to determine if a script was requested through Javascript or not, you'll have to signal it somehow.
Several toolkits define the header X-Requested-With. In that case, you can check for a Javascript call with:
if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) &&
strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
//requested with Javascript
}
You can check the size of the result given by debug_backtrace.
Alternatively (better), you can check $_SERVER['SCRIPT_FILENAME']:
if (realpath(__FILE__) == realpath($_SERVER['SCRIPT_FILENAME'])) {
//this one was requested; not in include
}
By "it should do nothing special" do you mean it shouldn't redirect?
So the Q is really if user accesses a URL for a PHP file directly, it should redirect, if thru AJAX, process as normal?
(to really clarify, you mean thru a URL and not thru a include statement, right?)
Answer: You can't. Artefacto mentions the HTTP_X_REQUESTED_WITH header - sure, but that can be faked.
Is it really so bad is the user accesses the URL directly?
If the answer is "OMG Yes!" then maybe there is something wrong with how the system is designed.
Redesign it until the answer is "Actually, I suppose it wouldn't really hurt."
If you really don't want someone accessing /site/page.php, you should consider moving /site/page.php outside of your web root. Then make your index.php load it as needed:
<?php
$includes = "/path/to/includes"; // specified in a config file somewhere
if ($_GET["view"] == "page") {
require_once(path_join($includes, "page.php"));
DoStuffInPageDotPHP();
}
else {
DoSomethingElse();
}
?>

Categories