Visibilidad a gran escala: cómo Figma detecta la exposición de datos confidenciales


Resolver los desafíos de seguridad a gran escala requiere tanto creatividad como rigor. Para reducir el riesgo de exposición de datos confidenciales, creamos un muestreo de respuestas: un control sencillo y en tiempo real que supervisa las respuestas salientes, valida el acceso y proporciona un sistema de alerta temprana en todos nuestros productos.
Compartir Visibilidad a gran escala: cómo Figma detecta la exposición de datos confidenciales
Ilustraciones de Jose Flores
Prevenir la exposición de datos confidenciales mediante programación es uno de los desafíos más complejos de la ingeniería de seguridad. La naturaleza de los sistemas modernos y distribuidos implica que los datos pueden viajar por rutas complejas y, en ocasiones, impredecibles, a través de servicios, capas de serialización y contextos en los que su presencia no siempre es evidente. Este tipo de problemas pueden manifestarse de formas sutiles: un terminal que devuelve más datos de los previstos, una ruta de código heredada que omite una verificación de permisos o una validación que falta y que permite a los usuarios ver recursos que no deberían. En términos de seguridad, a menudo se trata de fallas de autorización o de una sobreexposición involuntaria de datos, pequeños errores que pueden tener un impacto desmesurado en la privacidad y la confianza a gran escala.
Para abordar este desafío de frente en Figma, necesitábamos crear un sistema de supervisión que actuara como red de seguridad y como sistema de alerta temprana, detectando las exposiciones en la fase de preparación antes de que llegaran a la producción y continuando con la vigilancia de regresiones inesperadas una vez implementado. Esto significaba crear algo lo suficientemente preciso como para ser confiable y lo suficientemente amplio como para ser valioso en muchos componentes diferentes del producto.
Nos complace compartir nuestra experiencia en la creación del muestreo de respuestas, un sistema diseñado para detectar posibles fugas de datos confidenciales en tiempo real. Al proporcionar una visibilidad continua de los datos que salen de nuestros servicios, el muestreo de respuestas ofrece a nuestros equipos la oportunidad de investigar y resolver problemas rápidamente, lo que reduce el riesgo de exposición y mejora nuestra confianza en la forma en que se gestionan los datos.
Abordamos este problema con una mentalidad centrada en la seguridad de la plataforma, tratando las superficies de nuestras apps como infraestructura y agregando controles continuos de supervisión y detección. Al aplicar técnicas que normalmente se reservan para sistemas de nivel inferior a nuestra capa de aplicación, logramos obtener visibilidad continua de cómo se mueven los datos a través de nuestros productos, sin ralentizar el desarrollo.
Identificación del problema: visibilidad de las exposiciones ocultas
En Figma, nos tomamos muy en serio los permisos y las autorizaciones. A lo largo de los años, hemos invertido en controles preventivos sólidos,como PermissionsV2, nuestro marco de autorización detallado, así como en pruebas continuas mediante pruebas unitarias negativas, pruebas integrales en entornos de prueba y producción, y programas de revisión de seguridad continuos (incluido nuestro programa de recompensa por errores y pruebas de penetración periódicas). Estos sistemas nos transmiten una gran confianza en nuestros límites de acceso y constituyen la base de cómo evitamos la exposición de datos confidenciales.

