-
-
Notifications
You must be signed in to change notification settings - Fork 825
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
Refs: dev/core#3671 Fix regression involving CiviCRM Webform + Cases. #23836
Conversation
Ignores permissions on api4 call in Recent::getTitle()
(Standard links)
|
In addition to above. Had some more time to look at this. The permissions loosening is on a private method that is only called by the create method of the class - and this class isn't extended anywhere. |
I'm thinking overall this should be merged, but have put some followup thoughts in a new ticket in https://lab.civicrm.org/dev/core/-/issues/3677 |
@@ -182,6 +182,7 @@ private static function getTitle($entityType, $entityId) { | |||
$record = civicrm_api4($entityType, 'get', [ | |||
'where' => [['id', '=', $entityId]], | |||
'select' => [$labelField], | |||
'checkPermissions' => FALSE, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, unfortunately, I believe this has created a security regression.
Steps to reproduce:
- Login as a limited user (eg
advisor
ondmaster
; has permissionaccess CiviCRM
but is limited by ACL-groups) - Determine a contact ID that is not visible to the limited user (eg I chose cid
173
for contact named "Global Empowerment Association") - Open JS console and run:
CRM.api4('RecentItem', 'create', { values: {"entity_type":"Contact", "entity_id":173} })
- Reload the page - look at the list of recent items. If you see
#173
and their name, then you've learned new information about a restricted record.
On 5.50.3 and 5.51-rc (pre-23836), this sequence has a secure outcome -- step 3 raises an error, and step 4 does not reveal any information about contact 173. But with the patch, the user advisor
can see restricted records like 173
. They can just loop through and get all the names.
The patch here would have made sense in 5.48 -- before Civi\Api4\RecentItem
was made available via AJAX. If RecentItem
is fully trusting on both writes and reads, then it can be a vector getting extra info. There needs to be restriction somewhere.
I think the basic question is this: if you use webform (etal) to access a record with elevated privileges (beyond your normal RBAC privileges), should that item be added to "Recent Items"? Consider:
- "Yes" - You viewed an item. It was recent. You should put it on "Recent Items".
- "No" - The "Recent Items" are things that you can go back and see. You can't necessarily go back to a webform. The link sends to the wrong place - somewhere you probably can't even see.
Or even more basically... Does anybody really want webform-views to register as normal views on the "Recent Items"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the creation of recentItems is a default behaviour - A judicious try-catch might be the right fix
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While looking at this I noticed there exists a skipRecentView param for other elements, but it seemed awkward and almost a one-off, but maybe is one approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Grepping for calls to Recent::add
, it appears to be a mix - some low-ish level calls (eg CRM_Contact_BAO_Group::create
calls CRM_Utils_Recent::add()
) and some higher-level form-based calls (eg CRM_Contact_Page_View
). It's probably the BAO-based calls that muck up the webform-elevated-pageviews.
If we don't actually want webform-elevated-pageviews to register as "Recent Items", then perhaps CRM_Utils_Recent::add()
should have an additional permission-check? (Only add this item to the list if we're really sure that the current user has standard access to the item.) It's liable to fire some extra SELECT
s, but it would help secure a couple dataflows (ie the AJAX-RecentItem-API dataflow and the automagic-BAO-dataflows).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just adding that the gist of my spun-off lab ticket is that core should check permissions, but could also provide a way for that external code to say "for everything that follows during this api call I'm making, turn all permission checking off". Not just for Utils_Recent, because this is going to come up with any other secondary api calls made from the primary api call.
So if the idea here is to limit to Utils_Recent, then ok for 5.51, but then going forward is that extendable to all secondary api calls not just Utils_Recent?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@demeritcowboy I tend to agree with the POV in dev/core#3677 that there should be a way to express a default that propagates across multiple calls. (I'll comment more about that on the ticket.) But... it seems to me that this scenario is interesting as a counter-example.
Suppose it propagated more systemically. I would expect it play out like this:
- The user fills out a webform
//example.com/new-subscriber
. - Webform sets
checkPermissions=>false
which propagates toContact.create
API which calls a BAO or fires some hooks and eventually propagates toRecentItem
API. - With no permission checks, you can add anything to the
RecentItem
list. - All is permitted, so it adds CID 123 (aka
//example.com/civicrm/contact/view?id=123
). - But if the user clicks the link for CID 123 (
//example.com/civicrm/contact/view?id=123
), then they'll get a permission-denied error. - That's not the right page for this user. The user never had permission to look at that page. Nobody intends for them to view that link.
There are a couple weak-links that we could attack to resolve this:
- Move responsibility for
RecentItems
out of the BAO. It belongs in a form. (Academically, maybe you'd want add a config-option to enable webform<=>RecentItem integration? But it doesn't feel pressing to me...) - Keep it in the BAO, but do a regular permission-check while writing to
RecentItem
s (despite the privilege-escalation that webform does). - Keep it in the BAO, and do a regular permission-check while reading from
RecentItem
s (despite the privilege-escalation that webform does).
Moving responsibility out of BAO (#1
) feels a bit more "correct" but less practical (IMHO; it'll be a game of whack-a-mole). Adding more permission-checks (#2
or #3
) feels more manageable...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The entire implementation of RecentItems feels shoehorned in. But enforcing permissions is a good solution regardless of other cleanup we end up doing.
Ignores permissions on api4 call in Recent::getTitle()
Overview
Addresses regression identified by colemanw/webform_civicrm#756
Before
Permissions check on api4 call when getting the default title.
After
Permissions ignored on api4 call when getting the default title.
Comments
Please review cautiously - I've not looked at ramifications of removing this permissions check on calls from elsewhere - merely followed the breadcrumbs from -> colemanw/webform_civicrm#756