В этой статье мы поговорим о “секьюрной” (безопасной) разработке в Salesforce. Мы рассмотрим концепции, лежащие в основе разработки безопасных приложений на платформе Salesforce с использованием Apex, Visualforce и LWC, которые необходимо понять каждому разработчику и архитектору Salesforce. Мы обсудим основные виды уязвимостей и опасностей, а также расскажем, как избежать появления некоторых из них в вашем коде, как обеспечить безопасность данных и предотвратить атаки злоумышленников.
User Mode vs System Mode
В Salesforce существует два возможных режима запуска кода:
System Mode:
- Код запускается, игнорируя все доступы пользователя. К примеру, у пользователя нет доступа к объекту, но в системном режиме этот объект будет доступен для этого пользователя.
- В системном моде Apex код имеет доступ ко всем объектам и полям, т.к. Profiles, FLS и Sharing rules игнорируются. Это сделано для того, чтобы код не “падал” из-за того, что какой-то объект или поле не доступно для пользователя.
- В Salesforce весь Apex код выполняется в системном режиме. Единственное исключение - анонимные блоки, такие как Dev Console и стандартные контроллеры. Даже метод runAs() не обеспечивает принудительное использование разрешений пользователей или разрешений на уровне полей, он только обеспечивает общий доступ к записям.
User Mode:
- Запуск кода происходит с соблюдением разрешений пользователя, если вошедший в систему пользователь не имеет разрешения на создание - он не сможет создать запись.
- К пользователю применяются все Profiles, FLS и Sharing rules.
- В Salesforce в пользовательском режиме работают только стандартные контроллеры и анонимные блоки, такие как консоль разработчика.
Object and Field-level Security(CRUD & FLS)
Обеспечение CRUD и FLS в Apex
По умолчанию Apex не применяет разрешения на уровне объектов и полей. Давайте посмотрим, как мы можем обеспечить соблюдение CRUD и FLS в Apex.
SOQL | DML | |
---|---|---|
Schema methods | Да | Да |
WITH SECURITY_ENFORCED | Да | Нет |
Security.stripInaccessible() | Да | Да |
User mode database operations | Да | Да |
Schema Methods
Вы можете применить разрешения на уровне объектов и полей в своем коде, явным образом вызвав методы Schema.DescribeSObjectResult.
CRUD
Используйте методы isAccessible, isCreateable или isUpdateable объекта Schema.DescribeSObjectResult, чтобы проверить, имеет ли текущий пользователь права на чтение, создание или обновление объекта sObject.
- Schema.sObjectType.Contact.isAccessible() – перед запросом
- Schema.sObjectType.Contact.isCreateable() – перед инсертом
- Schema.sObjectType.Contact.isUpdateable() – перед обновлением
- Schema.sObjectType.Contact.isDeletable() – перед удалением
if (Schema.sObjectType.Contact.isDeletable()) {
// Delete Contact
}
FLS
Вы можете вызвать приведенные ниже методы для проверки безопасности на уровне поля:
- Schema.sObjectType.Contact.fields.Status__c.isAccessible() – перед запросом
- Schema.sObjectType.Contact.fields.Status__c.isCreateable() – перед инсертом
- Schema.sObjectType.Contact.fields.Status__c.isUpdateable() – перед обновлением
if (Schema.sObjectType.Contact.fields.Email.isAccessible()) {
Contact c = [SELECT Email FROM Contact WHERE Id= :Id];
}
WITH SECURITY_ENFORCED
Используйте выражение WITH SECURITY_ENFORCED, чтобы включить проверку разрешений безопасности на уровне полей и объектов для запросов SOQL в коде Apex.
Это выражение проверяет как CURD, так и FLS.
List<Account> acctList = [
SELECT Id, (SELECT LastName FROM Contacts)
FROM Account
WHERE Name like 'Acme'
WITH SECURITY_ENFORCED];
Security.stripInaccessible()
Используйте метод stripInaccessible для принудительной защиты данных на уровне полей и объектов. Этот метод можно использовать для удаления полей из результатов запроса и подзапроса, к которым пользователь не может получить доступ. Этот метод также можно использовать для удаления недоступных полей sObject перед операциями DML, чтобы избежать ошибок и очистить объекты sObject, которые были десериализованы из ненадежного источника.
SObjectAccessDecision securityDecision = Security.stripInaccessible(AccessType, sourceRecords);
Contact ctc = securityDecision.getRecords()[0];
System.debug(ctc.isSet('social_security_number__c')); // false
User mode database operations (Pilot)
Теперь вы можете объявить, когда Apex выполняет операции с базой данных в пользовательском или системном режиме. Новые методы базы данных поддерживают параметр AccessLevel, который позволяет выполнять операции с базой данных в пользовательском режиме, а не в системном режиме по умолчанию.
- Методы Database.query
- Методы Search.query
- Методы Database DML(insert, update, upsert, merge, delete, undelete, convertLead)
Record-level security(Sharing)
Ключевые слова With/Without Sharing
Apex обычно запускается в системном контексте, что означает, что во время выполнения кода действуют разрешения текущего пользователя и безопасность на уровне поля. Наш код Apex не должен предоставлять пользователю конфиденциальные данные, которые скрыты в настройках безопасности и общего доступа. Следовательно, безопасность Apex и соблюдение правил общего доступа являются наиболее важными. Давайте посмотрим, как мы можем обеспечить применение “шарингов” в Apex.
Не имеет отношения к CRUD и FLS
Sharing Mode | When to use |
---|---|
with sharing | Используйте при объявлении класса, чтобы применить “шаринг рулы” для текущего пользователя. |
without sharing | Используйте при объявлении класса, чтобы гарантировать, что “шаринг рулы” не применяются для текущего пользователя. Класс, объявленный с этим ключевым словом, выполняется в системном режиме. |
inherited sharing | Используйте при объявлении класса, чтобы применить “шаринг рулы” класса, который его вызывает. |
без использования ключевых слов | Apex без явного объявления “шаринг рулов” по умолчанию небезопасен, т.к. класс запустится в системном режиме. Настоятельно рекомендуется всегда указывать объявление “шаринг рулов” для класса. |
Применение “шаринг рулов” для текущего пользователя может повлиять на:
- SOQL и SOSL запросы. Запрос может вернуть меньше строк, чем при работе в системном контексте.
- DML-операции. Операция может завершиться неудачно, потому что текущий пользователь не имеет необходимых разрешений.
Data Security in LWC
Базовые компоненты LWC реализуют CRUD, FLS и Sharing.
- lightning-record-form
- lightning-record-edit-form
- lightning-record-view-form
Адаптеры и функции LDS Wire реализуют CRUD, FLS и Sharing при вызове Apex.
Application Security
SOQL Injection
Когда запросы строятся непосредственно со встроенными пользовательскими данными или текстом пользовательского запроса, вредоносный ввод может изменить структуру запроса, чтобы обойти или изменить логику приложения. Это называется SOQL Injection.
Предотвращение SOQL Injection
В Salesforce доступен следующий способ предотвращения внедрения SOQL:
- Используйте статические запросы
public static List<Account> getAccount(String searchValue) {
String likeValue = '%Acme%';
return [SELECT Name FROM Account WHERE Name LIKE :likeValue];
}
- Если необходимо использовать динамические запросы, всегда “биндите” пользовательский ввод с помощью “:”
public static List<Account> getAccount(String searchValue) {
String likeValue = '%' + searchValue + '%';
return (List<Account>) Database.query(
'SELECT Name FROM Account WHERE Name LIKE :likeValue'
);
}
- Если это невозможно, экранируйте, введите тип или добавьте входные данные в whitelist.
String query = 'Select Name From Account Where Name like \'%'+String.escapeSingleQuotes(name)+'%\'';
String query = 'Select Name, Address from Object__c where isActive = ' + Boolean(input);
CSRF (Cross-Site Request Forgery)
Защита по умолчанию, которая включает токен при каждом запросе ресурсов, который проверяется на сервере. Кроме того, локер блокирует доступ к определенным конечным точкам с помощью XMLHttpRequest.
Как разработчик:
- Не изменяйте состояние (выполнять DML) при загрузке компонента connectedCallback, renderedCallback и тд.
- Проверьте заголовок источника на ваших открытых конечных точках API или добавьте пользовательские токены для защиты от CSRF.
Locker Service
Locker Service — это мощная архитектура безопасности для компонентов Lightning. Служба Locker повышает безопасность, изолируя компоненты Lightning, принадлежащие одному пространству имен, от компонентов в другом пространстве имен. Служба Locker также продвигает лучшие практики, которые улучшают возможность поддержки вашего кода, разрешая доступ только к поддерживаемым API и исключая доступ к неопубликованным внутренним компонентам платформы. Более детально ознакомиться с Locker Service можно перейдя по ссылке.
А на этом у меня все! Сегодня мы вкратце рассмотрели модель секьюрности в Salesforce и обсудили основные виды уязвимостей и опасностей с которыми вы можете встретиться в процессе разработки. Всем добра и мирного неба.