Tag: cakephp security

Save now, sanitize later…

Good discussion came up on IRC today, regarding sanitizing of the data.

I’d like to clear up a little confusion and hopefully set the record straight on the sanitizing of data.

First, we need to keep in mind that there are two types of “evil” data, which most web developers are worried about.
One can hurt your database and the other one that can hurt your HTML pages.

Therefore, it is generally advisable to protect your web application against:

1. SQL Injection
and
2. XSS, or cross-site scripting.

It is, however, important not to mix up the two and realize at which point it is appropriate to protect yourself (or your app) from harm.

First, the good news. With CakePHP you are automatically protected from SQL injection IF you use CakePHP’s ORM methods (such as find() and save()) and proper array notation as outlined in the manual. The bad news is that if you are playing around with plain SQL or do not adhere to proper CakePHP syntax of writing queries, you could still be vulnerable to an SQL injection attack.

To be a little more specific, CakePHP will quote and escape all fields and values in your queries, assuming you’re following the rules, to keep your DB nice and safe.
(If you care about more details, see here).
It is important to note, that updateAll() does not escape the fields, so be cautious when using it.

So, technically you have to worry very little about SQL injection when working with CakePHP.

Now, what about user inputting some evil scripts into your blog to hijack your site?

I think the most important point here is that any HTML script, tag or trick is perfectly safe to store in your database as is.
The basic rule is that you do not need to sanitize HTML data in any way before saving it into the database.

When you are concerned about XSS it is the output of data from the database that you need to worry about. If you display raw data from the DB, it is quite possible that you’ll have “evil scripts” injected into your page. With CakePHP it is easy to combat enough with a handy h() method.

Are there cases where you must sanitize HTML before saving it to the database?
Probably, but I can’t really think of any.
Even if your application requires it, you might want to create two fields in the relevant table raw_data and sanitized_data, as an example.

P.S. AD7six just proposed an excellent question, which he also answered just as well… Why allow script code to be stored in some user’s profile? The answer is that having this raw (although unwanted) data is useful for tracking and dealing with malicious users. That’s where having two fields in the table to store sanitized and raw data might come in very handy. If you remove the script tags prior to storing the user information, it’ll become much harder to find and flag users who are obviously trying to screw with your app.

Simplistic example of row-level access control with Auth, Security and App Model in CakePHP

Let me just preface this post, by saying that this is indeed a very much simplified example.
The main purpose here is not to provide a solution that will fit any application, but rather give a decent foundation to further expand your own solution.

The example is based on Auth (you should know a little about the Auth component), the Security component and a simple method in your App Model.

Let’s say we have some journaling app with Articles Controller, which has a “view” action.
We only want to allow access to view the journal articles to their owners, i.e. the users who’ve actually wrote the article (or journal entry).

To illustrate this further, I am going to attempt to access a URL such as:
http://www.example.com/articles/view/8

The goal is to ensure that article with ID = 8, actually belongs to me (AKA the currently logged in user), and if I start tampering with URL by changing the ID, the access to “view” should be denied (unless I happen to pick another article ID, which belongs to me).

In a typical setup we probably have an “articles” table with a “user_id” field, i.e. User hasMany Article.

With that in mind we can create an easy method in our App Model to check for user access:

function canAccess($userId = null, $primaryKey = null) {

        if($this->find('first', array('conditions' => array($this->alias.'.user_id' => $userId, $this->primaryKey => $primaryKey),
                                           'recursive' => -1))) {
            return true;
        }

        return false;
}

Update (05/13/2009): Some users pointed out that recursive = -1, might cause problems with following find() operations. I’ve updated the code to pass ‘recursive’ as part of the find(), which resets the value back to the original in the latest versions of cake. Either way, you don’t want to pull associated models on this simple check.
If you decide to reset recursive later on, or better yet, use Contanable behavior, this solution should work perfectly well.

The above function simply looks for a combination of Article.user_id and Article.id to ensure that the Article actually belongs to the logged-in user.

So how do we use this in the Articles controller?
Perhaps something like this:

function beforeFilter() {
   if (in_array($this->action, array('view'))) {
      if(!$this->Article->canAccess($this->Auth->user('id'), $this->params['pass'][0])) {
         $this->Security->blackHole($this);
      }
   }
}

If the action is “view”, we pass the logged-in user ID $this->Auth->user(‘id’) and the article ID $this->params['pass'][0] to check the access.
If no record with both ID’s is found, we “blackhole” the request, otherwise the access is allowed.

And there you have it, a very simple way to control row-level access to any action in your controller.
As mentioned, I’m hoping that this post will inspire some ideas and will let you expand further in your app.

P.S. Do not forget to include your Auth and Security components, and if you need to get some more info on both of them you can take a look at the CakePHP manual or even do a quick search on this blog.

Clearing up some confusion regarding the Security component

In the previous post, I’ve made a little “mistake” (if you wish to call it that) in the way I’ve setup the Security component…

So, here I’d like to shed some light on the way things really work.

This is the code I’ve been using in the past and…, I guess, didn’t fully investigate what exactly happens, when such setup is used:

class UsersController extends AppController {

   var $name = 'Users';
   var $components = array('Security');

   function beforeFilter() {
        $this->Security->requireAuth('add');
   }

   //the rest of your controller code....
  //....
}

