Overview
Puedes usar el driver de Node.js para encriptar campos específicos del documento mediante un conjunto de funcionalidades llamado encriptación en uso. El cifrado en uso permite que tu aplicación cifre los datos antes de enviarlos a MongoDB y consulte documentos con campos cifrados.
Advertencia
MongoDB 8.2 Problema conocido
La versión 8.2.0 de mongocryptd podría no ejecutarse en Windows. Este error afecta el encriptación en uso con el driver si se especifica el argumento --logpath NUL al iniciar mongocryptd.
Para obtener más información sobre este problema y cómo resolverlo, consulta Problemas conocidos en el MongoDB 8.2 notas de versión.
El cifrado en uso impide que los usuarios no autorizados vean datos de texto sin formato mientras se envían a MongoDB o mientras están en una base de datos cifrada. Para habilitar la encriptación en uso en una aplicación y autorizarla a descifrar datos, debe crear claves de cifrado a las que solo su aplicación pueda acceder. Solo las aplicaciones que tienen acceso a tus claves de cifrado pueden acceder a los datos en texto plano descifrados. Si un atacante obtiene acceso a la base de datos, solo puede ver los datos cifrados, ya que no tiene acceso a las claves de cifrado.
Puede que uses cifrado en uso para cifrar los campos de tus documentos de MongoDB que contengan los siguientes tipos de datos sensibles:
Números de tarjetas de crédito
Direcciones
Información de salud
Información financiera
Cualquier otra información sensible o identificable personalmente (PII)
MongoDB ofrece las siguientes funcionalidades para habilitar el cifrado en uso:
Queryable Encryption
Queryable Encryption (QE) es una función de cifrado en uso que permite ejecutar consultas sobre valores de campos cifrados, incluidas consultas de igualdad, rango, prefijo, sufijo y subcadena. La compatibilidad con consultas de rango requiere MongoDB Server 8.0 o posterior. La compatibilidad con consultas de prefijos, sufijos y subcadenas requiere MongoDB Server 9.0 o posterior.
Para obtener más información sobre Queryable Encryption, vea Queryable Encryption en el manual de MongoDB Server.
Encriptación a nivel de campo
El cifrado a nivel de campo del lado del cliente (CSFLE) se introdujo en la versión 4.2 de MongoDB Server y permite buscar la igualdad en campos cifrados. CSFLE difiere de Queryable Encryption en que puedes seleccionar, ya sea un algoritmo de cifrado determinista o aleatorio para cifrar campos. Cuando utilices CSFLE, solo podrás query campos cifrados que utilicen un algoritmo de cifrado determinista. Cuando utiliza un algoritmo de cifrado aleatorio para cifrar campos en CSFLE, pueden ser descifrados, pero no se pueden realizar consultas de igualdad en esos campos. Cuando utilices Queryable Encryption, no podrás especificar el algoritmo de cifrado, pero sí podrás consultar todos los campos cifrados.
Cuando cifras un valor de manera determinista, el mismo valor de entrada produce el mismo valor de salida. Si bien el cifrado determinista te permite realizar consultas en esos campos cifrados, los datos cifrados con baja cardinalidad son susceptibles a la ruptura de códigos mediante el análisis de frecuencia.
Tip
Para obtener más información sobre estos conceptos, consulta las siguientes entradas de Wikipedia:
Para saber más sobre CSFLE, consulte CSFLE en el manual del servidor.
Soporte del pipeline de agregación
A partir de MongoDB Server 8.1, puedes utilizar la etapa de agregación $lookup con clientes configurados para el cifrado en uso. Esta funcionalidad requiere la versión 6.3.0 o posterior del paquete mongodb-client-encryption.
La etapa $lookup permite unir datos relacionados entre colecciones cifradas sin tener que obtener y combinar documentos manualmente en el código de tu aplicación. Tanto la colección de origen como la colección from deben estar configuradas para encriptación en uso. Los campos especificados en localField y foreignField no deben ser campos cifrados.
El siguiente ejemplo muestra una operación de $lookup en una colección cifrada:
const pipeline = [ { $lookup: { from: "encryptedCollection", localField: "userId", foreignField: "_id", as: "userDetails" } } ]; const results = await collection.aggregate(pipeline).toArray();
Enrutar las solicitudes KMS a través de un HTTP proxy
A partir de la versión 7.6 del driver de Node.js, puede enrutar las solicitudes que el driver de Node.js realiza a su sistema de gestión de claves (KMS) a través de un HTTP proxy. Utilice esta funcionalidad cuando su entorno requiera que el tráfico KMS saliente pase a través de un proxy HTTP de reenvío. La configuración proxyOptions solo admite el protocolo SOCKS5 y no cubre este caso.
Para controlar cómo el driver se conecta a un host KMS, establezca la opción kmsConnectCallback en su objeto ClientEncryptionOptions o en su objeto AutoEncryptionOptions. Cuando establezca esta opción, el driver llamará a su función de retorno en lugar de conectarse al host KMS directamente. La función de retorno recibe las siguientes propiedades:
Propiedad | Descripción |
|---|---|
| El nombre de host del host de KMS al que debe llegar el driver. |
| El puerto del host KMS al que debe llegar el driver. |
| El tiempo restante en el presupuesto de tiempo de espera de la operación del lado del cliente (CSOT) de la operación, en milisegundos. Esta propiedad es |
| Un |
El siguiente ejemplo define una función de retorno que abre un túnel al host de KMS mediante el envío de una solicitud HTTP CONNECT a un proxy, y luego pasa la función de retorno a una instancia ClientEncryption:
import * as net from "net"; const kmsConnectCallback = ({ host, port, timeoutMS, signal }) => new Promise((resolve, reject) => { // Opens a plain connection to the proxy, not to the KMS host. // Passing signal lets Node abort the connection attempt when the // driver's timeout budget expires. const socket = net.connect({ host: "proxy.example.com", port: 8080, signal }); // Applies the remaining CSOT budget to the proxy handshake, so that // a proxy that accepts the connection but never answers CONNECT // can't stall the operation. if (timeoutMS !== undefined) { socket.setTimeout(timeoutMS, () => { socket.destroy(); reject(new Error("Timed out waiting for the proxy")); }); } socket.once("error", reject); socket.once("connect", () => { // Asks the proxy to tunnel to the KMS host socket.write( `CONNECT ${host}:${port} HTTP/1.1\r\n` + `Host: ${host}:${port}\r\n\r\n` ); socket.once("data", chunk => { if (chunk.toString("utf8").startsWith("HTTP/1.1 200")) { // Clears the handshake timeout and returns the socket so that // the driver can perform the TLS handshake socket.setTimeout(0); resolve(socket); } else { socket.destroy(); reject(new Error("Proxy refused the CONNECT request")); } }); }); }); const clientEncryption = new ClientEncryption(keyVaultClient, { keyVaultNamespace, kmsProviders, kmsConnectCallback });
La propiedad signal se aplica a la conexión con el proxy y la propiedad timeoutMS se aplica al intercambio CONNECT. Un tiempo de espera de socket permanece activo después de que finaliza el intercambio CONNECT, así que borra el tiempo de espera antes de resolver la promesa. De lo contrario, el tiempo de espera puede destruir el socket mientras el driver realiza el protocolo de enlace TLS.
El ejemplo anterior se condensa para mostrar la secuencia de llamadas. En el código de producción, almacene en búfer la respuesta del proxy hasta que reciba el final del bloque de encabezado, ya que la respuesta puede llegar a través de varios fragmentos.
Importante
Las opciones kmsConnectCallback y proxyOptions son mutuamente excluyentes. Si establece kmsConnectCallback y especifica un valor proxyHost en proxyOptions, el controlador genera un MongoCryptInvalidArgumentError.