Join us at MongoDB.local London on 7 May to unlock new possibilities for your data. Use WEB50 to save 50%.
Register now >
Docs Menu
Docs Home
/ /
/ / /

Implementando el Derecho al Olvido con CSFLE

La aplicación de muestra Crypto Shredding demuestra cómo puedes hacer uso de los MongoDB's Cifrado a nivel de campo del lado del cliente (CSFLE) para fortalecer los procedimientos de eliminación de datos confidenciales.

El derecho de supresión, también conocido como el derecho al olvido, es un derecho otorgado a los individuos bajo leyes y regulaciones como el GDPR. Esto significa que las empresas que almacenan los datos personales de un individuo deben ser capaces de eliminarlos a solicitud de este. Debido a que los datos pueden estar dispersos en varios sistemas, puede ser técnicamente complicado para estas empresas identificarlos y removerlos de todos los lugares. Incluso cuando se ejecute correctamente, existe el riesgo de que los datos eliminados puedan restaurarse a partir de copias de seguridad en el futuro, lo que podría crear riesgos legales y financieros.

Advertencia

MongoDB no garantiza que la solución y las técnicas descritas en este artículo cumplan con todos los requisitos regulatorios sobre el derecho de supresión. Su organización debe determinar las medidas adecuadas y suficientes para cumplir con requisitos regulatorios como el RGPD.

La aplicación de ejemplo de Destrucción de Criptomonedas muestra una forma de implementar el derecho de borrado. La aplicación de demostración es una aplicación web en Python (Flask) con una interfaz para añadir usuarios, iniciar sesión e introducir datos. También incluye una página de "Administración" para mostrar la funcionalidad de destrucción de criptomonedas.

Puede instalar y ejecutar la aplicación siguiendo las instrucciones en el Repositorio de GitHub.

El crypto-shredding, también llamado borrado criptográfico, es una técnica de destrucción de datos donde, en lugar de destruir los datos cifrados, se destruyen las claves de cifrado necesarias para descifrarlos. Esto vuelve los datos indescifrables.

Por ejemplo, imagina que estás almacenando datos para varios usuarios. Comienza por asignar a cada usuario su propia llave de cifrado de datos (DEK) única y la asigna a ese cliente.

En el diagrama, “Usuario A” y “Usuario B” tienen su propio DEK único en el almacén de claves. Cada clave se utiliza para cifrar o descifrar datos para su respectivo usuario:

Un almacén de llave de cifrado de datos con dos usuarios

Supongamos que desea eliminar todos los datos del Usuario B. Si elimina su DEK, ya no podrá descifrar sus datos. Todo el contenido del almacén de datos se convierte en texto cifrado indescifrable. Los datos del Usuario A no se ven afectados, ya que su DEK sigue existiendo:

Borrando la llave de cifrado de datos del usuario B

Con CSFLE, las aplicaciones pueden encriptar campos confidenciales en los documentos antes de transmitir los datos al servidor. Incluso cuando la base de datos está utilizando datos en la memoria, nunca están en texto plano. La base de datos almacena y transmite datos cifrados que sólo el cliente puede descifrar.

CSFLE utiliza cifrado de sobre, que es la práctica de cifrar datos de texto simple con una clave de datos, que a su vez está cifrada por una clave de sobre de nivel superior (también conocida como "clave maestra del cliente" o CMK).

Diagrama de encriptación de sobre

Por lo general, los CMK se gestionan mediante un Key Management Service (KMS). CSFLE soporta múltiples KMS, incluidos Amazon Web Services (AWS), Azure Key Vault, Google Cloud Platform (GCP) y almacenes de claves que soportan el estándar KMIP, como Hashicorp Keyvault. La aplicación de muestra utiliza Amazon Web Services como KMS.

