How to securely make AJAX calls?

Asked by jsherk

Ok, my question today is how to do a secure ajax/json request.

I have this in a javascript file which works when I click a button on the page:
function myAjaxTest() {
     $.ajax({
      type: "POST",
      url: "plugins/myPlugin/includes/test.php",
      dataType: "json",
      data: { aa: "cat",
                   bb: "dog"
            },
      success: function(_data) {
                    $.each(_data, function(_index, _value) {
                        $('#test').append(_index + ': ' + _value+' ');
                    });

                }
    });
 }

This is my test.php file:
<?php
$aa = $_POST['aa'];
$bb = $_POST['bb'];
$x = array($aa,$bb,'hi from me');
$encoded = json_encode($x);
echo $encoded;

Now this works fine, except I can directly access the test.php file from the internet, and it returns the data to the screen (which we don't want).

Obviously there must be a way to make an ajax call securely without leaving the data available to anybody who knows the web address of the php file.

I am of course using https which is mostly secure, but that does not solve the problem of keeping the data from being easily accessible!

Thanks

Question information

Language:
English Edit question
Status:
Solved
For:
PHPDevShell Edit question
Assignee:
No assignee Edit question
Solved by:
Greg
Solved:
Last query:
Last reply:
Revision history for this message
TitanKing (titan-phpdevshell) said :
#1

PHPDevShell offers an easy wait to make secure calls. Create a controller/model/view just like you would normally (standard plugin) do and create a new menu item for it and select to hide it from all. However, instead of giving it the standard theme, goto themes management and click install to install emptyCloud. Assign your ajax menu item to emptyCloud. Now simply call your new menu item as the url.

Revision history for this message
jsherk (jeff-forerunnertv) said :
#2

Just out curiosity, why does it have to use the empty theme?

Revision history for this message
TitanKing (titan-phpdevshell) said :
#3

It doesn't actually, Its just you want to call the content of just the controller and not with everything surrounding it like the menu items, logos, footer etc. Mostly when calling ajax you call just the results or page of results.

Revision history for this message
jsherk (jeff-forerunnertv) said :
#4

Ok, I see how this works... you need to be login in order to access the page and the data!

Now, I tried this and am using POST method from ajax to submit post. When I manually go to the new menu item, the data is displayed on screen, but AJAX tries, firebug shows an ACCESS DENIED error, even when I set the page having Guest access.

Revision history for this message
TitanKing (titan-phpdevshell) said :
#5

Actually when it is set to allow guest it should allow ajax to access it. Are you sure the url is correct? Try using the full url with url/index.php?m=[menu id] or url/index.php?m=123532423

Try accessing that menu url item directly like you used it in in the ajax.

Revision history for this message
jsherk (jeff-forerunnertv) said :
#6

I dont seem to be getting the access denied error anymore, but it's show null as being returned now.

Should I just be able to echo a json array back to it like this:
<?php
$encoded = json_encode(array('me','myself'));
echo $encoded;

Revision history for this message
jsherk (jeff-forerunnertv) said :
#7

Oh maybe its because I am not using the empty template yet... if ajax does not see a proper json response, will it just say NULL?

Or should it grab everything it sees even if it's not correct?

If I go to the menu item directly, the array is properly echo onto the screen... since I am POSTing the data from ajax, is it expecting some kind of special headers to be returned before the data, or for the data to be POSTed back instead of just echo?

Revision history for this message
TitanKing (titan-phpdevshell) said :
#8

No not with above method. Using above method is purely to left for the ajaxed called controller to do the output. If you want to share resources between each other there are different methods to follow. I will have to let Greg write documentation on this as he wrote the Json system. I will ask him as soon as he comes online.

Revision history for this message
TitanKing (titan-phpdevshell) said :
#9

There are a few very nice methods available in PHPDevShell for ajax, but just hold on so we can get clearance on them. Greg wrote them mostly and he can give us a quick overview. I would like to know more about it too.

Revision history for this message
jsherk (jeff-forerunnertv) said :
#10

I don't need to share in this case, I am just saying that when I go the menu item directly (type the url in my browser), it displays my data on the screen (as a nice json array) because I am using an echo command in the controller to output.

Ajax is sending the request using POST method, so what I am not sure about, is how ajax is expecting the data to be returned... is an echo statement in the controller sufficient with this simple text output (as a json array), or do I also need to include (echo) special headers in the reply before the ajax will accept it back?

Revision history for this message
TitanKing (titan-phpdevshell) said :
#11

Indeed echo in the controller is fine, or whatever is written in the view will be output. Remember you can hide the menu link from displaying in navigation but you cant prevent the item from loading when you have permission to view it and you access the url directly.

Revision history for this message
Best Greg (gregfr) said :
#12

OK basically you have it right, but you're missing a step:

- create a controller like you would do for a regular page :

    class my_controller extends PHPDS_controller ...

- in this controller add a special method:

    public function viaAJAX()
 {
             $aa = $_POST['aa'];
             $bb = $_POST['bb'];
             $x = array($aa,$bb,'hi from me');
             return $x; // note you don't have to encode as json
 }

- in the GUI, give your controller the needed permissions + visibility

Note that you can use the same controller in the usual way for non-ajax pages: the execute() method will be used (as opposed to viaAJAX() for ajax calls).

If you don't want to use a controller and to a direct script (or want to understand how it works), you need to use PU_exitToAJAX($result).

To see it in action, take a look at /plugins/PHPDevShell/controlls/menu-admin/menu-item-admin.php which uses the dual structure.

Revision history for this message
Greg (gregfr) said :
#13

NOTE: there is currently a problem with update requests. if you're ajax code sends such a request, it's very likely it won't be taken into account, because the database engine won't have the chance to close itself. To work around that, manually send a commit:

$this->db->endTransaction();

Revision history for this message
jsherk (jeff-forerunnertv) said :
#14

Thanks Greg, that solved my question.

Revision history for this message
jsherk (jeff-forerunnertv) said :
#15

Ok, thanks Greg, I got it working now!

I do not however understand your last comment about using $this->db->endTransaction();
Do you mean it should be used in the controller just before returning the data, like this:

<?php
class ajaxSearch extends PHPDS_controller
{
    public function viaAjax()
 {
         if (isset($_POST['search'])) {
            $search = $_POST['search'];
        } else {
            $search = '';
        }
        require_once('plugins/myPlugin/models/some-page.query.php');
        $RESULTS = $this->db->invokeQuery('myPlugin_searchForSomething', $search);

        $this->db->endTransaction(); //*<**<***<****< USE IT HERE???

        return $RESULTS;
 }
}
return 'ajaxSearch';

Revision history for this message
Greg (gregfr) said :
#16

Yes. In the future, clean will take place after returning from viaAJAX(), but meanwhile it's the safe route if you use insert/update/delete queries.

Revision history for this message
jsherk (jeff-forerunnertv) said :
#17

Ok, so not required for SELECT only queries then!

Thanks

Revision history for this message
jsherk (jeff-forerunnertv) said :
#18

Let me re-word that...

So its not required for queries that only contain a SELECT.