Docs Menu
Docs Home
/ /
/ / /

Implementando el derecho al borrado con CSFLE

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

El derecho al borrado, también conocido como derecho al olvido, es un derecho que se otorga a las personas en virtud de leyes y normativas como el RGPD. Esto significa que las empresas que almacenan datos personales de una persona deben poder eliminarlos si se les solicita. Dado que los datos pueden estar distribuidos en varios sistemas, puede resultar técnicamente difícil para estas empresas identificarlos y eliminarlos de todas partes. Incluso si se ejerce correctamente, existe el riesgo de que los datos eliminados se restauren a partir de copias de seguridad en el futuro, lo que podría generar 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, imagine que almacena datos de varios usuarios. Empiece por asignar a cada usuario su propia clave de cifrado de datos (DEK) y asignarla a ese cliente.

En el diagrama, el "Usuario A" y el "Usuario B" tienen cada uno su propia DEK única en el almacén de claves. Cada clave se utiliza para cifrar o descifrar los datos de su respectivo usuario:

Un almacén de claves 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 cifrar campos confidenciales en documentos antes de transmitir datos al servidor. Incluso cuando la base de datos utiliza datos en memoria, nunca están en texto plano. La base de datos almacena y transmite datos cifrados que solo 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 cifrado de sobres

Las CMK suelen administrarse mediante un Servicio de Administración de Claves (KMS). CSFLE admite varios KMS, como Amazon Web Services (AWS), Azure Key Vault, Google Cloud Platform (GCP) y almacenes de claves compatibles con el estándar KMIP, como Hashicorp Keyvault. La aplicación de ejemplo utiliza Amazon Web Services como KMS.

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

  • Con el cifrado automático, realiza operaciones de lectura y escritura cifradas según un esquema de cifrado definido, por lo que no necesita código de aplicación para especificar cómo cifrar o descifrar campos.

  • Con el cifrado explícito, utiliza la biblioteca de cifrado del controlador MongoDB para cifrar o descifrar manualmente los campos de su aplicación.

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

Un ejemplo de la interfaz de usuario de destrucción de criptomonedas

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

Luego, 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 ingresar datos como pares clave-valor a través de un formulario de entrada:

Una interfaz de usuario de muestra para agregar datos

La base de datos almacena estos datos en una colección MongoDB llamada “datos”, 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 realiza un bucle sobre ENCRYPTED_FIELDS para cifrarlo:

# 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 los datos, podrás verlos 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 "Eliminar clave de cifrado de datos" elimina la DEK, pero conserva los datos cifrados del usuario. Después, la aplicación ya no puede descifrarlos. Al intentar recuperar los datos del usuario conectado, se produce un error:

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

Nota

Después de eliminar el DEK, la aplicación aún podrá descifrar y mostrar datos hasta que su caché expire, hasta 60 segundos después.

Pero, ¿qué queda realmente 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 haya eliminado realmente los datos del usuario, debido a que la clave de cifrado de datos ya no existe, la aplicación solo puede mostrar el texto cifrado de los campos cifrados "nombre de usuario" y "valor".

Texto cifrado sin procesar de la base de datos de la aplicación de demostración

Aquí está el código utilizado para obtener estos datos. Utiliza una lógica similar a la del método encrypt mostrado anteriormente. La aplicación ejecuta una operación find sin filtros para recuperar todos los datos y luego recorre el diccionario ENCRYPTED_FIELDS para descifrar los 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 puedes usar el shell mongosh para verificar directamente en la base de datos y demostrar que no hay nada legible:

Salida del shell de Mongosh al consultar la base de datos

En este punto, los datos cifrados del usuario siguen 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 se pueden eliminar los datos cifrados, además de la clave de cifrado. Este enfoque de "defensa exhaustiva" ayuda a garantizar que los datos se eliminen por completo. Implementar la destrucción de cifrado 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 borrado.

Volver

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

En esta página