Prevent external acces to .php - php

Is there a way to block external acces to a .php file (like in the URL) and allow if the .php file got called by jquery post?
Thanks!
Wouter0100

I assume because you say like in the URL you want to prevent GET requests.
You can put this at the top of your script to prevent people accessing it through the URL. You will then only be able to POST to it, such as jQuery POST.
<?PHP
if($_SERVER['REQUEST_METHOD']!="POST")
header('HTTP/1.0 401 Unauthorized');
exit;
?>
Be aware, other sources can still POST to the form as well. This method only prevents access through other methods such as GET requests. I.e. typing in the URL in the address bar.

As it has been mentioned to you that allowing a .php to be accessed using jquery post is equivalent of providing an external access. The only way (and that is not very reliable) you can allow a php file to be accessed by jquery post is to check for $_SERVER['HTTP_REFERER'] variable in your PHP code to be same as the URL that has sent jquery post.

The easier way to do this would be to send a header with jquery that you later read with PHP. It's in no way a true protection, but it does prevent the users from sending requests without first inspecting the headers it's supposed to send.
For instance, in your jquery call:
$.ajax({
url: url,
beforeSend: function(xhr) {
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
},
success: function(data) {
}
});
And in your PHP:
if ($_SERVER['HTTP_X_REQUESTED_WITH'] != 'XMLHttpRequest') {
header("HTTP/1.0 405 Method Not Allowed");
exit();
}

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.

Allow access to PHP file only through ajax on local server

I have a website that needs to increment values in a database based upon user interaction. When users click a button a php script is called that increments the value. I'd like to protect this script from being accessed by outside scripts. Currently a user could write their own web page with a javascript function that hits the same php file repeatedly to blow up the value in the database.
Here's my jquery code that does the incrementing:
jQuery(function(){
$('.votebtn').click(function(e){
var mynum = $(this).attr('id').substring(0,5);
$.ajax({
url:"countvote.php",
type:"GET",
data: {
thenum:mynum
},
cache: false,
success:function(data) {
alert('Success!');
}
}
});
});
});
How would I go about making it so that only a call from ajax/jquery on the local server can access 'countvote.php'? If that's not the correct way to go about it, I'm open to any suggestion that will prevent my php script from being abused by outside scripts.
The solution needs two steps.
Firstly the ajax file must allow access only in ajax request with this code.
define('IS_AJAX', isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest');
if(!IS_AJAX) {die('Restricted access');}
Secondly the ajax file has access in the name of file that call it with command $_SERVER['HTTP_REFERER'].
So you can restrict access only in the host server.
$pos = strpos($_SERVER['HTTP_REFERER'],getenv('HTTP_HOST'));
if($pos===false)
die('Restricted access');
Maybe the code can work only with the second part
You can check if $_SERVER['HTTP_X_REQUESTED_WITH'] equals xmlhttprequest, but it's not a reliable method to determine whether a request is an AJAX request or not, there is always a way to get around this. But it protects you from random hits like wrongly entered urls, crawlers etc.
Theres not really a 100% method of doing so. AJAX requests are always going to come from a client. Use POST requests instead of GET and that will help deter any issues but not completely stop them and in your php, just drop all get requests.
I am not sure if this will work, but whats about settings an API key on eg. index.php into a $_SESSION variable, afaik this cannot be visible to the user, unless you do it manually, then in the restricted php file, check the $_SESSION['VOTEAPIKEY'] or whatever

Prevent user to see directly PHP url in Javascript

I want to prevent user to see directly PHP URL in Javascript.
Example :
{
$.ajax(
{
type: "POST",
url: "search.php",
data: dataString,
cache: false,
success: function(html)
{
$("#display").html(html).show();
}
});
}return false;
Is it possible or any way to prevent user see the php URL when He/She view the source of my page ? Sometimes user maybe try to open the php url directly.
Thanks for helps.
I (or any client) can still use any number of tools to figure it out (including the built-in debugger in 99% of the browsers built)--It's not worth obfuscating it.
If you're concerned about direct access, check for an AJAX request in your script. (Still hack-able, but it's a start). As also provided in a previous answer:
<?php
$isAjax = isset($_SERVER['HTTP_X_REQUESTED_WITH'])
&& strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest';
if (!$isAjax) die('Unauthorized access');
/* rest of search.php */
As stated in comments,
How can We prevent the User open directly the PHP url ?
You should create a session of very long random string (token) in your php and pass it to the js ajax function, so that it sends the token along with the ajax request. On server side you can check if its the same token generated. You may want to expire the token soon.
I dont know, if its the standard way, but can provide you a start.
Ok to make things clear..
Once its on the client-side(the browser) you can't hide it. Users can still download or view source the client-side return.
Obfuscating is not really needed because you just make things complicated and not protecting anything.
But anything that is server-side code(PHP) will not be shown as it is processed by the server-side and the server just return the results of execution of the server-side code.
well in case of your problem the thing you can do is to check whether the $_POST and $_GET parameters are valid upon reaching your PHP codes thus making every POST and GET request valid and safe. its somewhat like this
<?php
if(isset($_POST['username']) && isset($_POST['password'])){
//everything seems fine
echo 'ok';
}
else{
//someone is doing a direct acess
header('index.php');
}
?>
or check the sessions to protect your pages only for logged-in users
<?php
if(isset($_SESSION['userid'])){
//everything seems fine
echo 'ok';
}
else{
//someone is doing a direct acess
header('index.php');
}
?>

