This question addresses the security / user end side of things.
Suppose I have a script that is called via ajax which will add something to a database.
The script checks for the request method. If it is from 'POST' then the script will carry out this function.
I do not want users accessing my pages and either getting an error or a blank page.
What is the 'ideal' way to deal with this?
My current plan is as follows: If it is not a POST method, redirect them to an error page in the same way as a 404 handler and then provide some links for elsewhere.
Returning a 400 Bad Request is a pretty standard way to indicate that the user got there without the proper data that's needed.
if(!isset($_POST)){
header("HTTP/1.0 400 Bad Request");
}
On top of that, you should spend some time investigating doing some cross site request forgery protection (CSRF) if you want to make sure only your UI posts to that page.
Try this, i use it in all my pages called via ajax:
if ($_POST['ajax'] == "ajax") { // You need to set this is your post ajax variables sent to this php file.
// all your code here
} else {
// Not needed for a blank page, or whatever you want for another page ie
header ("location: 404.php");
}
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.
I have a password protected website--imagine something like linkedin-- where if the session expires you are prompted to log in again.
Some pages have ajax calls, however, that load content from the server into divs.
If you come back to the open div after the session expires and try to enter something, the php on the other end does a redirect within the div, and basically loads the whole login page inside the div. This creates a page within a page, an obvious error that tells the user, the site is not working properly.
Instead of the login page appearing inside the open div, I would like the div to close and the whole page redirect to the login. I am having trouble accomplishing this, however.
Right now I am doing the password protection with an include that checks for session and either allows you to continue or bumps you out to the login page.
If ($_SESSION['login'] != '1') {
header("Location: relogin.php"); }
I have this include in the scripts triggered by ajax calls to fill divs so users cannot bypass security. It is a catchall include that also holds some global variables, functions and so forth.
Can I add code that detects if call is coming from ajax or something so as not to do redirect and instead give message to login. Or ideally, close div and redirect whole page?
Because it is a large site, I would like to find one block of code that could go into the global include.
Would appreciate any suggestions.
You will need to do the redirect on the JS side.
Let's go over the PHP side first. You want to give your AJAX handlers a clear, unambiguous, stateful response: "sorry, you're not authorized". Let's borrow from REST a bit right?
Top of each of your AJAX calls:
<?php if (!YouAreLoggedIn()) {
header($_SERVER['SERVER_PROTOCOL']." 403 Forbidden");
exit(); ?>
This will throw the visitor a 403 error, and will kill the script. 403 errors in jQuery count as a XHR error, so you can map it independently of everything else.
Your typical AJAX call then becomes:
$.ajax({
url: "your.url.here.php",
type: "POST",
success: function(d) { YourSuccessCallHere(); },
error: function() { window.location.href='your.redirect.here.php'; }
});
This is the cleanest way to do it.
You could differentiate the two different calls by User-Agent or other header fields.
Use setRequestHeader() as described in links below:
JQuery Ajax Request: Change User-Agent
http://www.w3.org/TR/2007/WD-XMLHttpRequest-20070618/#dfn-setrequestheader
You could add a GET variable to the request URL whenever you're calling it via Ajax:
myurl.php?ajax=Y
Then on myurl.php, check to see if it's an ajax call:
if(!isset($_SESSION['login']) || $_SESSION['login'] != '1') {
if(isset($_GET['ajax'])){
echo json_encode("Please login!");
exit;
}
else{
header("Location: relogin.php");
exit;
}
}
Use the following header to check if the request was an AJAX request:
X-Requested-With: XMLHttpRequest
read the header in php using:
$_SERVER['HTTP_X_REQUESTED_WITH'];
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 have several pages inside an AJAX directory. I don't want these pages accessible directly so you cannot just type in the URL of the page within the AJAX directory and access it. I "solved" this by using a PHP session on the page that calls it as follows:
Main page:
<?php
session_start();
$_SESSION['download']='ok';
?>
and on the ajax page I have this:
<?php
session_start();
if($_SESSION['download']!=='ok'){
$redirect='/index.php'; //URL of the page where you want to redirect.
header("Location: $redirect");
exit;}
?>
The only problem is that if a user goes through the correct process once, the cookie is stored and they can now access the page directly. How do I kill the session once they leave the parent page?
thx
why use session ?
if i understood what you want:
<?php /// Is ajax request var ?
if (isset($_SERVER['HTTP_X_REQUESTED_WITH'])) {
if (strtolower($_SERVER['HTTP_X_REQUESTED_WITH'])=="xmlhttprequest") {
// do your ajax code
} else {
// redirect user to index.php since we do not allow direct script access, unless its ajax called
$redirect='/index.php'; //URL of the page where you want to redirect.
header("Location: $redirect");
exit();
}
} ?>
A really simple solution is to open up each of the files you want to protect from direct URL entry & add the following to the top:
<?php if (isset($_GET['ajax']) != true) die();?>
Now get rid of your redirect script since it's useless now. You don't need to use sessions for this. Every time you request a page, use it's direct URL, just add ?ajax=1 to the end of it.
By adding the ?ajax=1, PHP will set a key of 'ajax' to the $_GET global variable with the value of 1. If ?ajax=1 is omitted from the URL then PHP will not set a key of 'ajax' in $_GET and thus when you check if it's set with isset() it will return false, thus the script will die and not output anything. Essentially the page will only output data if ?ajax=1 is at the end of the URL.
Someone could still "spoof" the URL and add '?ajax=1' themselves, but that is not the default behavior for people or web browsers. If you absolutely need to prevent this then it will be much more complicated, e.g. using templates outside of a publicly available folder. Most other "simple" solutions will have the same "spoofing" potential.
There's really no way to accomplish this with a 100% certainty - the problem is, both AJAX and regular web browser calls to your web site are using the same underlying protocol: HTTP. If the integrity and security of your site depends on keeping HTTP clients from requesting a specific URL then your design is wrong.
so how do you prevent people from directly accessing files inside certain directories while still letting the site use them??
Create a controller file. Send all AJAX requests to this controller.
ajax-control.php
<?php
$is_ajax = true;
include "ajaxincludes/test.php";
// ... use the ajax classes/functions ...
ajaxincludes/test.php
<?php
if (!isset($is_ajax) || !$is_ajax)) {
exit("Hey you're not AJAX!");
}
// ... continue with internal ajax logic ...
If clients try to access the file directly at http://mysite/ajaxincludes/test.php they'll get the error message. Accessing http://mysite/ajax-control.php will include the desired file.
I don't think there is a surefire way to do what you are asking, since HTTP request headers can be faked. However, you can use $_SERVER['HTTP_REFERER'] to see if the request appears to be coming from another page on your site.
If the rest of the security on your site is good, the failure of this method would not grant the user access to anything they were not already able to access.
I've never tried this but maybe you could do something with jQuery's .unload() and then call a PHP page to unset() the session.
Why not (on Ajax page):
session_start();
if($_SESSION['download']!=='ok'){
$redirect='/index.php'; //URL of the page where you want to redirect.
header("Location: $redirect");
exit;
}
// do whatever you want with "access granted" user
// remove the download flag for this session
unset($_SESSION["download"]);
In my test.php file, I sent a request to a Flickr app I have using
header("Location: " . $request);
where $request is the URL that I am trying to reach on Flickr.
For my Flickr app, I have to set a callback URL. When Flickr is done with processing my request, it will call the callback URL.
I would like the callback URL to be my original page, test.php. When I try this, I get stuck in an infinite loop, because test.php is re-sending the request back to Flickr, and Flickr calls my test.php again (repeat ad infinitum until the browser quits).
Is there a way to put some kind of conditional in test.php to check if the request came from Flickr, or at least some way to let the script know that the request has been sent, so don't send it again.
I've already tried it where I changed the callback URL to another page of mine, and that works fine. I'm just seeing if I could re-use the same page.
Its ugly.
The two posted solutions won't work because:
The referer isnt changed on redirect (well it is cleared if its a http meta redirect, but not if its a header redirect. but it doesnt become something else so easy).
Putting exiting after a sent header is generally a good idea if there is something else normaly executed afterwards, but its not related to the problem.
Simply put, if it should be the SAME page, you need to to store in a file or database or something the redirect counts per ip adress/user and break or something but NONE of this is really reliable. You can make it more secure by having a secured token that cannot be reverse engeneered etc but all this doesn't make sense. You could also use cookies. Which is just as unreliable as well.
Regarding your problem, flickr does NOT redirect back to the samep age.
Regarding to their specifications they append ?frob=[frob].
http://www.flickr.com/services/api/auth.spec.html
Check for that:
<?php
if(!isset($_GET["frob"])) {
header("Location: " . $request);
exit();
}
?>
try checking the referer with the $_server['HTTP_REFERER']
[Edited]
I just wanted to say that, you should try adding if condition
// just and example, use some regular expression to check the refere
if($_SERVER['HTTP_REFERER'] != http://flicker.com){
header("Location: " . $request);
}else{
// another code
}
Thanks
As an alternative to checking for the (non-)existence of $_GET["frob"], couldn't you set the callback url in Flickr to be www.mysite.com/test.php?from_flickr=1 and then do
if (!$_GET['from_flickr']) {
header('Location: '.$request);
exit;
}