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();
}
?>
Related
I am trying to prevent users from connecting to certain pages with a script. Thus, is there any method I can use to detect if a connection to a specific web page is a client browser versus an automated script?
I know certain headers can be spoofed, but is there another mechanism I can use; say like if unable to set a sesseion_start or setCookie. Do those return true/false values if able or unable be to be set?
Something like:
$sessionID = session_id() ;
$isSet = setCookie('cookieName',$sessionID, [ .... ]) ;
if ($isSet == false) {
... do something to kill the session
... or do something to redirect
}
Is this even possible? And even if it is, I know this probably isn't reliable, but what would be a better or more reliable method?
And to clarify, detect if its a script and if so, kill it before even serving the rest of the html page.
If you are trying to prevent pages from being called entirely, you can reliably do this with a combination of using an .htaccess file and a php "check" file .. This will check to see if the requested file came from your scripts, or an outside source. Make a directory, and put your "hidden" script files in it along with the following 2 files:
.htaccess
php_value auto_prepend_file check.php
check.php
<?php
if( !#$_SERVER["HTTP_X_REQUESTED_WITH"] ){
header('/page_404.php'); // Or whatever you want it to do.
exit;
}
All the .htaccess directive does is make check.php happen before every script call -- So technically you COULD just include check.php at the top of every file .. But I find this a more complete, elegent solution.
You can check with php_sapi_name() if you are running on CLI.
This example will only allow scripts from CLI.
if (PHP_SAPI !== php_sapi_name()) {
die('CLI only');
}
You can reverse the condition to make it only running for web server.
if (PHP_SAPI === php_sapi_name()) {
die('Web Server only');
}
You can do it with $_SERVER['HTTP_REFERER'] but it can be fake/dummy made.
<?php
if (isset($_SERVER['HTTP_REFERER']) && strtolower(parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST)) === 'example.com') {
//your code
} else {
die('Bots are not allowed!');
}
You can use UserAgent
(You can see how to get it here : How to get user agent in PHP)
This will let you know user web browser which -I assume- will be different for 'scripts'
Supposed the page is example.com/blog/data.php. I am using file_get_contents to get the content in another script page. Now, i want to:
Forbid google search to crawl and index the data.php page.
Forbid the visitor to access it
Is there a way to achieve this?
You can redirect to another page if the request url is example.com/blog/data.php, but a far easier and more logical solution would be to move the file out of your web-root.
Edit: If you really want to keep the file inside the web-root, you can use something like this at the top of the script that you don't want to access directly:
if ($_SERVER['REQUEST_URI'] === $_SERVER['SCRIPT_NAME'])
{
header('Location: /'); // redirect to home page
}
However, this will probably not work in combination with file_get_contents (you need to remove these lines from the result), you could include the file instead.
Don't put data.php under the web root. Keep it in a parallel directory.
You can pass token via GET. Overall your way is slightly wrong. Why don't you incorporate the data.php logic in the script that is calling it.
Simply apply access restriction for authorized users only. You are able to do it in the most simple way by accessing your page using url parama as password:
example.com/blog/data.php?secret=someblah
and in the first of your file data.php do the following:
<?php
if (!isset($_GET['secret']) || $_GET['secret'] != 'someblah')) exit();
?>
However,It is recommended, don't use this from public computer becuase it is not secure but it is the primitive authentication principle.
I'm using a jquery script that uploads files with ajax and PHP. It sends a request to upload_a_file.php which then uploads files.
Is there a way that I can make sure upload_a_file.php is not loaded directly in a browser?
I tried putting upload_a_file.php above my public_html folder. But can't seem to get javascript to load upload_a_file.php.
Here is the url format I use in the javascript to request upload_a_file.php:
../upload_a_file.php
Is it even possible to access files above public_html with javascript?
JS cannot access anything on a server that you yourself as a user cannot. If a file is outside of the site's document root, it is NOT accessible by a user, or by JS. Imagine the fun place the web would be if JS could magically bypass access restrictions on a server and grab any more. "Aww, I was going to grab this bank's accounts list, but it's not in the document root. Good thing I've got Javascript, it can do everything!"
It'd be like every episode of 24, where "patching into the subnet" can magically bypass any firewall and get data from machines which aren't even online or (better yet) not even powered up. Amazing things, those subnets.
You can check the HTTP header X_REQUESTED_WITH is present and has a value of XMLHttpRequest. This is not non-standard header but most JavaScript frameworks, including jQuery, Prototype, and mootools follow this convention.
In PHP you can access it $_SERVER['HTTP_X_REQUESTED_WITH'];
for example:
if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest')
{
// do something
}
The javascript is running in the browser. It makes its requests through the browser. So, No, there's no way to access a page through ajax but not directly from the browser.
No, not directly. You can call other script (PHP or whatever) that will either "call" your script with include or e.g. with fopen or curl.
Nothing can access files above public_html, because the web server will not serve them. Doing so would have obvious security vulnerabilities, like being able to view any file on your filesystem.
If you want to restrict the file to only being able to be loaded via your javascript, I would think you'd want to look at the $_SERVER['HTTP_REFERER'] variable in php. This should be set to the page the javascript is located on when it is being accessed properly. If it is anything else or empty, the user is accessing it in some other manner.
Using this method shouldn't be relied on for security however, because the referer can be spoofed with the right tools.
Since direct browser access to a page is a GET request by PHP, here is a very basic access control method to keep someone from inadvertently going directly to upload_a_file.php:
In your jquery script, use an ajax request with type "POST":
$.ajax({
url: "../upload_a_file.php",
dataType: "json",
type: "POST"
});
and use this in your upload_a_file.php:
if ($_SERVER['REQUEST_METHOD'] == "POST") {
// upload a file
} else {
header("Location: http://example.com/myPublicUploadPage.php");
die();
}
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"]);
one of my php page returns data like this:
<?php
//...
echo "json string";
?>
but someone else use file_get_contents() to get my data and use in other website.
can anybody tell me what can i do to prevent such thing happen.
i consider if i can get the request's domain name to echo something else.but i dont know
the function to get request's domain name.and if the request is sent by a server,that
will be unhelpful. My English is poor, to express doubts, please bear with.
you can also use sessions. if somewhere in your application, before the user gets the json data, you start a session, then in this page where you are outputting json data, you can check for the session variable. this way only users that have passed the session generator page, can view your output.
suppose you have page A.php that generates the session. use this code before outputting anything in this page.
session_start();
$_SESSION['approvedForJson'] = true;
then in your page where you are outputting json data, before outputting anything, call session_start() again. the beginning of your PHP code is a good place to call it.
then before outputting the json data, check if the session variable for approved users exists, or not.
if ( isset($_SESSION['approvedForJson']) && $_SESSION['approvedForJson'] ) {
echo "json data";
} else {
// bad request
}
You can use $_SERVER['REMOTE_ADDR'] to get the address of the client address. You can also check $_SERVER['HTTP_REFERER'] and block external requests that way, but it's less reliable. There's probably a few other techniques involving $_SERVER that you can try.
Your fighting an uphill battle here. I am assuming your serverside process that responds in json is being consumed via javascript in your users browsers... so there is no easy way to encrypt it. You might try some of the techniques used to prevent xspf (see http://en.wikipedia.org/wiki/Cross-site_request_forgery ). If you developed the client to pass along some session token that is uniq per client you could reduce some of the problem. But, chances are whoever is stealing your data is gonna figure out whatever mechanism you put in place ... assuming this is some sort of ajax type thing. If its a server-server thing then as sli mentions, setting up some restrictions based on the remote ip would help, plus setting up some sort of API authentication tokens would help even more (see oauth for some pointers)
You could also using .htaccess with apache block every external request to the page if it get's called internally or block every request that is not from your domain:
Google search thingie
EDIT
You could also use some php file which includes the file which can not be read. So for example you have file.php:
<?php
$allowedFiles[] = 'somefile.php';
$allowedFiles[] = 'someotherFile.php';
$allowedFiles[] = 'jsonReturnFile.php';
if(in_array($_GET['file'], $allowedFiles)){
include( "include/".$_GET['file'] );
}
?>
Then you can allow file_ get _contents() on that file and write a rewriteRule in your .htacces to disallow any request to the include/ folder.
RewriteRule include* - [F,NC]
That will return a 403 forbidden error for a request to that directory or any file in the directory.
Then you can do you JSON request to something like: file.php?file=jsonReturnFile.php&someothherParamReadByJsonFile=1
And when someone tries to get the file contents for the JSON file they will get the forbidden error, and getting the file contents for the include.php won't return anything usefull.