Writing secure Apex with the latest security best practices

Over the last few years, there have been a lot of changes around enforcing the CRUD (create, read, update, and delete) and FLS (field-level security) securities in Apex.

Writing secure Apex with the latest security best practices
Table of contents

The diagram above depicts the evolution of Apex security best practices. It dates back to 2006 when Salesforce developers used to do manual checks on objects to check for CRUD/FLS permission.

🔏
In 2019, Salesforce released some significant updates (“WITH SECURITY_ENFORCED” and “Security.StripInaccessible()”) to improve on some of the shortcomings of the earlier approaches.

To address most (if not all) of the issues encountered in the past, Salesforce announced user mode database operations.

Let’s see what it is all about.

Apex, by default, runs in a system mode with elevated permissions, meaning that developers can bypass security controls, such as CRUD, FLS, or record sharing, when writing code.

With user mode database operations, developers can run Apex in the user’s context and enforce the user’s CRUD/FLS and sharing rules access.

Enforce CRUD/FLS and sharing rules in SOQL

🔑
You can set the mode of the operation by using the keyword “WITH USER_MODE” for the user mode and “WITH SYSTEM_MODE” for the system mode in your SOQL (Salesforce object query language) inquiry.

Static SOQL example

Account[] accList = [
    SELECT 
    Id, Name
    FROM Account 
    WITH USER_MODE
]; // User Mode SOQL

Account[] accList = [
    SELECT 
    Id, Name
    FROM Account 
    WITH SYSTEM_MODE
]; // System Mode SOQL
Using the keyword “WITH USER_MODE,” the query respects the CRUD, FLS, and record level sharing security constraints.

Dynamic SOQL example

String query = 'SELECT Id, Name FROM Account';
Account[] accList = Database.query(query, AccessLevel.USER_MODE);

A database class has new overloaded methods, which now support an “AccessLevel” parameter.

Enforce CRUD/FLS and sharing rules for SOSL

🗣️
“WITH USER_MODE” or “WITH SYSTEM_MODE” are also supported for SOSL (Salesforce object search language) statements.

Static SOSL example

String keyword = 'Test';
List<List<SObject>> searchResults = [ 
    FIND :keyword
    IN Name FIELDS
    RETURNING
    Account(Name), 
    Contact(LastName, Account.Name)
    WITH USER_MODE
];

Dynamic SOSL example

String query = 'FIND \'Test*\' IN ALL FIELDS RETURNING Account(Name), Contact, Lead'; 
List<List<SObject>> searchResults = Search.query(query, AccessLevel.USER_MODE);  
Like the database class, a search class also has new overloaded methods, which now support an “AccessLevel” parameter.

Enforce CRUD/FLS and sharing rules for DML

🖥️
Database operations can specify user or system modes using the keywords as a user or system.
//Creating an account in user mode.
insert as user new Account(
   Name = 'Test Account'
);

//Creating an account in System mode.
insert as system new Account(
   Name = 'Test Account'
); 

For Dynamic DML, developers can use the “AccessLevel” parameter to run database operations in the user or system mode.

Database.insert(
    new Account(
        Name = 'Test Account'
    ),
    true, /*All or Nothing*/
    AccessLevel.USER_MODE
);

Important considerations

  • User mode DML operations now generate the correct DML exception. Previously, they generated a security exception. This behavior is versioned, and the valid exception is generated in API version 58.0 and later.
  • A SOQL query using the “WITH USER_MODE” keyword supports restriction and scoping rules instead of the “WITH SECURITY_ENFORCED” keyword.
  • A user mode overrides the class-level setting for the SOQL query or DML written in the mode.
public without sharing Example {
   public Account[] getAccounts() {
      String query = 'SELECT Id FROM Account';
      return Database.query(query, AccessLevel.USER_MODE);
   }
}
  • In the example above, even though the Apex class is set to run in the system context (without sharing the keyword), the SOQL query runs in the user mode, enforcing security.
  • Salesforce has recommended using the new user mode database ops instead of “WITH SECURITY_ENFORCED” going forward. "WITH SECURITY_ENFORCED" may likely be versioned out at some point.

Secure your APEX best practices

The new Salesforce release introduced numerous exciting updates for Apex, and we can anticipate even more enhancements in the upcoming Summer 2023 release.

Check out the 2023 release notes for a comprehensive overview of all the new Apex features.

🗺️
Furthermore, several exciting additions are planned for the Apex roadmap, so stay tuned for even more innovative things to come!