Protección de datos estructurados

Introducción

En el primer artículo hablamos sobre las tipologías de datos o información sensible de una forma genérica, y en este segundo, nos centraremos en cómo trabajar o que opciones tenemos con la información estructurada, imaginemos los campos de un CSV o de una tabla de Base de datos, en donde en cada columna tenemos un dato independiente, como la edad, un DNI, un correo electrónico, etc. 

Una vez que tenemos claro cuáles son los datos que queremos o debemos proteger, tenemos que decidir cuál es la mejor forma de hacerlo, para ello de nuevo tenemos que consensuar las necesidades de los consumidores de datos y/o analistas de datos y la de los responsables de la seguridad de los mismos, esto nos llevará a que cuanto mayor sean las necesidades de los analistas de datos más complejas y por ende más costosas (y no sólo en dinero) serán las soluciones que será necesario aplicar sobre nuestros datos.

Opciones de ocultación

Existen varias opciones para ello como el enmascaramiento, el hashing, etc., los cuales exponemos a modo resumen en la siguiente tabla, sin duda existen más opciones, pero aquí incluimos las más usadas:

Opciones de ocultación de Datos Estructurados

Pero, ¿cuándo interesa más el uso de unas opciones sobre otras?, para ello partiremos de varios supuestos, en donde iremos de menor necesidad de datos sensibles a más restrictivos, e iremos aplicando estas técnicas mostradas entrando más en detalle en cada una de ellas, obviamente podemos mezclar alguna de ellas o aplicarlas en otros supuestos, pero baste como ejemplos de su uso.

No se necesitarán nunca los datos

En este caso, asumimos que los datos sensibles no son necesarios para el proceso de análisis que se necesita realizar, por ello lo mejor es no cargarlos en el sistema, repositorio, DataLake, etc...

En este caso supongamos el entrenamiento de un modelo de Machine Learning, para identificar el precio de viviendas en función de diversas características, normalmente en estos casos los datos del propietario de la vivienda no serán necesarios, por lo que no tiene sentido el cargarlos y menos aún usarlos en nuestro entrenamiento, o en su defecto subirlos con un valor genérico en su lugar como por ejemplo un “*”. 

Se necesitan los datos sólo en Visualización

En este caso tenemos que los datos personales no son necesarios en fase de cálculo, pero posteriormente en la visualización si deberemos mostrarlos.

 Imaginemos un proceso en el que realizamos un Dashboard. Para los cálculos del modelo BI (ya sea estrella o copo de nieve) no necesitamos los datos sensibles, pero de cara a la visualización si debemos usar o mostrar los datos reales.

Para ello una opción es la de división de tablas, Split Tables, Look-Up tables, etc. ya que esta técnica puede adoptar diferentes nombres, pero al final es el mismo concepto.

En el caso más simple, a partir de la tabla origen que contiene todos los datos (sensibles y no sensibles) y durante la fase de carga, se divide en 2 entidades, enlazándolas o relacionándolas por un identificador o ID único:

  • Por un lado, tendremos la tabla con datos no sensibles que se almacena en un repositorio normal, con unas restricciones de seguridad más bajas, ya que no es información sensible. 
  • Por otro, los datos de carácter personal se almacenan en otra tabla, fichero, etc. que puede estar en el mismo repositorio o en otro diferente, pero en este caso el acceso a estos datos estará mucho más restringido y securizado.
Visualización de Datos Estructurados

Normalmente el ID, debe ser único, y no conviene que sea consecutivo o un secuencial, ya que si alguien consigue acceso, con pasar el ID, accederá a los datos, pero si usamos un identificador más o menos aleatorio, o algún valor Hasheado, podremos dar un nivel mayor de seguridad, una buena opción, es el generar un UUID (Universally Unique IDentifier) para asegurarnos que el valor es único y aleatorio, y cada vez que quieran recuperar un dato personal, se debe pasar ese código (ya sea el UUID o un hash del UUID).

De esta forma se trabaja de forma normal con la información no sensible, y si posteriormente en visualización se necesitan los datos, podremos acceder al segundo repositorio, y a través del identificador recuperar los datos sensibles para que los use el destinatario autorizado. 

En caso de que queramos proporcionar un mayor nivel de seguridad u ocultación de los datos, podremos aplicar o incluir otras técnicas como las que veremos en los siguientes ejemplos. 

