Salesforce’s Apex language empowers developers to perform sophisticated business logic and automate complex processes within the platform. Ensuring that this code adheres to the security and sharing models of Salesforce is crucial to maintaining data integrity and privacy. This guide covers the key aspects of Apex security and sharing, providing technical insights and best practices.
Understanding Apex Execution Contexts
Execution Contexts in Apex:
- User Context: When Apex code runs in the user context, it respects the permissions of the current user, including field-level security, object permissions, and sharing rules.
- Usage: This context is typically used for operations where data access must be limited to what the user is allowed to see and manipulate.
- Example: Code within a Visualforce page or Lightning component controller often runs in the user context.
// This code runs in user context, respecting sharing rules and user permissions.
public with sharing class UserContextExample {
public void updateContacts() {
List<Contact> contacts = [SELECT Id, Email FROM Contact];
for (Contact c : contacts) {
c.Email = 'updated@example.com';
}
update contacts;
}
}
2. System Context: In system context, Apex code runs with full permissions, bypassing the current user’s permissions, field-level security, and sharing rules. This means the code has access to all data.
- Usage: This context is used for operations that require elevated privileges, such as system-level operations, batch processing, and scheduled jobs.
- Example: Trigger execution and anonymous Apex run in the system context by default.
// This code runs in system context, ignoring sharing rules and user permissions.
public without sharing class SystemContextExample {
public void deleteAllContacts() {
List<Contact> contacts = [SELECT Id FROM Contact];
delete contacts;
}
}
Sharing Keywords in Apex
Key Keywords for Sharing:
- With Sharing:
- Definition: Enforces the sharing rules of the current user. The class respects the user’s sharing settings and limits access to data accordingly.
- Example:
public with sharing class AccountHandler {
public List<Account> getAccounts() {
return [SELECT Id, Name FROM Account];
}
}
2. Without Sharing:
- Definition: Ignores the sharing rules, allowing the code to run with system privileges. This can access all records, regardless of the user’s sharing rules.
- Example:
public without sharing class AdminTasks {
public void updateAllAccounts() {
List<Account> accounts = [SELECT Id FROM Account];
for (Account acc : accounts) {
acc.Name = 'Updated';
}
update accounts;
}
}
3. Inherited Sharing:
- Definition: Inherits the sharing rules from the class that called it, providing flexibility and ensuring consistency in security enforcement.
- Example:
public inherited sharing class SomeClass {
// Code here inherits sharing settings from the caller context
}
Enforcing Object and Field Level Security in Apex
You can use the following methods from the Schema.DescribeSObjectResult to check if a user has access to read, create, update, or delete the object:
- isAccessible
- isCreateable
- isUpdateable
- isDeletable
- Object Permissions:
- Access Check: Ensure the current user has the required permissions before carrying out any operations on an object.
- Example:
// Example to check object-level permissions
public void checkObjectPermissions() {
if (!Schema.sObjectType.Contact.isCreateable()) {
throw new AuthorizationException('Insufficient permissions to create Contact records.');
}
Contact newContact = new Contact(LastName='Smith');
insert newContact;
}
2. Field-Level Permissions:
- Access Check: Ensure that the user has access to specific fields before querying or modifying them.
- Example:
// Example to check field-level permissions
public void checkFieldPermissions() {
if (!Schema.sObjectType.Contact.fields.Email.isAccessible()) {
throw new AuthorizationException('Insufficient permissions to access Contact Email field.');
}
Contact contact = [SELECT Email FROM Contact LIMIT 1];
System.debug(contact.Email);
}
Security-Enforced Queries:
- USER_MODE in SOQL: USER_MODE is a security feature that enforces user permissions and sharing rules directly in SOQL queries.
Example:
List<Account> accounts = [SELECT Id, Name FROM Account USING USER_MODE];
- WITH SECURITY_ENFORCED: Automatically enforces field and object permissions in SOQL queries.
Example:
// Query enforcing field and object-level security
public List<Account> getSecuredAccounts() {
return [SELECT Id, Name FROM Account WITH SECURITY_ENFORCED];
}
In Salesforce, prioritizing Field-Level Security (FLS) enforcement with WITH USER_MODE over WITH SECURITY_ENFORCED offers distinct advantages:
- User mode meticulously handles polymorphic fields like Owner and Task.WhatId, processing all SOQL clauses, including the where clause.
- It also identifies SOQL query errors effectively using the getInaccessibleFields() method on Query Exception.
- The AccessLevel class enables user mode enforcement in key database methods including Database.query, Database.getQueryLocator, Database.countQuery, Search.query, and Database DML methods.
// Example of enforcing user mode in DML statements Database.SaveResult[] results = Database.insert(records, AccessLevel.USER_MODE);
When using AccessLevel.USER_MODE, developers can access DML errors via SaveResult.getErrors().getFields(). For insert operations, the DMLException method getFieldNames() helps identify fields with FLS errors.
Enforce Security with stripInaccessbile Method
Security enforcement is further strengthened by the stripInaccessible method, which selectively removes inaccessible fields and relationship fields from query and subquery results, ensuring data protection.
The stripInaccessible method carefully evaluates source records for FLS compliance and excludes inaccessible fields from the returned list of sObjects.
// Example of using stripInaccessible method
List<Contact> contacts = [SELECT Id, Name, Email, SSN__c FROM Contact];
Security.stripInaccessible(AccessType.READABLE, contacts);
// Example of checking field accessibility
Contact contact = new Contact();
contact.Email = 'test@example.com';
contact.SSN__c = '123-45-6789';
Security.stripInaccessible(AccessType.CREATABLE, new List<Contact>{contact});
Best Practices for Secure Apex Code
- Enforce Field-Level Security (FLS):
Always respect FLS by checking field accessibility using the Security.stripInaccessible method.
Avoid hardcoding field or object names in your code. Instead, use Schema methods to dynamically reference fields and objects. - Avoid SOQL Injection:
Use parameterized queries or bind variables in SOQL queries to prevent injection attacks.
Sanitize user input and validate against expected data types and formats before using them in queries. - Handle Exceptions Securely:
Implement exception handling in your code to gracefully handle errors and prevent exposing sensitive information to users.
Avoid using generic catch blocks and provide specific error messages to aid in troubleshooting without divulging sensitive details. - Implement Proper Sharing and Access Controls:
Follow the principle of least privilege by granting users only the permissions they need to perform their tasks.
Use Salesforce’s built-in sharing mechanisms such as sharing rules, manual sharing, and Apex managed sharing to enforce record-level security. - Secure External Integrations:
Use OAuth or Named Credentials for secure authentication and authorization when integrating with external systems.
Validate and sanitize input received from external sources to prevent injection attacks and other security vulnerabilities. - Encrypt Sensitive Data:
Encrypt sensitive data using Salesforce Shield Platform Encryption or custom encryption mechanisms to protect data at rest and in transit.
Be cautious when storing sensitive data in custom settings or custom metadata, as they may be accessible to users with administrative privileges. - Regularly Review Code for Security Vulnerabilities:
Conduct regular code reviews to identify and address security vulnerabilities in your Apex code.
Stay informed about the latest security best practices and updates from Salesforce, and apply them to your codebase as needed. - Use Secure Coding Patterns:
Follow secure coding patterns such as the Principle of Least Privilege, Defense in Depth, and Secure by Default.
Leverage Salesforce’s built-in security features and functionalities whenever possible rather than reinventing the wheel. - Keep Up with Salesforce Security Updates:
Stay informed about security advisories and updates from Salesforce by subscribing to the Salesforce Security Newsletter and regularly reviewing the Salesforce Trust site.
Apply critical security patches and updates promptly to protect your Salesforce org from known vulnerabilities. - Educate Developers on Security Best Practices: Provide comprehensive training and resources to your development team on secure coding practices, common security vulnerabilities, and how to mitigate them.
Foster a culture of security awareness and encourage developers to prioritize security throughout the development lifecycle.
Conclusion
Apex security and sharing in Salesforce are critical components for maintaining data integrity and protecting sensitive information. By understanding and implementing the appropriate sharing rules, enforcing object and field-level security, and following best practices, developers can ensure their Apex code adheres to the highest security standards.

Leave a Reply