Esta es una traducción que desde EGA Futura ofrecemos como cortesía a toda la Ohana y comunidad de programadores , consultores , administradores y arquitectos de Salesforce para toda Iberoamérica .

El enlace a la publicación original, lo encontrarás al final de este artículo.

En Salesforce, la confianza es nuestro valor número uno. Cuando cree aplicaciones en la plataforma Salesforce, tenga la seguridad de que residen en un entorno seguro.

Implementamos las mejores prácticas y estándares de seguridad de la industria en todas las capas, desde la infraestructura hasta el código de la aplicación. Brindamos múltiples opciones de configuración que le permiten implementar un modelo de seguridad de datos efectivo, de modo que los datos sean accesibles solo por usuarios autorizados.También brindamos protecciones integradas para vulnerabilidades de seguridad de aplicaciones comunes, como Cross-Site Scripting, inyección SOQL o Cross -Falsificación de solicitud de sitio. Además de todo eso, le brindamos herramientas para proteger el almacenamiento y la transmisión de secretos que puede utilizar para proteger aún más sus aplicaciones.

Sin embargo, como desarrollador de Salesforce, existen ciertos conceptos y mejores prácticas que debe conocer para evitar la filtración de datos o la creación de vulnerabilidades de seguridad de aplicaciones peligrosas. En esta publicación de blog, le brindaremos una descripción general rápida de las mejores prácticas de seguridad que debe seguir al codificar con Apex y con LWC (Nota: Visualforce y Aura están fuera del alcance de esta publicación de blog).

Hacer cumplir la seguridad de los datos para proteger sus registros

Primero, hablemos de la seguridad de los datos. La seguridad de los datos evita el acceso no autorizado. Es decir, asegura que cada usuario tenga acceso solo a los datos a los que debería tener acceso. En Salesforce, esto se implementa a través de tres capas diferentes: seguridad a nivel de objeto (también conocida como CRUD: Crear, Leer, Actualizar, Eliminar), seguridad a nivel de campo (FLS) y seguridad a nivel de registro (también conocida como Compartir).

Me gusta explicar estas tres capas con la siguiente imagen, en la que imaginamos una base de datos como si fuera una hoja de cálculo. Básicamente, cada capa controla la visibilidad de una tabla (pestaña), columna o registro en la base de datos.

Estas capas de seguridad se configuran a través de varias herramientas, como conjuntos de permisos, valores predeterminados de toda la organización o reglas de uso compartido. Si es un desarrollador en solitario o alguien de un equipo pequeño, puede configurarlos usted mismo. Pero si estás en un equipo más grande, es probable que no lo hagas. Sin embargo, en ambos casos, probablemente escribirá código. Por lo tanto, es extremadamente importante que comprenda cómo se ejecuta el código de la aplicación en lo que respecta a la seguridad de los datos y cómo hacer cumplir los diferentes mecanismos de seguridad de los datos cuando no se aplican de forma predeterminada.

Básicamente, las operaciones en Salesforce se pueden ejecutar en dos modos: modo de usuario, donde se aplica la seguridad de los datos, y modo del sistema, donde no lo está. Las operaciones a través de puntos de entrada como la interfaz de usuario estándar (páginas de registro de Salesforce estándar) y los puntos finales de API estándar se ejecutan en modo de usuario. Los componentes y servicios que se utilizan para crear interfaces de usuario también se ejecutan en modo de usuario. Estos pueden ser componentes Lightning en forma de registro o puntos finales LDS (Lightning Data Service).

Sin embargo, Apex fue diseñado para implementar la lógica empresarial. Muchas veces, los procesos comerciales necesitan acceso a todos los datos, independientemente del usuario que está ejecutando el proceso. Es por eso que decidimos hacer que Apex se ejecute en modo de sistema de forma predeterminada. Esto le brinda flexibilidad, pero al mismo tiempo, debe implementar controles de seguridad de datos cuando el proceso no requiere esos privilegios de datos.

Los puntos de entrada resaltados en la imagen son solo una parte. Puede encontrar una lista más exhaustiva en esta publicación de Stackexchange .

Para hacer cumplir la seguridad de los datos en Apex , deberá verificar los permisos de objetos, campos y niveles de registro cuando:

  • Crea, actualiza o elimina registros con operaciones DML
  • Lees registros con SOQL o SOSL