En casos más complejos, en donde tengamos N tablas con datos sensibles, podemos realizar este proceso de división y tener N tablas genéricas y N sensibles, o unificar parcial o totalmente los datos sensibles y así tener menos tablas en la partición de datos securizados.

Se necesitan los datos, pero no necesitamos ocultar en almacenamiento, pero si en visualización

En este caso, los datos son almacenado en abierto, pero a la hora de mostrarse a los usuarios, ejecutamos un proceso de masking o enmascaramiento, en donde sustituimos partes del contenido del dato por una serie de valores fijos, como por ejemplo suele ocurrir con las tarjetas de crédito en donde solo se dejan visibles los últimos dígitos, y el resto son asteriscos:

Num. Tarjeta: **************54

Esta opción se puede realizar desde la mayoría de los servicios de bases de datos de Azure (SQLDatabase, SQL Server, Synapse) y se denomina “Dynamic Data Masking”.

Dynamic Data Masking

Es importante notar aquí que el enmascaramiento sólo afecta a la visualización, las queries se ejecutan sin este enmascaramiento, en este ejemplo de la documentación se ve claramente que con la query filtra por salario, aunque luego enmascare con el valor que sea.

Queries en Datos Estructurados

Se necesitan los datos, pero podemos permitirnos generalizar algunos

En este caso nos encontramos con que tenemos ciertos datos, que, si bien son sensibles, no podemos permitirnos el lujo de modificarlos porque son necesarios para ciertos cálculos, pero sí podemos aplicar sobre ellos un proceso de generalización o agrupamiento de datos para anonimizarlos parcialmente. Imaginemos por ejemplo una tabla en donde tenemos los datos personales de algunos usuarios, entre ellos su edad y el salario, los cuales son necesarios para nuestro modelo, pero podríamos agruparlos o generalizarlos para en cierto modo reducir la exposición de dicho dato sensible:

Generalización de Datos Estructurados

Se necesitan los datos, pero no su reversibilidad

Dentro de este grupo nos encontramos con que normalmente lo que necesitamos, más que el dato en sí mismo, es la agrupación o la distribución que dicho dato genera en nuestro dataset, como por ejemplo un email, un número de la seguridad social, etc. En este caso, el dato en si no aporta mucho más allá de indicarnos a quién pertenece, y por lo tanto permitirnos el mantener ese dato como campo clave para esa agrupación, conteos, sumas, etc. pero en ningún momento necesitaremos saber cuál es ese correo electrónico.

Supongamos por ejemplo una visualización de datos de una empresa, en donde debemos agrupar la información por un campo clave que sea el correo electrónico, pero luego a la hora de visualizarlos, nunca lo haremos en función de esos datos, sino que lo haremos con un nivel de granularidad superior como por ejemplo la ciudad, el departamento, etc. al que pertenece ese usuario. En este caso, necesitamos que la función de transformación de este dato sea univoca y unidireccional, es decir, que de A siempre obtengamos B, pero no necesitamos saber que B viene de A.
 

Función de Datos Estructurados

En este caso, podemos aplicar alguna función de codificación de tipo HASH o proceso de Hashing, la cual asegura que a partir del mismo dato de entrada obtenemos siempre el mismo resultado, pero no podemos volver hacia atrás. 

Hash Encoder Datos Estructurados

Por ejemplo, en este caso he generado la tabla hash de 3 valores distintos aplicando tres algoritmos diferentes:

Tabla Hash de Datos Estructurados

Como vemos, en función del algoritmo empleado, la longitud del resultado será diferente, esto tiene varias implicaciones.

  • A mayor longitud, tendremos mayor seguridad, y confiabilidad de que será complicado volver atrás y obtener el valor de origen.
  • A mayor longitud, reducimos la posibilidad de tener colisiones, es decir, que, para dos valores distintos de entrada, el resultado de la función hash sea el mismo. Lo cual implicaría que dos números de la seguridad social diferentes serían tratados como si fueran de la misma persona, y esto distorsionaría nuestros resultados.
Hash Encoder de Datos Estructurados
  • Como contrapartida tenemos que tener en cuenta que a mayor longitud, será necesario más espacio y tiempo de procesamiento durante su explotación, si pensamos por ejemplo en la visualización de los datos en una herramienta de BI debemos tener en cuenta que estos son valores largos normalmente de tipo String, y este no es un formato óptimo, ya sea para realizar agrupaciones, conteos, etc., por ello se debe evaluar si es interesante el convertir este campo en una nueva dimensión para mejorar el rendimiento general del Dashboard.