CSFLE se puede utilizar en modo automático o explícito, o una combinación de ambos. La aplicación de ejemplo utiliza cifrado explícito.

  • Con el cifrado automático, se realizan operaciones cifradas de lectura y escritura basadas en un esquema de cifrado definido, por lo que no se necesita que el código de la aplicación especifique cómo cifrar o descifrar los campos.

  • Con el cifrado explícito, usa la librería de cifrado del driver de MongoDB para cifrar o descifrar manualmente campos en su aplicación.

La aplicación de ejemplo utiliza CSFLE con cifrado explícito y Amazon Web Services como KMS:

Un ejemplo de la interfaz de usuario del borrado criptográfico

La aplicación crea una instancia de ClientEncryption clase inicializando un objeto app.mongodb_encryption_client. Este cliente de cifrado se encarga de generar las DEK y luego cifrarlas mediante una CMK de AWS KMS.

Cuando un usuario se registra, la aplicación genera un DEK único para ellos usando el método create_data_key, y luego devuelve el data_key_id:

# flaskapp/db_queries.py
@aws_credential_handler
def create_key(userId):
data_key_id = \app.mongodb_encryption_client.create_data_key
(kms_provider, master_key, key_alt_names=[userId])
return data_key_id

La aplicación utiliza este método al guardar la información del usuario:

# flaskapp/user.py
def save(self):
dek_id = db_queries.create_key(self.username)
result = app.mongodb[db_name].user.insert_one(
{
"username": self.username,
"password_hash": self.password_hash,
"dek_id": dek_id,
"createdAt": datetime.now(),
}
)
if result:
self.id = result.inserted_id
return True
else:
return False

Una vez registrado, un usuario puede iniciar sesión e introducir datos como pares clave-valor a través de un formulario de ingreso:

Una interfaz de usuario de muestra para agregar datos

La base de datos almacena estos datos en una colección de MongoDB llamada "data", donde cada documento incluye el nombre de usuario y el par clave-valor:

{
"name": "shoe size",
"value": "10",
"username": "tom"
}

La aplicación de ejemplo cifra los campos value y username, pero no el name. La aplicación cifra los campos con la DEK del usuario y un algoritmo de cifrado específico:

# flaskapp/db_queries.py
# Fields to encrypt, and the algorithm to encrypt them with
ENCRYPTED_FIELDS = {
# Deterministic encryption for username, because we need to search on it
"username": Algorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic,
# Random encryption for value, as we don't need to search on it
"value": Algorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Random,
}

La función insert_data toma un documento no cifrado y recorre los ENCRYPTED_FIELDS para cifrarlos:

# flaskapp/db_queries.py
def insert_data(document):
document["username"] = current_user.username
# Loop over the field names (and associated algorithm) we want to encrypt
for field, algo in ENCRYPTED_FIELDS.items():
# if the field exists in the document, encrypt it
if document.get(field):
document[field] = encrypt_field(document[field], algo)
# Insert document (now with encrypted fields) to the data collection
app.data_collection.insert_one(document)

Si el campo especificado existe en el documento, la función llama a encrypt_field para cifrarlo utilizando el algoritmo especificado:

# flaskapp/db_queries.py
# Encrypt a single field with the given algorithm
@aws_credential_handler
def encrypt_field(field, algorithm):
try:
field = app.mongodb_encryption_client.encrypt(
field,
algorithm,
key_alt_name=current_user.username,
)
return field
except pymongo.errors.EncryptionError as ex:
# Catch this error in case the DEK doesn't exist. Log a warning and
# re-raise the exception
if "not all keys requested were satisfied" in ex._message:
app.logger.warn(
f"Encryption failed: could not find data encryption key for user: {current_user.username}"
)
raise ex

Después de agregar datos, puedes visualizarlos en la aplicación web:

Datos de muestra en la interfaz de usuario

Ahora veamos qué sucede al eliminar la DEK. La aplicación de ejemplo lo hace desde una página de administración, que debería estar restringida solo a quienes tengan autorización para administrar claves:

La página de administración de la aplicación de muestra

