Skip to main content

Historia de terror de seguridad: exposición accidental de datos personales

Escrito por
blog feature security alert purple

25 de octubre de 2021

0 minutos de lectura

Nada supera una buena historia de terror... sobre todo cuando se trata de desarrollo de software y seguridad. Es decir, ¿qué podría salir mal al desarrollar software? Y, más importante aún, ¿qué podría salir mal cuando tú y tu equipo trabajan en una pequeña aplicación de I+D y el financiamiento del proyecto aún está pendiente...?

Como podrás imaginar, trabajar bajo una enorme presión para entregar funcionalidades a toda velocidad y asegurar el financiamiento del siguiente periodo es el caldo de cultivo perfecto para un desastre inminente. En especial, si no hay una visión clara del objetivo final del proyecto y las ideas cambian día a día.

Déjame contarte mi historia, en la que las cosas salieron mal desde el punto de vista de la seguridad. Como este pequeño proyecto improvisado de I+D formaba parte de una institución más grande, similar a un banco o una aseguradora, había mucho más en juego que un simple proyecto.

El proyecto

El proyecto comenzó como una aplicación móvil para explorar propiedades inmobiliarias, como edificios y casas. La mayor parte de la lógica del sistema estaba del lado del servidor, así que creamos una excelente solución orientada a (micro)servicios en Java.

Uno de los servicios era el servidor de perfiles. Cada perfil contenía un UUID generado aleatoriamente y una lista de preferencias. Una de las principales funcionalidades permitía que los usuarios usaran la aplicación de forma anónima. Así que almacenábamos el UUID en el almacenamiento local del dispositivo y lo usábamos para recuperar el perfil del servidor. En pocas palabras, el servicio se veía más o menos así.

Diagrama que muestra las solicitudes para crear un perfil, actualizar preferencias y recuperar un perfil mediante UUID, enrutadas a través de un servicio de perfiles hacia los datos del perfil.

En cierto momento surgió la idea de que un usuario pudiera reclamar una propiedad en el sistema. Esto ocurre principalmente cuando el usuario es dueño de la casa o el edificio. Así, el propietario podía mejorar la ficha de la propiedad con fotos y una descripción. Solo un usuario podía reclamar cada propiedad.

Esta nueva funcionalidad implicaba dos cambios importantes para esta historia.

  • Creamos un nuevo servicio llamado “MyHouse” para que un usuario pudiera reclamar una casa.

  • Había que mejorar el servicio de perfiles. Ahora un usuario debía poder iniciar sesión y reclamar una casa. Por eso, mejoramos el servicio de perfiles existente con la opción de registrarse.

Los servicios se veían más o menos así: un objeto MyHouse estaba conectado a un perfil de usuario que contenía el UUID y que ahora también podía incluir una dirección de correo electrónico.

Diagrama que muestra los servicios Profile y MyHouse con sus entradas, salidas y datos asociados de perfil, correo electrónico, preferencias, dirección e imagen.

Es importante señalar que nos indicaron que debíamos seguir admitiendo el uso anónimo, como antes, y que esta funcionalidad debía agregarse a lo que ya teníamos.

El problema

El nuevo servicio MyHouse tenía un endpoint para enumerar todas las propiedades reclamadas. Este exponía el objeto MyHouse completo en formato JSON, incluido el UUID del perfil. Como teníamos que admitir la funcionalidad anterior, todavía era posible encontrar un perfil con solo tener su UUID.

Diagrama que muestra los servicios Profile y MyHouse, con solicitudes de perfil y vivienda asociadas a campos de datos basados en UUID.

En pocas palabras, el frontend móvil no necesitaba el UUID. Sin embargo, si hacías una solicitud HTTP simple y tenías el objeto MyHouse, podías usar el UUID en una segunda llamada para encontrar el perfil. A partir de ahí, era posible relacionar la dirección física de una propiedad con una dirección de correo electrónico. Como en muchos casos las direcciones de correo tienen el formato firstname.lastname@provider.com (o algo parecido), se produjo una filtración de datos: se podía relacionar a una persona con una dirección física. Ups, esto fue una filtración de información de identificación personal, o datos PII.

La solución y lo que vino después

Alguien reportó el problema de forma anónima al departamento de seguridad de la empresa. Por suerte, una persona ética asumió su responsabilidad e hizo una divulgación responsable. Una vez que entendimos el problema, resolverlo tomó cinco minutos, incluido el despliegue en producción. Al agregar la anotación @JsonIgnore al campo UUID del POJO MyHouse, impedimos que el campo se serializara en JSON y eliminamos la conexión entre un perfil y una dirección física.

Desde la perspectiva de ingeniería, podrías terminar aquí la publicación. Sin embargo, aunque solucionar el problema fue fácil, las consecuencias de un incidente así son sumamente invasivas. Todo comenzó con un montón de preguntas sobre el incidente:

  • ¿Quiénes quedaron expuestos?

  • ¿Durante cuánto tiempo estuvo expuesta la información?

  • ¿Qué impacto tuvo esta filtración de datos?

  • ¿Qué tipo de datos se filtraron?

  • ¿Quiénes fueron víctimas de esta filtración?

  • ¿Por qué no lo evitamos?

  • Etcétera, etcétera, etcétera.

Todas estas preguntas implicaron una enorme cantidad de papeleo que mi equipo y yo tuvimos que completar. Algunas respuestas eran obvias, pero, como se trataba de un proyecto de I+D bajo mucha presión, todavía no habíamos implementado un registro adecuado. Era imposible averiguar quiénes habían sido víctimas. Quizás personas malintencionadas ni siquiera aprovecharon la vulnerabilidad. Simplemente no lo sabíamos.

Lo peor fue que la gerencia comenzó a culparnos con comentarios como: “es una pena que nuestros ingenieros no tengan ningún conocimiento de seguridad” o “este equipo es incompetente; deberían haberlo detectado”. Además del enorme papeleo, los gerentes empezaron a supervisarlo todo al detalle, sin tener conocimientos adecuados de desarrollo ni de seguridad.

Lecciones aprendidas

Lo primero que hicimos fue registrar todo. Afrontar un problema de seguridad es una cosa; las consecuencias y las preguntas que vienen después son algo completamente distinto. Luego revisamos detenidamente nuestro modelo de datos para ver si exponíamos en nuestro endpoint REST datos que el frontend no necesitaba.

El equipo de ingeniería también aprovechó este incidente para resistir las altas exigencias y la presión de los gerentes de producto. Sin embargo, crear conciencia sobre la seguridad debería significar integrarla en el proceso de desarrollo, y no culpar a las personas. En mi opinión sincera, la solución adecuada habría sido invertir en la cultura y elegir las herramientas apropiadas para ayudar al proceso de desarrollo. Poco después, decidí dejar la empresa…

¡Síguenos en Twitter (@snyksec) para conocer más historias de terror de seguridad como esta! #31DaysOfSecurity