Esta solución, como hemos visto nos ofrece una importante seguridad, ya que no son reversibles, pero se debe tener en cuenta que para algunos casos o tipologías de datos como por ejemplo número de seguridad social, teléfonos, etc.

De longitud fija y conocida existen las conocidas “Rainbow Tables” que son tablas precalculadas en donde tenemos los resultados del Hashing para esas tipologías de datos, con lo que la vuelta atrás por la fuerza bruta es posible, es decir, si yo en un dataset robado, sabría que el valor “b1017ab1177d72528be39841a24e2f9f459b2b36” es de tipo sha1 y corresponde al valor “2222222222”.

Se necesitan los datos, y que sean reversibles

En este caso, necesitamos que los datos sensibles estén protegidos, no sean accesibles, pero en algún momento dado, necesitaremos volver a recuperar el data original, ya sea para mostrarlos en una visualización de un Dashboard, como resultado tras pasarlo por un modelo de ML, etc.

Para ello tenemos 2 opciones, por un lado, la encriptación de los datos o por otro el de la tokenización de los mismos usando un sistema externo que nos ayude.

Encriptación

Esta es la opción más clásica, en donde los valores son transformados (Encriptados) para que no se conozca el contenido y se puedan enviar por un canal inseguro, y posteriormente son vueltos a transformar en destino para conseguir el dato en claro usando una clave, que podrá ser la misma que se usó para la encriptación (Cifrado simétrico) u otra diferente pero relacionada matemáticamente con la primera (cifrados asimétrico).

Encriptación de Datos Estructurados

Para conseguir esto existen multitud de algoritmos, pero los más comunes son los de clave pública usando certificados digitales, o en caso de necesitar mantener el formato/características del dato están las encriptaciones “Format Preserving Encryption” para mantener la tipología y longitud en BBDD o en la herramienta de visualización.

Si entramos en cómo trabajar con ello en Cloud, normalmente los datos suelen estar cifrados tanto en tránsito como en reposo, es decir cuando viajan (entran o salen del cloud) o cuando están almacenados, pero esta encriptación normalmente no es suficiente cuando hablamos de protección de datos sensibles, ya que esto nos ayuda a que si alguien accede a los datos en bruto (Roba un bloque de datos) no pueda leerlos, pero si tiene acceso a ellos como si fuera un usuario legal, verá todos los datos, ya que este método no es selectivo.

Por ello si necesitamos ocultar o anonimizar un dato específico, deberemos hacerlo o forzarlo personalmente a través de un código específico que desarrollemos o alguna herramienta, en donde podemos seleccionar por objeto/fichero/tabla o incluso llegar a nivel de campo/columna, fila o incluso celda, y que nos permita posteriormente, el desencriptar ese campo en concreto si estamos en posesión de la clave.

En el siguiente ejemplo, vamos a encriptar una columna especifica usando un cifrado simétrico y luego la desencriptaremos, para ver que el resultado es el mismo.
 

Encriptación de Datos Estructurados

En este caso vemos en verde la columna encriptada, y hemos escrito en el fichero “clave.key” la clave necesaria para desencriptar que podremos usar en el proceso que necesite los datos en claro.

Clave Key Datos Estructurados

Una vez que queremos desencriptar esta columna, debemos leer el fichero con la clave y aplicarla sobre la columna encriptada:

Desencriptado de Datos Estructurados

Esto obviamente es válido cuando estamos trabajando con código, en donde tenemos más capacidad o margen de maniobra en las acciones que realizamos, pero que pasa si por ejemplo necesitamos que nuestros datos estén almacenados en una BB.DD. tipo SQL Server, y queremos que, dependiendo del usuario, recupere el dato encriptado, o desencriptado, para ello deberemos trabajar con las opciones que nos proporcione el sistema con el que trabajemos…

Por ejemplo, si trabajamos con la familia Microsoft, tenemos varias opciones:

Si lo hacemos con SQL Server en cualquiera de sus sabores, es decir, On-Premises, Azure SQL Managed Instance o SQL Database, o con CosmosDB, tenemos la opción de Always Encrypted, la cual nos permite encriptar la información de ciertas columnas, de forma que solo aquellos usuarios que tengan permitido la desencriptación de esas columnas podrán ver esos datos en claro, es decir, los administradores o usuarios sin ese permiso específico, no podrán ver el valor real, ya que la encriptación y desencriptación se hace en el Driver del cliente, no en el servidor, aunque debemos tener en cuenta que esto afectará al rendimiento de todas las consultas realizadas contra la BB.DD. 
 

