-
-
Notifications
You must be signed in to change notification settings - Fork 6.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
mod: convert bizRules into callables, avoiding eval() #471
Conversation
This is not any safer than Because bizRule uses |
I do not think we need this PR, since it creates a lot of inconvenience without any benefits except prefomance. |
@qiangxue My suggestion to make |
Closure cannot be serialized. |
@qiangxue Yes, and we will not selialize it.
|
@qiangxue With that we can take perfomance benefit for PhpManager from this PR and not loose any for DbManager. |
How do you store a biz rule which is a Closure? |
@qiangxue When you use DbManager you should use only strings. When use PhpManager you will have 2 ways:
and
So where is the problem with:
? |
@qiangxue Hmm... You about PhpManager::saveToFile(). Maybe we can take closures bodies through Reflection? |
I don't understand why you want to stick with eval. I do understand it's not bad in general, but I also realize that as soon as AuthItem's API provides bizRule as a string that will be evaluated as PHP code, this property will be exposed to end users for sure. Just look at existing extensions for v1.1. I believe by changing bizRule from string to callable, that issue will be eliminated for the most part. Simply because it won't be as easy any more to just provide a text box for hacking in some code. Of course, accompanying documentation on how to use bizRules when it comes to UI would also be of great value. I also do not see where this change introduces inconvenience. IMO, it's the other way round: Coding bizRules as strings sucks. You get no help whatsoever from your IDE, refactoring tools won't work, those rules never get tested and are prone to be broken when you modify your app. Implementing them as proper code helps you in all respects. Also, as far as I remember, I always wrote my bizRules when developing applications. I never needed them to be coded after the app was deployed. And why on earth should I write php code, put it into a string, pass it to an authItem, only so that very same authItem can later evaluated that code? If all it really needed was a hint to where the code is it has to execute? Exactly this can be achieved using callbacks. If someone finds a way to load and save closures, I'd be happy to see them being used, but to my knowledge, it is not possible. Using callbacks like it is done in this PR on the other hand works out of the box. For both PhpManager and DbManager, no need to introduce features that only half of the implementations can use. It's an easy concept, with barley any overhead, understandable for every php developer. I really hope you reconsider this. |
And this is a problem. Sometimes we need dynamically create bizRules and store it to db. Anyway your PR did not change something. Only illiminate eval and makes the solution of some RBAC tasks impossible. |
Well, I won't go as far as saying every application can have its bizRules defined at dev stage. But I do believe it is way more common than the requirement to change them after the app has been deployed. For cases where this is required, even if I myself never encountered one, the evaluation can still be done in the callback itself. So the PR does not make such a task impossible. It only requires the dev to willingly use eval() inside his callback. I say it again: I think this is an edge case and I don't think this edge case justifies the use of eval for every single bizRule, because for the vast majority, it is not needed. |
@bwoester: Your PR fundamentally is equivalent to the Ultimately I think the solution is to have a list of predefined biz rules and only allow untrusted end users to select from them, and allow trusted users to have the capability of creating arbitrary biz rules. You're right that proper use of biz rules needs good tutorials. For Yii 2, we plan to develop an official RBAC management module, which should serve for this purpose. |
After sleeping on it, I wonder if I'm probably mistaken. After all, my main assumption is that writing bizRules after an app has been deployed is almost never necessary. If you write them while developing your app, there's no need to use Now I wonder if that assumption is just plain wrong? Do you guys make use of runtime created bizRules a lot? I personally didn't ever need this, but this is probably not true for others. |
You can have very complex RBAC backend which generate bizRules on the fly. |
In theory? Sure. Any real use cases? I never encountered one. Also, till today nobody spoke up to say "Yes, I need this frequently, because xyz". So I adhere to my opinion that this is - if at all - a very rare use case and should be implemented by the dev if it is needed. The vast majority of uses cases - which is what the framework should focus on - does not need to evaluate code but should use callbacks. Think of it this way: even if you have very complex scenarios where you need to generate bizRules on the fly, you don't want the user to hack code into the bizRule. Instead, you might trigger a callback, that starts some sort of an configurable evaluation pipeline. |
@bwoester What's the difference between |
The key to prevent security problems here is to restrict the freedom of creating arbitrary biz rules by users who cannot be 100% trusted. There are many ways to implement this. Allowing end users to choose from a list of predefined callbacks is one of the choices. You could also predefine a list of named biz rules, each of which is a PHP statement (instead of a callback). The underlying biz rule evaluation mechanism is still BTW, there is no good way of serializing an anonymous function. You could use reflection to find out the code defining the anonymous function. Then you still need to use |
I think one possible solution we could take is to store an ID or name as a biz rule. There should be an external map between the biz rule ID and the actual definition of the biz rule. The map should only be maintained by 100% trusted users or developers. |
Sounds really good! We also will save space in the database. Especially for |
@qiangxue Suggest some additional php file with format like:
This also can be used for PhpManager. |
Another format is:
|
How to maintain this file (insert, update, delete)? We should consider DB-based storage too. |
It is true that I don't like it and that I try to avoid it when it is possible. But this PR is not based on "I just don't like it". I hope I presented enough arguments pointing out why it should not be used for bizRules.
I don't think this holds completely true. The difference is using
I agree, there needs to be something that identifies a bizRule. An ID or name could be used, but IMO a callback is not that different. It identifies a piece of code to be executed. Maybe it would be more straight forward to use an ID or a name. It could also be used to decouple the actual implementation of the bizRule. Maybe a bit like filters or actions, where an ID is used to reference it, but the implementation can be inline or a custom class. I still question the use of |
@bwoester I'm not saying callback is equivalent to The idea of the named biz rules is to impose the restriction that users can only use a list of predefined biz rules, instead of arbitrary callbacks. Maintaining biz rules means creating new rules and modifying or deleting existing rules. Only 100% trusted users can perform these actions. Examples of 100% trusted users: application developers, site owners and/or administrators. I don't think we can draw the conclusion that biz rules can be developed once for all. Note that biz rules are part of roles/operations. As long as users are allowed to create new roles/operations, there should be cases that new biz rules are needed. The question is who can create what kind of biz rules. |
Got your point and you're right, thx for elaborating on it. 👍 Also your argument of new bizRules for new operations makes sense to me. So basically what remains are two use cases:
While I still liked to have a possibility to execute predefined bizRules for the first kind of applications without using First question is how to store those new bizRules. Basically, there are only two options:
If there will be an ID => bizRule mapping, the bizRules are already decoupled from the auth items. So the rules don't necessarily need to be stored in DB, even when using a DB based rbac manager. Instead, they could directly be stored as PHP code as suggested by @creocoder. An alternative would be to store them in separate files, which might make it easier to manage them (CRUD). Advantage over evaluating strings would be faster execution speed and the possibility to work on the rules using an IDE. Not sure if it worth the effort, though. Maybe only if the biz rules reach a certain size and complexity... |
I think you suggest to maintance this file manually. Since:
|
@bwoester Lets not discuss calbacks VS events() since there is no real difference and we have real alternative to discuss. I'm about bizrule map and store only bizrule ids. |
@qiangxue I suggest for DbManager make Also i think we should make this:
Even if we not accept |
I can not see any benefit from callback usage. Callbacks can not as flexible as plain PHP code processed by eval. This means they can not replace it fully. Speaking of security, business rule codes are stored either in files or database. To modify these data and thus place hazard code to the rules someone will need and unlimited access to such storage. |
@klimov-paul I think its meaningless to discuss callback approach. What do you think about
|
Mapping approach will not be as flexible as eval. |
Sure they can. All you need to do is defining one callback doing evaluation being used for dynamically generated bizRules. There's still no need to use I don't insist on callbacks though. If we really start using bizRule IDs, I would be fine having any alternative. Be it InlineBizRules, BizRuleClasses, callbacks or whatever. EvalBizRules or IncludeBizRules are required if an app allows someone to define his own bizRules. But since I never needed this, please don't force me to |
Seems you not read this issue carefully. Mapping approach can use eval() like current implementation approach or Closures as alternative. |
Never seen action with 10 checkAccess()-es inside? Filters can solve only VERY simple RBAC tasks. |
Reasons for using a biz rule map:
|
So you against biz rules as Closures? |
Should be possible to use a closure as static bizRule and have it executed through |
@creocoder No, I'm not against using Closure. Closure can be executed via I will close this PR and create a new issue specific for this biz rule map thing. |
This changes the implementation of bizRules. They are no longer strings containing PHP code to be evaluated. Instead they are now callables to be invoked. Related issues are #24 and #42.
Of course Manager-implementations need to be able to (de)serialize the callables, so the usage is most likely limited to defining callbacks in the form of
array($classOrInstance,$methodName)
. PhpManager already used var_export, which works nicely with such callback definitions. DbManager now uses (de)serialize for bizRules just like it does for data.Since some people were concerned about loosing flexibility if they couldn't pass php code as bizRules, I included an example of an evaluating bizRule callback in the tests. I still don't think this is a commonly required use case, but if someone really requires users being able to write their own bizRule code, they can use such an approach. So we won't loose anything, only difference is it's now in the responsibility of the developer to provide the bizRule callback that does the evaluation.