[SalesForce] CRUD permission check Security Review with SOQL queries needed

The CRUD permission check for Security Review has been imposed recently, though I'm clear on the DML statement and Create/Update/Delete permissions I need to check for in my code, but I'm not clear how to proceed with SOQL queries in my code.

Do I need to verify Object read permissions for Objects & all fields in query before executing SOQL?

Consider following code:

public with sharing class MySetupController {

    public MySetupController() {
        system.debug('@ Read Permission Check: '+Schema.myns__Global_Settings__c.getSObjectType().getDescribe().isAccessible());
        myns__Global_Settings__c[] f   = [Select Id From myns__Global_Settings__c limit 1];
        util.logInfo('f: '+f);
        initSettingsRequired            = (f.size() == 0);
    }

}

In this code, the Schema.myns__Global_Settings__c.getSObjectType().getDescribe().isAccessible() is FALSE but still I am able to execute the query just below that line without any error. I don't understand why it didn't threw error and allowed reading the object, I even get 1 record in the next debug statement for that query.

Please note that the current User's profile does not have any CRUD permission on this object myns__Global_Settings__c. I've turned all Object Permission Checkboxes Off in User's Profile.

Best Answer

You should check that the current user has isAccessible() permission on the fields in the WHERE clause as well as any fields in the SELECT clause being returned to the logged in user. The reason why you need to do this check is that Apex will not throw a DML error when accessing fields that the user cannot access, so it is up to you to enforce the platform's permission model.

There is some confusion if your intuition comes from working in the developer console or via the API. The developer console runs in an execute anonymous context in which permissions are enforced. Permissions are enforced in the API as well. Permissions are not enforced in apex code running in your org, so you as the developer need to enforce them. You will not get permissions exceptions.

Also, be aware of the difference between profile perms, CRUD/FLS perms, and record sharing. Profile perms are always enforced but are only refreshed across logins. CRUD/FLS are never enforced which is why you need to make all those .isAccessible(), and isCreatable() calls before accessing, updating, deleting or inserting records. Record sharing is enforced if your class is 'with sharing'.

In terms of implementation, it's up to you as the dev to enforce programmatically whatever isn't enforced automatically by the platform, where appropriate. In some cases you may want to set a field as private/private for sharing and then ignore sharing when accessing the field. This should only be done for custom fields. In the case of sites and guest user access, you may also need to ignore CRUD/FLS, but again this should only be done for custom fields that are in your namespace. For standard fields you must always enforce CRUD/FLS (no exceptions), and you must always enforce sharing in the entry-points to your app (controllers and global classes). Hide the without sharing code in library functions invoked downstream from your entry points.

Related Topic