How to tell if a page is being called via Ajax, or on it's own

I have a page that loads other pages via Ajax (think frames, except without the frames).
Obviously these pages can all be called independently, so I want to detect if they are being called via the Ajax, and if not, redirect to the main Ajax page.
The pages are php pages, so I have access to that as well.
index:
goto = "StandalonePrograms.php";
var clear = "<br style='clear:both;'>"
if(goto != ''){
$.ajax({
url: goto,
context: document.body,
success: function(data){
$('#mainwindow').html(data + clear);
$('#mainwindow').find("script").each(function(i){
eval($(this).text());
});
}
});
}
Modern browsers add the following request header when a request is made using the XMLHttpRequest object:
X-Requested-With: XMLHttpRequest
In PHP, check the existence of this header using:
$_SERVER['HTTP_X_REQUESTED_WITH']
You cannot never trust clients and their sent information!
The headers can be spoofed by hackers (for example with cURL) and even HTTP_X_REQUESTED_WITH is not reliable. there is no 100% trusted way to know that.
The Only way is using captcha...

Form that makes browser redirect when accessed by either a regular form submit or an Ajax request - is this possible?

I have a web page with a form. When the user submits the form, I want the server to make the browser redirect to a different page from the form action. Right now, I am doing this by using PHP's header function to send a 302 status code. It works fine.
I am trying to make the page on the server redirect the browser in the same way, regardless of whether it was submitted normally (without Javascript) or via Ajax. I tried to do this by setting the window location to whatever URL is in the Location header. I am using jQuery, and doing a call like this:
$.ajax({
url: this.action,
type: "POST",
data: getFormData(this),
complete: function(request) {
window.location.assign(request.getResponseHeader("Location"));
}
});
However, that didn't work. After thinking about it, I realized that this is not very surprising. In an Ajax request, the browser is supposed to transparently handle redirect responses such as 302 codes before changing the readyState. When the complete function runs, it is looking for the Location header in the final destination and not finding it.
As an experiment, I then tried sending a 200 status code with a Location header. I tried the Ajax request and it worked fine. However, when I did the non-Ajax submit, it didn't work. The browser went to the form action page and stayed there, like it was ignoring the Location header.
Is there any way to make the same page redirect in both cases, without the server having to know or care whether the request is an Ajax request?
In case this matters, I tried the form in various browsers (IE8, IE7, IE6, Firefox 3.5, Chrome) with similar results each time. Also, I am doing a post request to avoid bumping into IE's 2083-character URL length limit.
HTTP 302 response are consumed silently by XmlHttpRequest implementations (e.g. jQuery's ajax function). It's a feature.
The way I've solved this in the past is to detect for XmlHttpRequests and issue a "Content-Location" header (rather than a "Location" header). The most cross-library way of doing this is to check for the "X-Requested-With" http header in your server-side code (jQuery, Prototype, Mootools among others set this):
if (#$_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') {
header('Content-Location: ' . $redirect_url);
} else {
header('Location: ' . $redirect_url);
}
You still need to special-case your client-side code:
$.ajax({
// ...
complete: function(xhr) {
var redirect_url = xhr.getResponseHeader("Content-Location");
if (redirect_url) {
window.location = redirect_url;
}
}
})
If the user is getting redirected regardless, why the Ajax? The whole point of Ajax like this is to make changes to the page without a page refresh, so the technique you're using seems a little like building a printer that outputs into a shredder hopper.
I'd like to know more about your use-case for this. From what I understand your trying to get your application to load a page based on the 'Location' header of an Ajax call within it? I'd ask why?
An HTTP header doesn't seem to be the right place to get that information from. Isn't your application essentially making a query that says "Where shall I redirect to?". There's no reason the Ajax response actually has to respond with a 302 and a 'Location' header. Why not just have it respond with JSON or XML which contains the new URL?
Edit: Just re-read your penultimate paragraph. I'm not sure there's a good way of achieving what you want. The concept sounds broken to me. :)
Pass additional parameter to your ajax request for easy identify type of request. When ajax - do not redirect - just send target url, then redirect client side in ajax callback via location.href
like this:
$.post('/controller/action', {formdata}, function (redirect_to) {
location.href = redirect_to;
});
Will "complete" work:
$.ajax({
type: frm.attr('method'),
url: frm.attr('action'),
data: frm.serialize(),
complete: complete(xhr, status) {
window.location.assign(xhr.getResponseHeader("Location"));
}
});
Did you try using the error function instead of complete?
$.ajax({
url: this.action,
type: "POST",
data: getFormData(this),
error: function(request) {
if(request.status == 302)
window.location.assign(request.getResponseHeader("Location"));
}
});
jQuery sends any 3xx response to the error function. Maybe the 'Location' header will still be available at this stage.
Why not have your "ajax action" simply fill in the needed form fields and submit the form instead? This way you'll get exactly the same behavior as when submitting by hand.
Here is another option although you will need to do some cross browser tests:
complete: function(request) {
if(request.status == 200) {
var doc = document.open(request.getResponseHeader('Content-Type'));
doc.write(request.responseText);
doc.close();
}
}
Major drawbacks: URL in address bar doesn't change; could mess with back button/history
Although I think #crescentfresh's idea is the way to go

Categories