We are moving our forum in GitHub Discussions. For questions about Phalcon v3/v4 you can visit here and for Phalcon v5 here.

Row Level Security. Dear community, what do you think about?

There was my issue in github, now it's closed, bot don't realized (https://github.com/phalcon/cphalcon/issues/351).

Just want to know community opinion. After you read this post - please, say do you agree with such [NFR] or no.

NFR: I think that the RLS for the ACL is a must.

RLS - Row Level Security, or filtration of the SQL (PHQL) query by the user's defined filters. For instance, RLS can enable an feature when the user must have access to edit bills only of his company (or user can not edit bills of the other companies).

Such permissions must be set in the framework, but work on the database layer.

Code example:

$acl = new Phalcon\Acl\Adapter\Memory();
/* Add RLS */
$rls = array('model' => 'robots',
'allowRead' => array('name' => 'C3PO'), 
'allowWrite' => array('name' => 'DarthVader'));
$acl->addRLS('users', $rls); // Now the user with "users" role can read only robot C3PO and can read and edit Darth Vader. There must be an option, when the value of the parameter can be obtained from the another model or table.
$acl->addRLS('users', array('model' => 'robotparts', 'property' => 'robot_id', 'rls' => $rls)) // Now, the user with "users" role can't read any 'robotsparts' of all robots, except C3PO and Darth Vader.
// And now:
$robot = Robots::findFirst('name = C3PO');
$robot->save() // returns "false", because user can only read C3PO data, but not write
foreach ($robots->getRobotsParts() as $part)
 $part->save() // returns "false"
$robot = Robots::findFirst('name = R2-D2'); // returns "false", because it is not allowed for the user with role "user"

There may be another functions, such as:

$acl->addRLS('users', $rls, true); // Now, all models from the application, where presents binding with "Robots" model, uses the same access restrictions as "Robots" model. It is very useful feature from ERP-practice.
/* Obtaining restrictions from the anoter model*/
$rls = array("model" => 'robots', 'allowRead' => array('model' => 'rowlevelsec', 'rolename' =>'users', 'modelAlias' => 'allowedRobots'));
$rls = array("model" => 'robots', 'allowRead' => array('model' => 'rowlevelsec', 'rolename' => true, 'modelAlias' => 'allowedRobots')); // The same as above, but 'rolename' parameter sets implicitly (later this parameter must be obtained from the role of the acl) .
$acl->('users', $rls); // Now the user with "users" role can read only robots that presents in "rowlevelsec" model in the objects that 'rolename' parameter match 'users', and 'allowedRobots' contains accessable robots. allowedRobots is alias for the belongsTo() method for "rowlevelsec" model.

Main feature of the RLS is that it works DIRECTLY in the database.


  1. If the restrictions are working, than we need to retrieve less data from the database. (traffic improvement)
  2. The application does not transforms the restricted relational table rows into the objects (ORM). (speed improvement)


Really? Nobody answered... What methods do you use to avoid data leaks instead?

I use an approach with adding role based joins to the query automatically before it is executed. So I only fetch the relevant records from the DB.

This works very well for my purposes.