First, Tarique Sani pointed out that $this->Security->requireAuth(‘add’);, is not really necessary to make the Security component produce the hash and verify against the one sent with the form data.
So we can really easily protect our forms by just including: var $components = array(‘Security’); and nothing else.

After that, Nate explained that “adding $this->Security->requireAuth(’add’); adds a different type of form security. By default (without calling any methods) the Security component will make forms generate a hash to ensure that they haven’t been tampered with. Adding requireAuth(), on the other hand, writes a random hash to the session, which also gets written into the form. On POST, these hashes are compared. This protects the form from CSRF attacks, and is the only type of protection that interferes with Ajax or multiple tabs.”

The issue with forms not working with multiple tabs (or AJAX calls) was brought up by Reen and Jonah, and while I thought it was a nice, extra security feature, it is understandable that for some people it might be a drawback.

Well, now we’re all, hopefully, on the same page… and once again Nate and cake save the day :)

Make your CakePHP forms a lot more secure

Update: 11/06/2008
Tarique Sani pointed out that I had an extra line of code, which wasn’t necessary to make all this work (perhaps an old habit, but the post has been modified to reflect the change).
———————

My recent post started up some good conversations and I figured that a good follow-up would be an example of how to use the Security component to make your forms much more… secure.

We’ll start with a basic usage and then expand a little…

First let’s assume a basic model:

class User extends AppModel {

  var $name = 'User';

  var $validate = array(
      'name'=>array('rule'=>'notEmpty'),
      'email'=>array('rule'=>'email'),
      'password'=>array(
              'Cannot be empty' => array('rule'=>'notEmpty'),
            'Must be at least 4 chars' => array('rule'=>array('minLength', 4))
      )
  );
}

We’ve got some basic validation rules defined (and note, there is no ‘required’=>true, which was the point of confusion and problems for some people).

Now we’ll assume that we have an evil user, who wants to tamper with our form fields and bypass the ‘name’ field, for example, to save blank data into the DB. If we leave our form unsecured, it is very easy to remove the field from the data array (by using some basic hacking tool) and since it won’t be present in the array, the validation will be skipped and the form data will be saved with a blank name.

So how can we avoid this problem, by using the Security component?

Let’s build our controller:

class UsersController extends AppController {

    var $name = 'Users';
    var $components = array('Security');

    function add() {
        if(!empty($this->data)) {
            $this->User->save($this->data);
        }
    }
}

And a basic view for the add action:

echo $form->create();
echo $form->inputs(array('name', 'email', 'password'));
echo $form->end('Register');

Pretty simple, right?
We’ve made our form quite secure with only one “extra” line of code:
var $components = array(‘Security’);

Let me explain exactly what happens behind the scenes…

The Security component will create a hash based on the form fields produced by our Form Helper. If someone tampers with the form fields (by adding or removing or changing any field), the hash is not going to match with the expected one and the add() action will fail.

Yep, it’s that simple. You are welcome to try to mess around with the form by using your favorite POST-modifier tool (maybe: https://addons.mozilla.org/en-US/firefox/addon/1290, thanks to Jonah for providing the link).

You’ll notice that the action will fail without any error message (you’ll just get a blank screen in most cases). In my opinion, that’s just fine for any evil user… why make the app user-friendly for them?

Well, let’s be nice and make it a bit more user-friendly. It’s a good exercise, if anything…

First, we’ll extend our controller a little by creating a beforeFilter() method, let’s add one more line of code to it:

  function beforeFilter() {
        $this->Security->blackHoleCallback = 'fail';
  }

The $this->Security->blackHoleCallback = ‘fail’; tells the Security component to call our custom fail() method, in case the action gets black-holed, which it will if someone tampers with the form.

So let’s create the fail() method:

 function fail() {
        $this->cakeError('youSuck');
    }

Alright, as you can see this method will in turn trigger the youSuck() error method, which we’ll need to build in our custom app_error.php handler:

So, if you don’t have one, create app_error.php in your /app/ root directory (this is where you define custom error methods, or override existing ones).

class AppError extends ErrorHandler {
    function youSuck() {
        $this->controller->set(array(
             'name' => __('You are an evil person', true)
         ));

        $this->__outputMessage('bad_user');
    }
}

And now we need a new view bad_user.ctp, which is placed in /app/views/errors/bad_user.ctp

<h2><?php echo $name; ?></h2>
<p class="error">
  <strong><?php __('Error'); ?>: </strong>
  <?php  __('Do not try that again!'); ?>
</p>

Now, when someone tampers with the form, they’ll get a nice error page suggesting what we really think of hackers.

Hopefully you can see how Security component can make your app a lot more secure with just 2-3 extra lines of code. And at the same time we’ve covered a little example of how to best handle custom errors.

P.S. You can make your form even more secure by supplying additional params to save().

CakePHP and save() security

An interesting point came up on IRC…

What happens if someone submits data to your application via a fake form?

How can you ensure that a malicious user will not simply save some unwanted data by filling your $this->data array with things you don’t want there? For example, by sending an “extra” field, one could post $this->data['User']['id'] = 5; and trigger an update instead of save… well you can use your imagination to come up with some other evil tricks.

A simple solution is to ensure that you pass a third parameter to your save() method. If you take a look at the API, you’ll see that save() will allow you to specify a list of fields, which you know should be saved, the rest will be ignored. 

P.S. Additional security for your forms (and ultimately your data) can be achieved with the Security component.