Obtén más información sobre cómo creamos PermissionsV2.
La exposición de datos confidenciales es una vulnerabilidad de seguridad en la que información confidencial o protegida se pone involuntariamente a disposición de personas que no deberían tener acceso a ella, lo que crea un riesgo de uso indebido o pérdida de confianza.
Sin embargo, las medidas preventivas y las pruebas por sí solas no pueden detectar todos los casos extremos. A medida que nuestros productos e infraestructura se han vuelto más complejos, el riesgo de descuidos sutiles o flujos de datos inesperados ha aumentado de forma natural. Incluso los sistemas bien diseñados pueden dar sorpresas cuando los servicios interactúan de nuevas formas o cuando las rutas existentes se comportan de forma diferente a lo esperado.
Dada la importancia que tiene la protección de datos para Figma, queríamos agregar otra capa de defensa, centrada en la detección y la observabilidad. Nuestro objetivo era crear un sistema que pudiera validar continuamente que nuestros controles preventivos funcionaban según lo previsto y nos ayudara a detectar anomalías de forma temprana, antes de que pudieran afectar la producción.
Para que eso fuera posible, necesitábamos un sistema que pudiera:
- Supervisar continuamente las posibles exposiciones, independientemente del lugar del producto en el que se produjeran.
- Proporcionar insights útiles que nos permitieran solucionar los problemas de forma temprana, idealmente antes de que llegaran a la producción.
- Mantenerse activo en la producción como una capa adicional de defensa para detectar regresiones en tiempo real.
Estos objetivos moldearon los cimientos de nuestro enfoque y guiaron la manera en que equilibramos el alcance de la detección, el impacto en el rendimiento y la mantenibilidad operativa.
Paso 1: creación del muestreo de respuestas para identificadores de archivos
Antes de que pudiéramos detectar la exposición de datos sensibles programáticamente, primero tuvimos que decidir qué se consideraba sensible. No todos los campos de una respuesta API suponen un riesgo, por lo que empezamos con un tipo bien definido: los identificadores de archivos, donde la confidencialidad y las reglas de acceso ya estaban claras. Los identificadores de archivos en Figma son tokens únicos insertados en la URL de cada archivo que lo vinculan a controles de acceso específicos. Dado que son tokens de alta entropía con un conjunto de caracteres conocido y una longitud constante, los identificadores de archivos son fáciles de detectar en flujos de texto. Eso los convirtió en un punto de partida práctico para detectar errores de autorización y crear la infraestructura que más adelante permitiría realizar un muestreo de respuestas más amplio, una vez que se dispusiera de una definición sistemática de los datos confidenciales.

Nuestra implementación inicial se centró en este tipo de datos y en las comprobaciones de permisos asociadas a ellos. La idea era sencilla, pero eficaz: tomar una pequeña muestra de respuestas de servicios clave, buscar identificadores vinculados a archivos y verificar que el usuario solicitante tuviera permiso para acceder a cada valor. El muestreo se realiza de forma aleatoria y uniforme, con una tasa configurable en todas las rutas de solicitud, lo que nos permite controlar la cobertura y limitar la sobrecarga, al tiempo que se obtienen resultados representativos.
Creamos el sistema como middleware en nuestro servidor de aplicaciones Ruby porque proporciona acceso directo al objeto de usuario autenticado, al cuerpo completo de la respuesta API y a nuestro sistema interno de permisos, PermissionsV2. Esto facilita la inspección de los datos de respuesta y la evaluación de los permisos en un solo lugar. Aunque podríamos haber implementado verificaciones similares en una capa proxy, como Envoy, hacerlo habría dificultado considerablemente la evaluación de permisos con conocimiento del contexto del usuario que requiere nuestra arquitectura.
Implementamos el muestreo de respuestas utilizando un bloque after y trabajos asíncronos. El filtro after es un gancho integrado que se ejecuta automáticamente una vez que se completa cada solicitud, lo que nos brinda un punto fijo en el flujo de la solicitud para inspeccionar las respuestas antes de enviarlas de vuelta al cliente. El filtro inspecciona las respuestas elegibles de acuerdo con las tasas de muestreo configuradas y analiza los cuerpos JSON para extraer los identificadores de archivos. Cuando se encuentra un identificador relevante, el sistema pone en cola los trabajos asíncronos para verificar los permisos. Para reducir los falsos positivos, la lógica de verificación aplica reglas que tienen en cuenta los casos seguros conocidos, lo que garantiza que solo se muestren los resultados inesperados para su revisión. Todo esto se realiza sin bloqueos: si el muestreo o la verificación fallan, la solicitud se completa normalmente y los errores se registran para su supervisión.
Un extremo interno permite que otros servicios, como LiveGraph, nuestro servicio de obtención de datos en tiempo real que mantiene sincronizadas las experiencias de colaboración, envíen sus propios datos de muestreo y reutilicen el pipeline de procesamiento. Después de generar una respuesta, LiveGraph realiza una llamada ligera a la API a este extremo, lo que te permite beneficiarte del muestreo de respuestas sin agregar sobrecarga a tu flujo de datos en tiempo real. Para mantener un rendimiento predecible, el muestreo en LiveGraph se controla mediante la configuración y la limitación de la velocidad. Los hallazgos comparten el mismo esquema y la misma ruta de registro que otros servicios, por lo que los resultados se unifican en nuestro almacén de análisis y paneles de control de triaje, lo que facilita a los ingenieros de guardia la interpretación de las alertas, independientemente de su origen.

