[SalesForce] Security Review – CRUD/FLS Checks for every SOQL Query

I know this sounds like a standard question, so please bear with me.

Recently our Security Reviews fail due to CRUD/FLS violations. The highlighted codelines include almost every SOQL Query in the application.

Our approach is usually as follows:

  • In case of displaying data on VF pages we either use sObjects fields or use the platform methods to check the accessibility of the fields
  • In case of domain logic triggered by the user (e.g. by clicking a button on a VF page) we have a helper class that checks every field to be updated before doing the DML operation.

Up until recently this approach has worked fine (and passed pervious Security Reviews). As mentioned above the latest Security Review results seem to require us to check every field in a SOQL query for accessibility even if it is never displayed back to the user.

Let's suppose the following program flow as an example:

  1. Query an object with some fields
  2. Perform some modification on said fields
  3. Perform an update on the sObject to save the modification using a helper class which checks for the required CUD/FLS rights for the modified fields

As I see it there is no need for checking field accessibility in step 1 in that case (since nothing is displayed back to the user and the dml operation is already protected). Is that correct or am I missing something?
So is it really required to do an accessibility check for every SOQL Query in the code?

Another question would be how to handle background operations in that case like data purging. These have either to be running in system mode (which causes issues during the Security Review) or require the job to be started by a user with the appropriate access rights (which can be error prone and is not that user friendly). Is there any best practice regarding that.

Unfortunately I could not find a question targeting exactly that issue. Most of the questions I have found are related to how to perform that check (like this or that). So please apologize in case the question was already answered (I would really appreciate a link to the answer then).

Thanks for your time and help.

Mathias

Best Answer

You don't need to check every field that you query. The issue really boils down to who manages security for the field -- your app or the admin. With standard objects, the answer is always the admin. With custom objects, it depends on whether the field is user visible and is used by users or whether it is internal and used only by your app. Things like wizard state, Auth state, etc.

The standard example would be something like an app that manages contracts. The text of the contract would be managed by the admin, but something like contract state would be managed by your app.

Because this is fundamentally ambiguous, you can make a false positive document outlining which fields are managed by your app and which are not. The worst thing to do is nothing and let the tester try to guess, as they might not have much time to go through your app and may not understand your app well enough to correctly classify this on their own. So a lot of this is up to you in making the case that you own some objects and not the admin.

Once you have the list of fields you need to check perms for, it doesn't matter whether they are used in WHERE clauses or directly accessed -- you need to make sure that the perms are checked. You can use the ESAPI API which contains helper functions such as updateAsUser(), you can write your own helper functions, or you can do checks centrally in your controller.

Triggers run after other code or the UI already allows an operation, so the trigger wouldn't fire if the user didn't have permission already, assuming all the upstream checks are made when necessary. Therefore triggers that only update the object being modified generally don't need a check, the issue is if the the trigger modifies some other object, in which case you do need to do the check if the object is managed by the admin.

For background/async/scheduled jobs, there is absolutely no difference in security requirements for async apex versus synchronous apex. Whether you do an operation synchronously or not has nothing to do with whether the admin's policies need to be respected. The same concerns apply as above -- do the check if you don't own the object and don't do it if you do.

One thing to keep in mind here is that unlike sharing, you generally control the profiles and permission sets of your users as you can package these with your app. So package the permissions so that your checks always return true. Then, if your checks return false, it means that the admin assigned a different perm set or changed the perm set assignment for a user of your app, which is something that should generally result in a failure message. There may be situations in which the app should not work for a user -- say the admin removed some perms from that user, but due to not having deep knowledge of how your app works, did not remove that user from your app. Making these checks is exactly for this type of conflict situation, and generally you want to stop processing with an error message and let the admin resolve the inconsistency at the perm level, rather than trying to guess what the admin would want to do and then override the org perms. This is because if every app overrode the org perms, then the admin wouldn't be able to manage permissions centrally anymore.

Related Topic