2

I am trying to research the best way to secure users data. Example: An application has a table 'widgets', each user can have as many 'widgets' as required. The application identifies the 'widgets' by the 'userId' column, which referenced the ID of the logged in user.

Currently the best way I have been able to secure the widget data from being accessed if by overriding the fetchAll() method with my own in my models, and add in WHERE userId = X before passing the params to parent::fetchAll() like so:

class Model_Widgets extends Zend_Db_Table_Abstract {

protected $_name = 'widgets';

/**
 * Abstracted function to ensure data security
 * Adds in a WHERE to the SELECT to check if this user is the datas owner
 * 
 * @see Zend_Db_Table_Abstract::fetchAll()
 */
public function fetchAll($where = null, $order = null, $count = null, $offset = null)
{
    // Handle the additional security check
    $userId = 'userId = ' . Model_Users::getUser()->id;
    // Merge the WHERE userId statement with the rest
    if($where)
    {
        if(is_array($where))
            $where[] = $userId;
        else
            $where = array($where, $userId);
    }
    else
        $where = $userId;

    return parent::fetchAll($where, $order, $count, $offset);
}

This method works fine, but I cant help to think that there must be a better way, I have recently discovered $_rowClass but am still not sure I understand the concept. If overriding concrete functions is the only way to apply these security checks, is there a way to override them once rather than in each model perhaps via a helper, and then simply add a function like the following to each model that needs to check the user against the row:

public function fetchAll(...)
{
    return SecurityCheckHelper::fetchAll(...);

I hope this makes sense, in reality all I am trying to do is make sure users cant access other users data by playing about with ID's in the URL etc. Thanks guys

Jucks
  • 400
  • 4
  • 10

1 Answers1

0

Currently the best way I have been able to secure the widget data from being accessed if by overriding the fetchAll() method with my own in my models, and add in WHERE userId = X before passing the params to parent::fetchAll()

You really should do this for all functions of Zend_Db_Table_Abstract then as this could result in some nasty bugs later on.

these security checks, is there a way to override them once rather than in each model perhaps via a helper, and then simply add a function like the following to each model that needs to check the user against the row:

Why don't you create a new abstract base class that implements this feature for all of your models? Like My_Db_Table_Abstract extends Zend_Db_Table_Abstract.

am trying to do is make sure users cant access other users data by playing about with ID's in the URL etc

This is the controller's job!

In my projects I solve this by using ACL and custom asserts (in my models). This even allows you further modifications without changing your models.

Fge
  • 2,971
  • 4
  • 23
  • 37
  • Thanks for this, I would have thought Zend would have come up with a set way of how best to achieve this. Obviously I can add checks everywhere to ensure the rows are owned by the user before allowing any CRUD's but it would be great if there was a defined method of achieving this via the framework... maybe in the future – Jucks Sep 25 '11 at 00:44
  • Just want to thank you for mentioning custom assertions, that's ultimately what I was looking for here. Cheers. – Jucks Sep 25 '11 at 01:02