SQL y DataBase Engine

En los siguientes enlaces tenéis más información sobre esta característica:

https://docs.microsoft.com/es-es/azure/azure-sql/database/always-encrypted-landing
https://docs.microsoft.com/es-es/azure/cosmos-db/how-to-always-encrypted

En caso de que estemos trabajando con Synapse, podremos hacerlo a través de la opción de cifrado simétrico mediante Transact-SQL, ya que no tenemos la opción del Always Encrypted, esta opción, también es viable con la familia de SQL Server.

https://docs.microsoft.com/es-es/sql/relational-databases/security/encryption/encrypt-a-column-of-data

En caso de estar trabajando en alguna otra base de datos (Oracle, MySQL, PostgreSQL, etc.), se deberá evaluar si existe alguna opción similar en el servicio, y si no, deberá ser la propia aplicación la que se encargue de cifrar antes de insertar en la BB.DD. y descifrar al leer de ella.

Tokenización

Otra forma de ofuscar la información, consiste en el de Tokenizar los datos, es decir, sustituir el valor sensible (total o parcialmente) por un identificador o token en cierto modo aleatorio, manteniendo a ser posible la tipología y la longitud, pero que por otro lado no tenga ninguna relación con el dato al que sustituye, siendo este con el que trabajamos, y si posteriormente necesitamos recuperar el valor original mediante el uso de funciones específicas, se solicite al generador de estos tokens.

Como ejemplos podríamos tener:

  • En un correo electrónico sustituirlo entero o sólo el nombre de usuario, dejando el dominio intacto asdfasdsdfsdff@nttdata.com
  • En las tarjetas de crédito la sustitución completa o dejar los últimos dígitos sdfsdfgsdd2568

Esto normalmente se pude realizar internamente en la empresa implementando nuestro propio servicio de tokenización, esto tiene la ventaja de que el coste será mucho menor, pero también tiene sus riesgos, ya que no tendremos tanto conocimiento y expertise como si lo hacemos con una empresa especializada que disponen de herramientas de mercado específicas para este tipo de servicios como por ejemplo SecuPi, Protegrity, Tokenex, etc. de los que NTT DATA somos partners.

De forma genérica, existen 2 tipologías de tokenización de datos:

Tokenization Vault

En este caso las relaciones entre los datos originales y los tokens son almacenados en una Base de datos.

Tokenización Vault en Datos Estructurados
  1. Se recuperan los datos en claro
  2. Se cambian los valores sensibles por los tokens, y se almacenan en la base de datos de tokens las equivalencias.
  3. Se almacenan en el repositorio los datos con la información sensible anonimizada.
  4. En caso de necesitarse su consumo, se recuperan los datos
  5. Se cambian los tokens por su valor en claro
  6. Se muestra a los usuarios el valor real

Este formato nos asegura que los datos estarán correctamente anonimizados, pero debemos tener en cuenta, que tendremos que asegurarnos completamente de la confiabilidad del sistema Tokenizador, ya que en él tendremos toda nuestra información sensible.

Así mismo estos sistemas son sensibles al volumen de datos, y podemos llegar a tener problemas de rendimiento cuando el volumen de datos anonimizados sea muy alto.

Vaultless Tokenization

En este caso el sistema Tokenizador se basa en la misma idea que el proceso anterior, pero en este caso no tiene una base de datos en donde almacenar la información, y por tanto no tiene el punto de penalización en el rendimiento, si no que tiene por debajo un sistema de encriptación de los datos (FPE: format-preserving encryption), o unas lookup tables que hace que la vuelta atrás sea muy rápida. 

Conclusión

En esta segunda parte, ya sí hemos visto cosas más interesantes, viendo que alternativas tenemos para trabajar con datos estructurados, pero por desgracia, la mayoría de los datos que se manejan hoy en día, vienen de fuentes no estructuradas, como texto, video, etc. por ello en el siguiente post y como cierre, nos centraremos en ver que opciones tenemos para trabajar con esta tipología de información.

 

 

 

He leído y acepto la política de privacidad
Acepto recibir emails sobre actividades de recruiting NTT DATA