I read that checking the X-Requested-With header of the ajax request is a good way to make sure the request isn't coming from outside. On the server side, how do I check this header? and what's the right way to react of this header is missing or wrong (redirect, throw exception, else)?
You can check it like this...
$isAjax = isset($_SERVER['HTTP_X_REQUESTED_WITH']) AND
strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest';
If you are only expecting access via XHR, then just exit if this header is not present.
Note: This header is trivial to spoof. Don't rely on this for anything but it looks like it came from na XHR.
The only sure fire way to ensure that the request came from your site and not someone else's is to issue a unique token to the user and store it in their session. In your code where you make the AJAX request you then need to pass this token back and if it matches the one in their session then you can be sure the request came from your site.
More info:
http://en.wikipedia.org/wiki/Cross-site_request_forgery
Related
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.
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.
I'm using some PHP pages do some AJAX stuff but I don't want them to be directly accessible. Facebook does a similar thing so for example: domain.com/ajax/my_ajax_form.php
If I was to load that page using AJAX it would work fine, but if a user were to try and loading the file directly by typing in that url it would do through an error so e.g.
if( IS FILE LOADED DIRECT? )
{
header ( HTTP/1.0 404 );
}
This isn't possible. You cannot rely on $_SERVER['HTTP_X_REQUESTED_WITH'], and even if you could, it doesn't matter. Anyone can send the same request to your server that your browser does, via POST or GET.
What you should do is validate the request, and return the proper result if it is valid. If it is invalid, do not return a 404. (Browsers can cache errors like 404. If your client-side code had a trouble, subsequent requests may fail!) If the request is invalid, return an error of some sort.
Again, it is impossible to secure stuff like this. You should be validating the session and request data. That's all.
You can look for the HTTP_X_REQUESTED_WITH header.
$is_ajax = array_key_exists('HTTP_X_REQUESTED_WITH', $_SERVER)
&& $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest';
if (! $is_ajax) {
die('go away.');
}
Note, though, that it's not standard, but needs to be set explicitly on the requesting side. AFAIK, at least jQuery and Mootools set it though, probably most others as well, but don't take my word for it.
Simplest way is to only access that page via POST, and not via GET. Though keep in mind - if a browser can do it - then a hacker can too.
You have to use session variables, or more generally, cookies.
With cookies: (set in JavaScript)
JavaScript: Set token in cookie
JavaScript: Make XMLHttpRequest
Server side: Check token from cookie
Server side: Return JSON output or error message
Please note that this is no way secure! This just prevents easy linking.
With session variables: (cookies set in server side)
Server side: Authenticate user, set privileges
JavaScript: Make XMLHttpRequest
Server side: Check privileges
Server side: Return JSON output or error message
This method is as secure as the user authentication is.
All over the Internet, included even here at Stack Overflow, people state that a good way to check if a request is AJAX or not is to do the following:
if (strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest' ) {...}
However, I don't see $_SERVER['HTTP_X_REQUESTED_WITH'] in the official PHP documentation
And when I try to do the following:
echo $_SERVER['HTTP_X_REQUESTED_WITH'];
Nothing is outputted.
Am I doing something wrong? Because I'd really like to be able to use $_SERVER['HTTP_X_REQUESTED_WITH'] if it's available.
The variables in $_SERVER are not really part of PHP, which is why you won't find them in the PHP documentation. They are prepared by the Web server which passes them on to the scripting language.
As far as I know, the X-Requested-With is sent by the Ajax functions of most major Frameworks but not all (Dojo, for example, added it only two years ago: #5801). As such, and taking into considerations #bobince' comments, it's safe to say it's not generally a 100% reliable method to determine whether a request is an AJAX request or not.
The only 100% secure way is to send a pre-defined flag (e.g. a GET variable) along with the request and for the receiving page to check for the presence of that flag.
don't forget that you can easily spoof any header with cURL like so
curl_setopt($ch,CURLOPT_HTTPHEADER,array("X-Requested-With : XMLHttpRequest"));
$_SERVER keys that start with HTTP_ are generated from HTTP request headers. In this case, the X-Requested-With header.
This header is a standardization-in-progress from all of the AJAX libraries out there.
It won't be documented in the php documentation per-se, but rather in the different AJAX libraries that set this header. Common libraries do sent this header: jQuery, Mojo, Prototype, ...
Usually these library will set the header using
xhrobj.setRequestHeader("X-Requested-With", "XMLHttpRequest");
Here's a quick function with example usage:
function isXmlHttpRequest()
{
$header = isset($_SERVER['HTTP_X_REQUESTED_WITH']) ? $_SERVER['HTTP_X_REQUESTED_WITH'] : null;
return ($header === 'XMLHttpRequest');
}
// example - checking our active call
if(!isXmlHttpRequest())
{
echo 'Not an ajax request';
}
else
{
echo 'is an ajax request';
}
echo $_SERVER['HTTP_X_REQUESTED_WITH'];
What'd you expect from such a code? Assume you're running it directly from the browser, not using AJAX request. So, how come this header could be set?
Well the Answer to the Ultimate Question of Life, the Universe, and Everything - an HTTP sniffer! Get yourself one and forget of printing $_SERVER variable.
Firebug has one, or you may want to use Fiddler HTTP proxy or LiveHTTPHeaders Mozilla plugin. I'm bored to make links but it easily googled.
So, with HTTP sniffer you can be sure of any HTTP header ever.
Note that you can't prevent any "direct access" by using XHR, as every HTTP request to your server is already "direct".
You have to set it specifically in your ajax request object (that is if you are not using a framework like jQuery), but core Javascript; like so:
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
Where xhr is your request object.
Then, PHP will now receive and set it in the global variable $_SERVER like so:
$_SERVER['HTTP_X_REQUESTED_WITH']
Otherwise $_SERVER['HTTP_X_REQUESTED_WITH'] will always be null.
Note: In your javascript, Please make sure you set headers after the request is open. I mean after xhr.open() method.
You can also blame some browser bugs - see this question and its solution for Firefox
Firefox does not preserve custom headers during Ajax request redirect: an ASP.NET MVC solution
IE also having caching issue which is more serious then detection of request method.
You anyway needs to add cache busters to avoid caching, so why not use another flag to specify the ajax call - or more better you can use different URL like http://ajax.mysite.com/endpoint/sevice?params
I agree Pekka. There is no reliable native method between front side and back side that can auto-detect if a client is really calling an endpoint using AJAX.
For my own use, I have few main ways to check if a client is requesting one of my endpoint:
I can use HTTP_X_REQUESTED_WITH when I'm not in cross domain context.
instead of checking "X-requested-with", I'm checking $_SERVER['HTTP_ORIGIN'] (that is sent from AJAX request) intending to handle cross domain permissions. Most of time, the main reason why I'm checking if a request is an AJAX request, is especially because of cross domain permissions, using this PHP code: header('Access-Control-Allow-Origin: '.$_SERVER['HTTP_ORIGIN']); // If this "HTTP_ORIGIN" is in my white list
my APIs expect from the client to explicit, in few cases, the datatype (JSON, HTML etc.) into a GET or a POST var. For example, I check if $_REQUEST['ajax'] is not empty or equal to an expected value.
The best solution to make sure if an HTTP request is truly sent via AJAX is using SESSION checking , you send session_id in a get parameter and you check this session if it's allowed or not !
$headers = apache_request_headers();
$is_ajax = (isset($headers['X-Requested-With']) && $headers['X-Requested-With'] == 'XMLHttpRequest');
I need to deal with these two cases differently,is there a good solution?
if ($_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest') { /* ajax request */ }
I can think of 2 ways to accomplish this:
On the AJAX side you could set a custom HTTP header with XMLHttpRequest.setRequestHeader() and then check for the presence of that header on the PHP side with getallheaders() to indicate that the request was made by an AJAX client. If your php script doesn't find the custom header, you can consider it to be a non-AJAX request.
When you create the request in your code, you could simply tack on a querystring variable to indicate the nature of the request. eg. http://example.com/process?ajax=true for an AJAX reqeust or http://example.com/process?ajax=false for a non-AJAX request.