Security in Salesforce

In this session we will talk about Apex security in Salesforce which developer must know. We’ll go through the main concepts that developers must understand to code secure applications on the Salesforce Platform. We will cover how to enforce data security and how to prevent SOQL injection attacks in Apex. We’ll also review what Locker Service does for you and security best practices for LWC. We will also cover some security in Salesforce interview questions for apex.

We will not talk about how to configure security in Salesforce. If you want to learn about who see what check this post. When you use Apex, the security of your code is critical. You’ll need to add user permissions for Apex classes and enforce sharing rules.

User Mode vs System Mode

System mode means running apex code by ignoring user’s permissions. User mode means running apex code by respecting user’s permissions and sharing of records. Let’s understand it in more detail

User Mode vs System Mode

Object and Field-level Security (CRUD & FLS)

Here is CRUD & FLS Data Model

Object and Field-level Security (CRUD & FLS)

Enforcing Object & FLS Permissions in Apex

Apex doesn’t enforce object-level and field-level permissions by default. Let see how we can enforce the CRUD & FLS in Apex.

Read data (SOQL)Modify data (DML)
Schema methodsYesYes
WITH SECURITY_ENFORCEDYesNo
Security.stripInaccessible()YesYes
Database operations in user mode (pilot)YesYes

Schema Methods

You can also enforce object-level and field-level permissions in your code by explicitly calling the sObject describe result methods.

CRUD

you can call the isAccessibleisCreateable, or isUpdateable methods of Schema.DescribeSObjectResult to verify whether the current user has read, create, or update access to an sObject.

  1. Schema.sObjectType.Contact.isAccessible() – before querying
  2. Schema.sObjectType.Contact.isCreateable() – before inserting
  3. Schema.sObjectType.Contact.isUpdateable() – before updating
  4. Schema.sObjectType.Contact.isDeletable() – before deleting
if (Schema.sObjectType.Contact.isDeletable()) {
   // Delete Contact
}

FLS (CRUD Implicit)

You can use below method to check field level security.

  1. Schema.sObjectType.Contact.fields.Status__c.isAccessible() – before querying
  2. Schema.sObjectType.Contact.fields.Status__c.isCreateable() – before inserting
  3. Schema.sObjectType.Contact.fields.Status__c.isUpdateable() – before updating
if (Schema.sObjectType.Contact.fields.Email.isAccessible()) {
   Contact c = [SELECT Email FROM Contact WHERE Id= :Id];
}

WITH SECURITY_ENFORCED

Use the WITH SECURITY_ENFORCED clause to enable field- and object-level security permissions checking for SOQL SELECT queries in Apex code.

It Checks for both CURF & FLS.

List<Account> acctList = [SELECT Id,
          (SELECT LastName FROM Contacts)
           FROM Account
           WHERE Name like 'Acme'
           WITH SECURITY_ENFORCED]

Security.stripInaccessible()

Use the stripInaccessible method to enforce field- and object-level data protection. This method can be used to strip the fields and relationship fields from query and subquery results that the user can’t access. The method can also be used to remove inaccessible sObject fields before DML operations to avoid exceptions and to sanitize sObjects that have been deserialized from an untrusted source

The Id field is never stripped

SObjectAccessDecision securityDecision = Security.stripInaccessible(AccessType, sourceRecords); 
Contact ctc = securityDecision.getRecords()[0];
System.debug(ctc.isSet('social_security_number__c')); // prints "false"

User mode database operations (Pilot)

sfdc.co/user-mode-dml

CRUD, FLS and sharing New parameter on:

  1. Database.query methods
  2. Search.query methods
  3. Database DML methods (insert, update, upsert, merge, delete, undelete, convertLead)

Apex Recipes

github.com/trailheadapps/apex-recipes

Record-level Security (Sharing)

Record Sharing Data Model

Record-level Security (Sharing)

Sharing Clauses for Apex Classes

Apex generally runs in system context means current user’s permissions and field-level security take in place during code execution. Our Apex code should not expose the sensitive data to User which is hidden via security and sharing settings. Hence, Apex security and enforcing the sharing rule is most important. Let see how we can enforce the sharing in Apex.

Not related to CRUD or FLS!!!!

Sharing Enforced
with sharingYes
without sharingNo
inherited sharingInherited from parent, with sharing if entry point
no sharing clauseInherited from parent,
without sharing if entry point except for lightning

With Sharing Keyword

