Goodbye Blue Sky


Finally switching to WordPress. Thanks for all the years Drupal!
This is the static archive of all the pages available at http://gablog.eu/online/
Successor is http://gablog.eu/void/

Howto respond in JSON to jQuery AJAX request in CakePHP?

Today I had to submit a form via AJAX to a CakePHP controller. That was not big deal thanks to jQuery.

In particular it was a registration form. The response therefore had not just to indicate success or failure, but in case of the latter also supply error message(s) why it failed (e.g. 'e-mail address and username invalid' etc.). JSON is a natural choice to supply structured information, XML would be an overkill. So how to
a) respond in AJAX & JSON from CakePHP
b) process a response data as JSON in jQuery?

First create controllers/ajax_controller.php:

<?php
class AjaxController extends AppController {
 
    var $name = "Ajax";
    var $components = array('RequestHandler');
    var $layout = 'ajax';  // uses an empty layout
    var $autoRender=false; // renders nothing by default
 
    // Default action    
    function index() {
        $this->redirect("../");
    }
 
    // Sample action that does not return anything
    function procedureCall() {
        // do business logic
    }
 
    // Sample action that does return some text
    function functionCall() {
        $this->respond('Hello World!');
    }
 
    // Sample action that does return JSON
    function JsonCall() {
        $this->respond(array('first'=>'Hello', second=>'World'), true);
    }
 
    // The magic is here. When not called, no view is rendered. 
    // When called it renders message.ctp,
    // content set to $message, or json_encode($message), respectively
    function respond($message=null, $json=false) {
        if ($message!=null) {
            if ($json==true) {
                $this->RequestHandler->setContent('json', 'application/json');
                $message=json_encode($message);
            }
            $this->set('message', $message);
        }
        $this->render('message');
    }
 
    // You will need this to disable debug output appended to the view by CakePHP.
    // Otherwise it will mess up your returned messages.
    function  __construct() {
        parent::__construct();
        Configure::write('debug', 0); // disable debug output in AJAX responses!
    }
}

It is very important to set the content-type to application/json. It might work anyway, but it introduces a serious security flaw to your site.

views/ajax/message.ctp is very simple:

<?php echo $message ?>

And the respective routes:

Router::connect('/ajax/:action/*', array('controller' => 'ajax'));

That's all you need for CakePHP. How to use it on the client side?

$.post($.url('/ajax/ProcedureCall'), $("#formID").serialize(), function(data) {
    alert('Success'); // data empty
});
 
$.post($.url('/ajax/FunctionCall'), $("#formID").serialize(), function(data) {
    alert(data); // Hello World!
});
 
$.post($.url('/ajax/JsonCall'), $("#formID").serialize(), function(data) {
    alert(data.first+data.second); // HelloWorld
}, "json");

If you do not want to post a form to your controller, replace $("#formID").serialize() with any array() of your choice. The content of the supplied array is available in the CakePHP controller as $this->params['form'][$name];

Prevent XSS and request forgery and other common attack patterns

Are you part of the web security problem? An indepth review of the current most common attack vectors is a must-read for every web developer.

It looks like two-third of the attacks are based on three vectors:

1. SQL injection (25%)

$id="1;DROP TABLE users"; mysql_query("SELECT * FROM bars WHERE id=".$id); It is deeply shocking how many "developers" still don't get the message not to execute SQL commands forged from user input. Or at least, why are they still employed? This attack would be the most simple to prevent. You just always have to *escape* strings which are parameters of the sql query coming in as request parameters. If in doubt, what do I mean by that, simply escape *all* parameters of a query. Or better use queries parameterized as "SELECT ... WHERE id=? AND type=?"-s, your language must have a way to pass the values safely afterwards.
But stop, why in the world are these guys still writing any SQL queries in the first place?! Because script kiddies don't know what a persistence framework is. Stop handcrafting CRUD DAOs.

2. Cross-site scripting a.k.a. XSS (17%)

Rule of thumb: always check. If you use any output mechanism or view, check whether it escapes or not. If not, it is *your job* to do so! (Error messages printing also the invalid value are the simplest to overlook.)

* <c:out value="${id}" /> escapes by default.

* ${id} never escape by default. This is one of the most pithiest design decision in JSTL/EL. It is insecure by default. But of course you have the option to turn on security. Thank you very much. I understand the need for backward compatibility, but this is the kind of design problems which can be solved. Why not add an option to change the default behavior, and add fn:unEscapeXml() ?

<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
${fn:escapeXml(id)}

Plain EL expressions to produce output is pure evil.

* The output tags of your framework of choice is the most important to test. Never assume you already know it. In Spring 2.0 escaping in the form:input and form:errors tags were optional and off by default. In 2.5, it was switched to on by default in the documentation. But form:errors tag continued to print out unescaped output. In 3.0 everything seems to be fine by default in both.

Just to improve your chances always add this to your root context:

<context-param>
    <param-name>defaultHtmlEscape</param-name>
    <param-value>true</param-value>
</context-param>

3. Authentication and authorization (14%)

I guess mostly this happens by plain simply ignoring security logic. Most likely to happen when refactoring and ignoring to adopt security logic to the new business logic or domain structure. Those three should be independent by design. AOP or a security framework is a good candidate for separating the security concerns.
If you are not in control of the server side issues, use discovery tools like PhpSecInfo.

++1 Cross site request forgery a.k.a. CSRF and XSRF

Only 2% of the identified attacks fall into this category. But I also saw a lot of plain simply wrong attempts to fix this issue. This also shows how non-trivial it is for the average programmer to safeguard against this kind of attacks. It feels like many sites are vulnerable but not exploited yet.
To check the ingenuity of requests, first one must ensure, that GET requests are never changing state of the domain. (Trivial but not for everyone.)
Second, to always check POST requests' referer header values: they must match yours. This is sufficient for protection against XSRF, but has limitations.
Mostly suggested are tokens, a hidden field in every POST with a random variable identifying genuine requests (e.g. hash of the SESSIONID). The problem is, that every browser has a way to hack around it. You have to generate a new random token for each request to be used to fully safeguard yourself.
Alternatively you can change URLs dynamically (the token becomes part of the URL): for example you can use Spring's @PathVariable annotation bound to a @RequestParam("/action/{nextToken}").

Syndicate content