La opción "Borrar llave de cifrado de datos" remueve la DEK, pero deja los datos cifrados del usuario en su lugar. Después de eso, la aplicación no podrá descifrar los datos. Intentar recuperar los datos del usuario conectado da error:

Un mensaje de error al intentar recuperar datos cifrados sin una clave

Nota

Después de borrar el DEK, la aplicación aún podría ser capaz de desencriptar y mostrar datos hasta que su caché caduque, hasta 60 segundos después.

Pero, ¿qué es lo que realmente queda en la base de datos? Puedes revisar la información volviendo a la página de administración y haciendo clic en Fetch data for all usersEsta vista no genera una excepción si la aplicación no puede descifrar los datos. En cambio, muestra exactamente lo que está almacenado en la base de datos.

Aunque no hayas borrado los datos del usuario, como la llave de cifrado de datos ya no existe, la aplicación solo puede mostrar el texto cifrado de los campos "username" y "value".

Texto cifrado no procesado de la base de datos de la aplicación demo

Aquí está el código utilizado para obtener estos datos. Utiliza una lógica similar al método encrypt mostrado anteriormente. La aplicación ejecuta una operación find sin ningún filtro para recuperar todos los datos, luego recorre el diccionario ENCRYPTED_FIELDS para descifrar campos:

# flaskapp/db_queries.py
def fetch_all_data_unencrypted(decrypt=False):
results = list(app.data_collection.find())
if decrypt:
for field in ENCRYPTED_FIELDS.keys():
for result in results:
if result.get(field):
result[field], result["encryption_succeeded"] = decrypt_field(result[field])
return results

Se llama a la función decrypt_field para cada campo que se va a descifrar, pero en este caso la aplicación detecta el error si no puede descifrarlo correctamente debido a una DEK faltante:

# flaskapp/db_queries.py
# Try to decrypt a field, returning a tuple of (value, status). This will be
either (decrypted_value, True), or (raw_cipher_text, False) if we
couldn't decrypt
def decrypt_field(field):
try:
# We don't need to pass the DEK or algorithm to decrypt a field
field = app.mongodb_encryption_client.decrypt(field)
return field, True
# Catch this error in case the DEK doesn't exist.
except pymongo.errors.EncryptionError as ex:
if "not all keys requested were satisfied" in ex._message:
app.logger.warn(
"Decryption failed: could not find data encryption key to decrypt the record."
)
# If we can't decrypt due to missing DEK, return the "raw" value.
return field, False
raise ex

También puede usar el shell de mongosh para verificar directamente en la base de datos y comprobar que no hay nada legible:

Salida del shell de Mongosh al consultar la base de datos

En este punto, los datos cifrados del usuario aún están presentes. Alguien podría acceder a ellos restaurando su clave de cifrado, por ejemplo, desde una copia de seguridad de la base de datos.

Para evitarlo, la aplicación de muestra utiliza dos clústeres de bases de datos separados: uno para almacenar datos y otro para almacenar DEKs (el "bóveda de claves"). Utilizar clústeres separados desacopla la restauración de copias de seguridad para los datos de la aplicación y la bóveda de claves. Restaurar el clúster de datos desde una copia de seguridad no restablece ninguna DEK que haya sido eliminada del clúster del almacén de claves.

El cifrado a nivel de campo del lado del cliente simplifica el olvido de ciertos datos. Al eliminar las claves de datos, se pueden olvidar eficazmente los datos existentes en diferentes bases de datos, colecciones, copias de seguridad y registros.

En una aplicación de producción, también puedes borrar los datos cifrados en sí mismos, además de remover la clave de cifrado. Este enfoque de "defensa en profundidad" ayuda a garantizar que los datos estén realmente eliminados. Implementar el borrado criptográfico además de la eliminación de datos minimiza el impacto si una operación de eliminación falla, o no incluye datos que deberían haberse eliminado.

Volver

Utiliza el cifrado automático en el lado del cliente a nivel de campo con KMIP

En esta página