If you use this keyword, then the Apex code will enforce the Sharing settings of current user to Apex code. This does not enforce the Profile permission, only the data level sharing settings.

Without Sharing Keyword

Class declared with this keyword executes in System mode.

Enforcing the current user’s sharing rules can impact:

  1. SOQL and SOSL queries. A query may return fewer rows than it would operating in system context.
  2. DML operations. An operation may fail because the current user doesn’t have the correct permissions

System.runAs()


Only for Test Mode
Enforces sharing, not CRUD or FLS

@isTest
private class TestRunAs {
   public static testMethod void testRunAs() {
        // Setup test data
        // Create a unique UserName
String uniqueUserName = 'standarduser' + DateTime.now().getTime() + '@testorg.com'; // This code runs as the system user
Profile p = [SELECT Id FROM Profile WHERE Name='Standard User'];
User u = new User(Alias = 'standt', Email='[email protected]', EmailEncodingKey='UTF-8', LastName='Testing', LanguageLocaleKey='en_US', LocaleSidKey='en_US', ProfileId = p.Id,
TimeZoneSidKey='America/Los_Angeles', UserName=uniqueUserName);
System.runAs(u) {
// The following code runs as user 'u'
System.debug('Current User: ' + UserInfo.getUserName()); 
System.debug('Current Profile: ' + UserInfo.getProfileId());
}
} 
}

Data Security in LWC

LWC Base Components enforce CRUD, FLS and Sharing

  • lightning-record-form
  • lightning-record-edit-form
  • lightning-record-view-form

LDS Wire adapters and functions enforce CRUD, FLS and Sharing If calling Apex → apply the techniques just seen!

Application Security

SOQL Injection

When queries are built directly with user data inlined or query text, instead of using type-safe bind parameters, malicious input may be able to change the structure of the query to bypass or change application logic. This is called as SOQL injection attack.

Preventing SOQL Injection

There following way available in Salesforce to prevent the SOQL Injections.

  • Use static queries
  • If need to use dynamic queries, always bind user input with “:”
  • If not possible, escape, typecast or whitelist inputs

1 ) Using static SOQL:

2) If need to use dynamic queries, always bind user input with “:”

public static List<Account> getAccount(String searchValue) {
    String likeValue = '%' + searchValue + '%';
    return (List<Account>) Database.query(
      'SELECT Name FROM Account WHERE Name LIKE :likeValue'
    );
  }

3) Escape Single Quotes / Typecasting

If not possible, escape, typecast or whitelist inputs

String query = 'Select Name From Account Where Name like \'%'+String.escapeSingleQuotes(name)+'%\'';

Typecasting like below

String query = 'Select Name, Address from Object__c where isActive = ' + Boolean(input);

XSS (Cross-Site Scripting)

  • Reflected XSS → app echoes malicious script from user input
  • Stored XSS → app returns malicious script from database
  • DOM XSS → reflected XSS but just on the browser

Locker Service

  1. JavaScript Strict mode enforcement
  2. DOM access containment → Safe Harbour: mechanism to relax this restriction
  3. Secure wrappers → sfdc.co/locker-api-viewer
  4. CSP → sfdc.co/locker-csp

CSRF (Cross-Site Request Forgery)

CSRF (Cross-Site Request Forgery)

Default protection that includes a token on each resource request => validated on the server. Additionally, locker will block specific endpoints from being accessed with XHR.

As a developer:

  •  Don’t change state (execute DML) on component load – connectedCallback, renderedCallback….
  •  Validate origin header on your exposed API endpoints or add custom tokens for CSRF protection

Recording

YouTube video

Please subscribe our YouTube channel to get notification for video upload.

Amit Chaudhary
Amit Chaudhary

Amit Chaudhary is Salesforce Application & System Architect and working on Salesforce Platform since 2010. He is Salesforce MVP since 2017 and have 17 Salesforce Certificates.

He is a active blogger and founder of Apex Hours.

Articles: 462

5 Comments

  1. no sharing clause Inherited from parent,
    without sharing if entry point except for lightning

    Please explain what is exactly means of entry point except lightning..does it mean if we call a class from lwc for a private obj will it fetch only the records which user has access if no clause mentioned in apex

  2. @Amit It is very helpful and everyone should know about security in Salesforce. Thank you so much for sharing the Knowledge. Need some more explanation on With Sharing and Without Sharing concepts.

Leave a Reply

Your email address will not be published. Required fields are marked *