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 |
CRUD
You can call the isAccessible, isCreateable, 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
- Schema.sObjectType.Account.isCreateable() – before inserting
- Schema.sObjectType.Account.isUpdateable() – before updating
- Schema.sObjectType.Account.isDeletable() – before deleting
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()
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:- Database.query methods
- Search.query methods
- Database DML methods (insert, update, upsert, delete)
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:-- Too many SOQL queries: 101
- Dml rows 10001
- Too many query rows 50001.
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 inputsEscape 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
- JavaScript Strict mode enforcement
- DOM access containment → Safe Harbour: mechanism to relax this restriction
- Secure wrappers → sfdc.co/locker-api-viewer
- 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
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 methods from
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}”