Hay diferentes formas en las que puede verificar la seguridad a nivel de campo y de objeto en Apex:

  • Usando la WITH SECURITY_ENFORCED en consultas SOQL. Esta cláusula evita la recuperación de objetos y campos a los que el usuario no tiene acceso, lanzando una excepción en su lugar:
     Public static List <Cuenta> getAccountsWithSecurityEnforcement () {
    regreso [
    SELECCIONE Nombre, Ingresos anuales, Industria
    De la cuenta
    CON SECURITY_ENFORCED
    ORDEN POR Nombre
    ];
    }
  • Uso de los métodos Schema.DescribeSObjectResult y Schema.DescribeFieldResult. Permiten una gran flexibilidad para ajustar la forma en que su código verifica la seguridad de los datos, pero también requieren más trabajo de su parte como desarrollador y ocupan más líneas de código:
 cuenta estática pública createAccountCRUDCheck () { Cuenta de cuenta; // Solo cheque CRUD if (Schema.sObjectType.Account.isCreateable ()) { acct = nueva cuenta (); acct.Name = 'ACME'; acct.AnnualRevenue = 1000000; insertar cuenta; } demás { lanzar nueva DMLException ('No hay permisos de objeto para crear una cuenta.'); } cuenta de retorno; }
 Lista estática pública <Cuenta> getAccountsFLSCheck () { // Comprobación FLS (comprobación CRUD implícita) Si ( Schema.sObjectType.Account.fields.Name.isAccessible () && Schema.sObjectType.Account.fields.AnnualRevenue.isAccessible () && Schema.sObjectType.Account.fields.Industry.isAccessible () ) { return [SELECCIONAR Nombre, Ingresos anuales, Industria DE la cuenta ORDENAR POR Nombre]; } return new List <Cuenta> (); }
 Lista estática pública <Cuenta> getAccountsStripInaccessible () { SObjectAccessDecision securityDecision = Security.stripInaccessible ( AccessType.READABLE, [SELECCIONAR Nombre, Ingresos anuales, Sector DE la cuenta ORDENAR POR Nombre] ); System.debug (securityDecision.getRecords ()); return securityDecision.getRecords (); }
 cuenta estática pública createAccountStripInaccessible () { Cuenta cuenta = nueva cuenta (); acct.Name = 'ACME'; acct.AnnualRevenue = 1000000; SObjectAccessDecision securityDecision = Security.stripInaccessible ( AccessType.CREATABLE, nueva lista <Cuenta> {cuenta} ); insertar securityDecision.getRecords (); return (Cuenta) securityDecision.getRecords () [0]; }

Hay una cuarta opción, que todavía no está disponible en general, pero en fase piloto, llamada Código Apex seguro con operaciones de base de datos en modo de usuario . Con este piloto, los métodos de la base de datos admitirán un AccessLevel que le permitirá ejecutar operaciones de la base de datos en modo de usuario. ¡Manténganse al tanto!

Bonificación: si desea ver un ejemplo de uso más avanzado de los Schema , eche un vistazo a CanTheUser en Apex Recipes. Esta clase es una biblioteca que expone métodos fáciles de leer para verificar la seguridad a nivel de campo y objeto.

Para aplicar la seguridad a nivel de registro , debe indicar una cláusula de uso compartido en la definición de la clase Apex . Una clase puede ser with sharing (impone permisos de registro), without sharing (omite intencionalmente los permisos de registro) o inherited sharing (hereda el comportamiento de verificación de seguridad de registro del código de llamada).

 público con clase de uso compartido AccountController { // Contenido de la clase
}

No especificar una cláusula de intercambio es siempre una mala práctica. Omitir la cláusula de uso compartido de una clase y usar el uso inherited sharing refuerza el comportamiento de uso compartido de la clase que llama. Sin embargo, si la clase es el punto de entrada a la transacción de Apex, el inherited sharing pasa a ser más seguro with sharing mientras que el caso omitido tiene el valor predeterminado without sharing . Además, si se omite la cláusula de uso compartido, no estará claro si se espera el comportamiento heredado o si el desarrollador simplemente se olvidó de indicarlo.

Como ha visto, las formas de verificar la seguridad a nivel de campo y de objetos son diferentes de cómo verifica la seguridad a nivel de registro. Este es un concepto erróneo común que me encantaría que los lectores recordaran: ¡ configurar una clase como para compartir no impone permisos de seguridad a nivel de campo o de objeto!

Prevención de amenazas con seguridad de aplicaciones

Seguridad de aplicaciones describe las mejores prácticas a seguir al crear aplicaciones para prevenir amenazas y vulnerabilidades comunes. Anualmente, la organización Open World-Wide Application Security Project ( OWASP ) revisa la lista OWASP Top 10. Este es un informe que describe las 10 vulnerabilidades más críticas que están afectando la seguridad de las aplicaciones web. Estas son las vulnerabilidades enumeradas en OWASP Top 10 para 2021:

A1: 2017-Inyección
A2: Autenticación rota en 2017
A3: Exposición de datos sensibles en 2017
A4: Entidades externas XML 2017 (XXE)
A5: 2017-Control de acceso roto
A6: Configuración incorrecta de seguridad en 2017
A7: XSS de secuencias de comandos entre sitios de 2017
A8: Deserialización insegura en 2017
A9: 2017: uso de componentes con vulnerabilidades conocidas
A10: Registro y monitoreo insuficientes en 2017

Afortunadamente, Salesforce cuenta con protecciones predeterminadas para la mayoría de estas vulnerabilidades, como CSP, Locker Service, Shadow DOM y muchas más. Sin embargo, hay algunos casos extremos, en los que un desarrollador puede abrir involuntariamente la puerta a algunos de ellos. Analicemos algunas de estas situaciones:

Inyección SOQL

La inyección de SQL se produce cuando los datos que no son de confianza se interpretan como parte de una consulta SQL. En Salesforce, tenemos nuestro propio lenguaje de consulta, SOQL.SOQL es similar a SQL , pero una de sus principales diferencias es que SOQL no se puede usar para modificar datos, solo para leer. Como consecuencia, SOQL es intrínsecamente más seguro contra los ataques de inyección SOQL , ya que no modificarán la base de datos. Sin embargo, un ataque de inyección SOQL puede revelar datos confidenciales que el desarrollador no esperaba exponer.

El uso de la sintaxis de consulta SOQL estática en Apex mitiga el riesgo de un ataque de inyección SOQL. Los tokens de consultas estáticas se validan en tiempo de compilación y las variables de Apex vinculadas con ":" se tratan como variables en tiempo de ejecución para garantizar que no se conviertan en elementos ejecutables en la consulta.

 Public static List <Cuenta> getFilteredAccountsStatic (String searchValue) { String likeValue = '%' + searchValue + '%'; // CONSULTA SEGURA :) regreso [ SELECCIONE Nombre, Ingresos anuales, Industria De la cuenta DONDE Nombre COMO: likeValue ORDEN POR Nombre ]; }

Sin embargo, si utiliza consultas dinámicas , es posible que se produzca una inyección SOQL. Piense en el siguiente código:

 Public static List <Cuenta> getFilteredAccountsInjection (String searchValue) { String likeValue = ''% '+ searchValue +'% ''; // ¡¡¡NO HAGAS ESTO !!! return (Lista <Cuenta>) Database.query ( 'SELECCIONAR Nombre, Ingresos anuales, Industria DE la cuenta DONDE Nombre LIKE' + likeValue + 'ORDEN POR Nombre' ); }

Si un atacante consigue pasar un valor como %' AND AnnualRevenue >= 2000000 AND Industry LIKE '% , a la searchValue , podrá recuperar todas las cuentas que AnnualRevenue> = 2000000, revelando información privada.

Para prevenir esto:

  • Utilice consultas estáticas cuando sea posible
  • Si usa consultas dinámicas, vincule los datos que no sean de confianza con ":"
 Public static List <Cuenta> getFilteredAccountsBinding (String searchValue) { String likeValue = '%' + searchValue + '%'; return (Lista <Cuenta>) Database.query ( 'SELECCIONAR Nombre, Ingresos Anuales, Industria DE Cuenta DONDE Nombre COMO: likeValue ORDENAR POR Nombre' ); }
  • Si alguna de estas opciones es posible, escape, encasille (encuentre un ejemplo aquí ) o allowlist (para permitir solo valores identificados) los datos no confiables
 Lista estática pública <Cuenta> getFilteredAccountsEscape (String searchValue) { String likeValue = ''% '+ String.escapeSingleQuotes (searchValue) +'% ''; return (Lista <Cuenta>) Database.query ( 'SELECCIONAR Nombre, Ingresos anuales, Industria DE la cuenta DONDE Nombre LIKE' + likeValue + 'ORDEN POR Nombre' ); }

Secuencias de comandos entre sitios (XSS)

Con Cross-Site Scripting (XSS) , los atacantes pueden inyectar scripts maliciosos en el navegador de la víctima. Esto sucede siempre que una aplicación incluye datos que no son de confianza en la salida que genera sin validarlos o codificarlos. XSS puede provocar el secuestro de sesiones, redireccionamientos maliciosos o simplemente desfigurar la aplicación web.

Locker Service y CSP (Content-Security Policy) son nuestras herramientas para luchar contra XSS en Salesforce. Sin embargo, a pesar de que hacen un gran trabajo, existen algunas mejores prácticas de desarrollo que deben seguirse para no disminuir su eficacia:

  • Manténgase alejado de la manipulación DOM ( lwc:dom="manual" ) cuando sea posible, y use directivas de plantilla en su lugar. ¿Por qué? porque cuando dejas que el marco manipule el DOM, Locker Service desinfecta las entradas antes de renderizar el HTML. Mientras que si lo manipula usted mismo, Locker Service no lo hace. Alternativamente, si necesita usar lwc:dom="manual" , desinfecte las entradas usted mismo. Puede hacerlo aplicando filtrado de entrada (por ejemplo, no permitir > ) o codificación de salida (por ejemplo, transformar > a &lt; ).
  • Evite las funciones de JavaScript que evalúan cadenas como código, como Eval , DOMParser.parseFromString , Document.implementation.createHTMLDocument y setTimeout / setInterval (cuando se utilizan para evaluar una cadena).
  • Evalúe adecuadamente las bibliotecas de terceros, ya que también pueden contener vulnerabilidades XSS. Puedes hacerlo manualmente o usando herramientas automáticas, como CheckMarx o Snyk.

Falsificación de solicitud entre sitios (CSRF)

La falsificación de solicitudes entre sitios (CSRF) obliga a un usuario a ejecutar acciones no deseadas en una aplicación web en la que está autenticado. Imagine que el usuario está autenticado con Salesforce. Con CSRF, un atacante malintencionado podría hacer que el usuario elimine cuentas, cambie una cantidad de oportunidad o algo mucho peor. ¡Y es posible que el usuario que haya iniciado sesión no se dé cuenta de que está ocurriendo! En algunos casos, un ataque CSRF no modifica la base de datos, como cerrar la sesión del usuario. Si bien no es inmediatamente dañino, puede ser molesto.

Salesforce cuenta con protecciones CSRF; esta protección está activada (y no puede desactivarse de forma predeterminada) en el menú Configuración. La protección envía un token con cada solicitud que el servidor valida antes de responder. Esto dificulta la vida del atacante, ya que tendría que averiguar tanto la URL como el token anti-CSRF.

Sin embargo, nuevamente, hay un caso de borde que la protección no cubre. Este es el momento exacto en el que se carga una página. La recomendación en este caso es evitar cambiar el estado de la base de datos al cargar la página. Es decir, no realice operaciones DML en la carga de Lightning Web Components ( constructor, connectedCallback, renderedCallback ).

Exposición de datos sensibles

A veces, necesita trabajar con datos confidenciales en su código, como contraseñas, claves de cifrado, tokens OAuth, información de pago, etc. Este tipo de datos nunca deben codificarse de forma rígida, sino que deben almacenarse correctamente en las aplicaciones. En Salesforce, hay varias funciones que puede utilizar para almacenar secretos de forma segura:

  • Credenciales con nombre : un tipo de metadatos que se utiliza para almacenar información sobre los puntos finales de las llamadas y que se puede hacer referencia fácilmente en Apex. Le permiten configurar la autenticación y mantener los secretos relacionados con la autenticación almacenados de forma segura en Salesforce.
  • Configuraciones personalizadas protegidas : configuraciones personalizadas que pertenecen a un paquete no son visibles en las organizaciones de los suscriptores.
  • Metadatos personalizados protegidos y Registros de metadatos personalizados protegidos : los tipos de metadatos personalizados que pertenecen a un paquete no son visibles para los suscriptores. También tiene la opción de proteger registros de metadatos personalizados individuales en lugar del tipo de metadatos personalizados.
  • Cifrado de plataforma de escudo : una función que le permite cifrar datos en reposo (en la base de datos) para requisitos de cumplimiento de seguridad más estrictos. Como desarrollador, sepa que cuando se utilizan campos encriptados de protección, existen algunas limitaciones de SOQL y SOSL.

Además, si necesita enviar información confidencial fuera de los límites de seguridad de Salesforce, puede cifrar sus datos y descifrarlos en el destino. Hay varias funciones en la clase Apex Crypto que lo ayudarán a implementar diferentes algoritmos para garantizar el secreto, la integridad, la autenticidad y el no repudio de los datos. De manera equivalente, puede encontrar bibliotecas JavaScript como CryptoJS con el mismo propósito y utilidades similares.

Próximos pasos

En esta publicación de blog, hemos cubierto algunas de las mejores prácticas de seguridad que debe seguir al desarrollar en la plataforma Salesforce. Esta no es una lista completa, ya que la seguridad es un tema importante, ¡pero es un buen punto de partida!

Para explicar estos conceptos con más profundidad, he creado una serie de videos. La serie contiene tres episodios de una hora que espero que disfruten. Mira la serie aquí:

Si quiere ponerse manos a la obra, le recomiendo que eche un vistazo a la ruta Desarrollar aplicaciones web seguras en Trailhead. Si desea consultar la documentación completa, consulte la Guía de seguridad de Salesforce .

Sobre el Autor

Alba Rivas trabaja como líder desarrolladora evangelista en Salesforce. Se centra en los componentes web Lightning y la estrategia de adopción de Lightning. Puedes seguirla en Twitter @AlbaSFDC ( http://twitter.com/AlbaSFDC ).

Esta es una traducción realizada por EGA Futura, y este es el link a la publicación original: https://developer.salesforce.com/blogs/2021/07/security-for-salesforce-developers.html

Entradas recomendadas