• Home
  • Blog
  • Salesforce AppExchange Security Review
Salesforce AppExchange Security Review

Salesforce AppExchange Security Review

What is salesforce security?

The Salesforce Security model assists you in protecting information at various levels, from an org level down to a personal record. The Organization, Objects, Records, and Fields are the logical tiers of security. While using the model allows users to safeguard the organization’s information at four layers.

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 the apex.

Why does salesforce security need in your code?

The Salesforce Security Features Developed by a Salesforce Application Development Company Can Assist You in Empowering Your Users To Do Their Jobs Safely And Efficiently. Salesforce Limits The Exposure Of Data To The Users.

User Mode vs System Mode

System mode means running apex code by ignoring the user’s permissions. like Apex Classes, Apex Triggers, and Apex Services. User mode means running apex code by respecting the user’s permissions and sharing of records. Let’s understand it in more detail.

List of Component  for applying salesforce security in below

  • Apex class Security
  • Application Security
  • Lightning Web Component Security  
  • Visualforce page Security

Security in apex class 

Enforcing Object & FLS Permissions in Apex Apex doesn’t enforce object-level and field-level permissions by default. Let’s see how we can enforce the CRUD & FLS in Apex.
Read data (SOQL) Modify data (DML)
Schema methods Yes Yes
WITH SECURITY_ENFORCED Yes No 
Security.stripInaccessible() Yes Yes
Database operations in user mode (pilot) Yes Yes
Schema Methods You can also enforce object-level and field-level permissions in your code by explicitly calling the sObject to describe result methods.

CRUD

You can call the isAccessibleisCreateable, or isUpdateable methods of Schema.DescribeSObject -Result to verify whether the current user has read, create, or update access to an sObject.
  • Schema.sObjectType.Account.isAccessible() – before querying
For example :
  • Schema.sObjectType.Account.isCreateable() – before inserting
For example :
  • Schema.sObjectType.Account.isUpdateable() – before updating
For example :
  • Schema.sObjectType.Account.isDeletable() – before deleting
For example :

Field Level Security

You can use the below method to check field-level security before querying.
  • Schema.sObjectType.Contact.fields.Status__c.isAccessible()
  • Schema.sObjectType.Contact.fields.Status__c.isCreateable() 
  • Schema.sObjectType.Contact.fields.Status__c.isUpdateable()
For example:   

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. For example:

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)

CRUD, FLS and sharing New parameter on:
  1. Database.query methods
  2. Search.query methods
  3. Database DML methods (insert, update, upsert, delete)
Apex generally runs in system context meaning current user’s permissions and field-level security take place during code execution. Our Apex code should not expose the sensitive data to the User which is hidden via security and sharing settings. Hence, Apex security and enforcing the sharing rule is most important. Let’s see how we can enforce the sharing in Apex.

Not related to CRUD or FLS!!!!

Sharing Enforced  
With sharing  Yes
Without sharing No
Inherited  sharing  Inherit from parent, with sharing if entry point   
No sharing clause  Inherited 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 the current user to Apex code. This does not enforce the Profile permission, only the data level sharing settings. For example:

Without Sharing Keyword

Class declared with this keyword executes in System mode. For example :

Enforcing the current user’s sharing rules can impact:

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

Bulkify Apex Code

The very first principle is to write code for more than one record at a time. We should write scalable code and avoid hitting the governor. Let’s understand with an example. In the code below we are using a hard Coded Index[0]. Means code will only work on single record Solution In the above Trigger, the code explicitly accesses only the first record in the trigger.new collection by using the syntax Trigger.New[0]. Instead, the trigger should properly handle the entire collection of Accounts using Trigger.new collection. For example : Trigger AccountTrigger on Account(before insert){   for(Account acc: trigger.New){     if(acc.Name != null){       // DO something     }   }   }

Avoid SOQL & DML inside for Loop

Do not place SOQL or DML(insert/update/delete/undelete) statements inside a loop. When these operations are placed inside a for loop, database operations are invoked once per iteration of the loop making it very easy. For example:    Map<Id, Account> accountMap=new Map<id, Account>([select id,name, (select id from contacts) from account where id in:trigger.newmap.keyset()]); for(Account acc: accountMap.values()){         for(Contact con:acc.Contacts){          } }

Use of the Limits Apex Methods

Use Apex Limits Methods to Avoid Hitting SF Governor Limits. Many of us are facing governor limit errors in trigger/classes/test classes. Few of the governor limit errors as follow:-
  1. Too many SOQL queries: 101
  2. Dml rows 10001
  3. Too many query rows 50001.
For example: Now, using the above Limit methods we can check how many SOQL queries we can issue in the current Apex Context If(Limits.getLimitQueries() – Limits.getQueries()>0) {           // Execute SOQL Query here. }

Exception Handling in Apex Code

DML statements return run-time exceptions if something went wrong in the database during the execution of the DML operations. Don’t forget to use Try catch blocks for exception handling. With Apex, you can write code that responds to specific exceptions. For example:

System.runAs()

Only for Test Mode Enforces sharing, not CRUD or FLS For example:  @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=’standarduser@testorg.com’,                         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());          }  }

Application Security

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 a SOQL injection attack. Preventing SOQL Injection There is the following way available in Salesforce to prevent SOQL Injections.
  • Use static queries
  • If need to use dynamic queries, always bind user input with “:”
  • If not possible, escape typecast or whitelist inputs

Using static SOQL:

Account[] accts = [SELECT Name, Phone FROM Account];

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

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

Escape Single Quotes / Typecasting

If not possible, escape typecast or whitelist inputs

Escape Single Quotes:

Typecasting like below:

  • 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

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!

Enable Lightning web security in your Org.

  • From Setup, in the Quick Find box, enter Session, and then select Session Settings.
  • On the Session Settings page, select Use Lightning Web Security for Lightning web components and save.
  • Clear your browser cache after enabling or disabling Lightning Web Security to ensure the correct files are loaded in the browser. If you suspect that the correct security architecture is not in effect. 

Load Assets Correctly

To import a third-party JavaScript or CSS library, use the platformResourceLoader module.
  • Download the JavaScript or CSS files from the third-party library’s site.
  • Upload the library to your Salesforce organization as a static resource, which is a Lightning security requirement.
  • In a component’s JavaScript file:
  • Import the static resource.
import myResourceName from ‘@salesforce/resourceUrl/myResourceName’;
  • Import methods from 
import { loadStyle, loadScript } from ‘lightning/platformResourceLoader’; Using the Lightning Platform resource loader guarantees your scripts always load in the correct order, are not duplicated, and load only when all dependencies have already loaded. If the Lightning Platform resource loader is not used, it is possible that you or your customers may encounter page-breaking bugs as a result of a duplicated or improperly loaded script.

Visualforce page security

When does the Platform stop respecting FLS? When you assign from a sObject to a primitive!

Apex: 

Random_Sensitive_Object_1__c r;  wRandom_Sensitive_Object_1 wR; wR.Sensitive_Number = r.Sensitive_Number__c;

Visualforce:

We showed you how to respect FLS read permissions in Apex. Which one of the following would allow you to respect the FLS read permission in Visualforce? Solution: 
  • Rendered=”{!$ObjectType.CustomObject__c.fields.CustomField__c.isAccessible}”
  • Rendered=”{!$ObjectType.CustomObject__c.CustomField__c.isAccessible()}”
  • Rendered=”{!$ObjectType.CustomObject__c.fields.CustomField__c.Accessible}”
  • Rendered=”{!$ObjectType.CustomObject__c.CustomField__c}”