Obtén más información sobre cómo creamos LiveGraph.
Incorporamos esta lógica directamente en nuestra infraestructura de API, de modo que se pudiera ejecutar tanto en el tráfico de prueba como en el de producción. Las tasas de muestreo se ajustaron para capturar una cobertura suficiente que proporcionara resultados significativos sin introducir una latencia apreciable, y todas las verificaciones se realizaron de forma asíncrona para evitar ralentizar el ciclo de solicitud-respuesta. Además, se estableció una limitación de la tasa para evitar la sobrecarga del pipeline de procesamiento y el consumo excesivo de recursos.
Este enfoque comenzó a revelar inmediatamente insights valiosos. A los pocos días de su implementación, el muestreo de respuestas sacó a la luz casos sutiles en los que se devolvían innecesariamente identificadores relacionados con archivos en determinadas respuestas, lo que dio lugar a un mejor filtrado de datos. También reveló rutas en las que determinados archivos eludían por completo las verificaciones de permisos, lo que nos permitió cerrar esas brechas y reforzar nuestros controles de acceso generales.
El primer paso demostró la viabilidad del concepto, pero su alcance era limitado. Los identificadores de archivos son importantes, pero solo representan una categoría de la información confidencial que debemos proteger.
Paso 2: aumentar la visibilidad con un muestreo de respuestas ampliado
Una vez sentadas las bases, nos propusimos ampliar el alcance del sistema. La implementación inicial demostró que el muestreo de respuestas podía detectar problemas de autorización reales de manera eficiente, pero se limitaba a un solo tipo de datos. El siguiente desafío consistía en ampliar el mismo enfoque a cualquier campo confidencial, es decir, enseñar al sistema a reconocer el significado de “confidencial” en todos nuestros productos.
El muestreo de respuestas ampliado, conocido internamente como "muestreo de respuestas sofisticado", extendió los mismos principios de muestreo a todos los datos confidenciales al integrarse con FigTag, nuestra herramienta interna de categorización de datos.

