How to securely make AJAX calls?

Asked by jsherk on 2011-01-17

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:
2011-01-17
Last query:
2011-01-17
Last reply:
2011-01-17
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.

jsherk (jeff-forerunnertv) said : #2

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

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.

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.

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.

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;

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?

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.

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.

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?

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.

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.

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();

jsherk (jeff-forerunnertv) said : #14

Thanks Greg, that solved my question.

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';

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.

jsherk (jeff-forerunnertv) said : #17

Ok, so not required for SELECT only queries then!

Thanks

jsherk (jeff-forerunnertv) said : #18

Let me re-word that...

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