FigTag funciona anotando cada columna de la base de datos con una categoría que describe su confidencialidad y el uso previsto. Estas anotaciones se almacenan en un esquema central y se propagan a nuestro almacén de datos, por lo que es fácil determinar la confidencialidad de una columna en el momento de la consulta. Una de estas categorías, banned_from_clients, actúa como nuestra señal de confidencialidad, marcando los campos que no deben devolverse en las respuestas API en circunstancias normales (por ejemplo, identificadores relacionados con la seguridad, detalles de facturación y otra información de identificación personal).
Al integrarnos con FigTag, podemos obtener muestras de un subconjunto de respuestas que contienen cualquier campo confidencial, en todos nuestros extremos de la API de nuestro servidor de aplicaciones. Cuando un registro de la base de datos con una columna etiquetada como banned_from_clients se carga en la aplicación (en nuestro caso, a través de un modelo ActiveRecord, la capa de mapeo objeto-relacional utilizada en nuestra aplicación Ruby), una devolución de llamada registra su valor en el almacenamiento local de la solicitud. Para las solicitudes muestreadas, esto garantiza que solo se registren los valores a los que realmente se accede durante la solicitud, evitando una sobrecarga innecesaria.
Una vez generada la respuesta, un filtro after inspecciona el JSON serializado y lo compara con los valores confidenciales registrados. Si aparece algún valor confidencial en la respuesta, se registra un hallazgo. Como antes, los resultados se envían a nuestro almacén de análisis unificado y a nuestros paneles.
También introdujimos un proceso flexible de listas de permitidos, de modo que los extremos con exposición intencionada y segura puedan excluirse del muestreo de respuestas sin sacrificar la detección de datos verdaderamente inesperados. Por ejemplo, un secreto de cliente OAuth podría devolverse intencionalmente desde un extremo de gestión de credenciales dedicado para usuarios autorizados, pero sería un problema grave si se incluyera en respuestas API no relacionadas.
Detección temprana en acción
El sistema ampliado de muestreo de respuestas se ha convertido en una potente capa de detección, que saca a la luz problemas sutiles que habrían sido extremadamente difíciles de detectar solo mediante la revisión del código o el control de calidad manual. Nos ha permitido detectar de forma proactiva los riesgos en la fase de preparación y responder rápidamente a las regresiones de producción. Aquí hay algunos ejemplos:
- Detectamos que un campo de datos que llevaba mucho tiempo sin utilizarse aparecía inesperadamente en ciertas respuestas. El equipo confirmó el hallazgo, lo categorizó y envió una solución específica rápidamente.
- El sistema puso en evidencia casos en los que se incluían datos de recursos relacionados en las respuestas sin una necesidad clara, lo que dio lugar a tareas de limpieza específicas.
- El muestreo de respuestas puso de relieve situaciones en las que se devolvía una lista de recursos en una respuesta sin verificar el acceso a cada elemento individualmente, lo que dio lugar a mejoras en las verificaciones de permisos.
Lecciones aprendidas para equilibrar precisión y rendimiento
La creación de sistemas como este es un esfuerzo conjunto de varios equipos en Figma. Nuestros ingenieros de seguridad envían código junto con los equipos de producto y plataforma, aportando la misma creatividad y rigor a los sistemas de detección que a las funciones orientadas al usuario.
Tras meses de crear y ejecutar el muestreo de respuestas, hemos aprendido mucho sobre los requisitos para crear un sistema de detección programático:
- Piensa siempre en el impacto en el rendimiento: descubrimos que incluso pequeñas cantidades de monitoreo pueden introducir latencia si no se diseñan cuidadosamente. Al ajustar las tasas de muestreo y ejecutar verificaciones de forma asíncrona, mantuvimos el rendimiento para los usuarios y, al mismo tiempo, obtuvimos una visibilidad significativa del tráfico.
- Gestiona los falsos positivos (¡o ellos te gestionarán a ti!): una tasa elevada de falsos positivos puede abrumar a los equipos y reducir la confianza en las alertas. Para abordar este problema, implementamos una lista de permitidos dinámica y flujos de trabajo de triaje rigurosos. Esto significó un filtro rápido de los casos conocidos como seguros y permitió que los ingenieros se concentren en hallazgos realmente riesgosos.
- El contexto importa: no todas las exposiciones de datos confidenciales son igualmente problemáticas. Mediante la configuración dinámica, pudimos ajustar rápidamente las reglas de detección sin necesidad de volver a implementar los servicios. Esto permitió un manejo matizado de los casos de uso legítimos, mientras que se seguían señalando los escenarios anormales o inesperados.
- Crear una defensa por capas: ejecutar el sistema tanto en la fase de prueba como en la de producción nos proporcionó dos líneas de defensa: la detección temprana antes del lanzamiento y la supervisión continua para detectar regresiones. Este enfoque de defensa en profundidad ha sido fundamental para mantener la resiliencia a largo plazo.

El camino a seguir
Con el muestreo de respuestas, hemos aplicado un enfoque de seguridad de plataforma a la seguridad del producto, superponiendo monitoreo y detección continuos sobre nuestras superficies de aplicación para detectar problemas temprano sin ralentizar el desarrollo.
Estamos ampliando este marco para abarcar más servicios y otros puntos de contacto con los usuarios, de modo que podamos identificar la exposición potencial en todos los principales canales de interacción. También tenemos previsto ampliar la cobertura a otras categorías de datos confidenciales, incluidas clases más amplias de información de identificación personal y datos regulados, para garantizar que nuestras capacidades de detección escalen con las necesidades de cumplimiento normativo en constante evolución.
Para mantener la eficacia del muestreo de respuestas a medida que nuestros sistemas crecen, estamos explorando formas de hacerlo más adaptable y detallado. Por ejemplo, estamos investigando controles de muestreo más precisos para equilibrar el uso de recursos con la visibilidad, el triaje automatizado para acelerar las investigaciones y la elaboración de Informes más completos para detectar tendencias a lo largo del tiempo. A medida que ampliamos este marco, nuestro objetivo sigue siendo el mismo: proteger los datos de los usuarios y asegurar que cada experiencia de Figma sea rápida, confiable y segura.
Los equipos de AppSec no suelen adoptar enfoques de seguridad de infraestructura, pero la creación del muestreo de respuestas demostró lo eficaces que pueden ser cuando se aplican en la capa de aplicación. Acercar la detección continua a la capa de aplicación nos ayudó a detectar problemas antes y a responder más rápidamente, un enfoque del que creemos que otros equipos podrían beneficiarse si lo adoptaran.

¡Estamos contratando ingenieros! Obtén más información sobre la vida en Figma, y explora nuestras vacantes.



