Guía para principiantes sobre el cifrado de datos con NodeJS

Guía para principiantes sobre el cifrado de datos con NodeJS
Guía para principiantes sobre el cifrado de datos con NodeJS

A medida que las aplicaciones web continúan obteniendo acceso a grandes cantidades de datos confidenciales que pertenecen a personas, organizaciones e incluso gobiernos; se presenta ante los creadores de apps, la amenaza de la seguridad de los datos.

Desde los primeros días de la programación, los programadores utilizaron técnicas de cifrado y criptografía para proteger esos datos confidenciales contra las partes malintencionadas.

En la época actual, las técnicas de criptografía tienen un papel crucial, a la hora de poder garantizar la seguridad de los datos de nuestros usuarios.

En el desarrollo web, la criptografía, se utiliza a menudo para proteger los datos mientras se transfieren a través de una red o se almacenan en bases de datos.

La mayoría de las operaciones criptográficas se ejecutan en un servidor web y es por eso, que como desarrolladores de Node JS, siempre se debe comprender como poder cifrar y descifrar los datos.

A continuación, vamos a ojear, las técnicas criptográficas básicas utilizadas para proteger los datos en el desarrollo web y como se pueden implementar con Node.js.

El propio Node JS, proporciona al desarrollador, un módulo integrado llamado criptografía para implementar diferentes tareas.

Antes de nada, debemos ser capaces de comprender qué es exactamente la criptografía (y el cifrado) y comprender como ese cifrado funciona.

¿Qué es la criptografía?

La criptografía no es precisamente algo sencillo. Es toda un área de estudio que se ocupa de las técnicas utilizadas para mantener los datos seguros.

Para lograr este objetivo, principalmente, se convierte un conjunto de datos en «algo» que cualquier persona que no tenga las credenciales necesarias, le será imposible entender.

Algunas técnicas criptográficas, se ocupan de garantizar que ninguna técnica o fórmula externa sea capaz de alterar esos datos.

Existen tres ingredientes principales en un proceso criptográfico: el texto plano, el texto cifrado y un algoritmo.

El algoritmo criptográficos convierte los datos de texto plano en texto cifrado, una forma codificada e irreconocible de los datos iniciales.

El algoritmo, utiliza cálculos matemáticos para esa conversión.

Por lo general, los algoritmos criptográficos utilizan algo llamado clave, a la hora de convertir el texto sin formato en texto cifrado.

El convertir el texto cifrado, de nuevo, a texto sin formato; es posible exclusivamente si obtienes la clave correcta para ello.

Por tanto, quienes tengan el privilegio de poseer la clave, deben almacenarla bajo la máxima seguridad posible y no dejarla caer en manos de extraños.

¿Qué es el cifrado?

Si bien, los términos de cifrado y criptografía, suelen ser usados de forma indistinta. La realidad, es que son dos términos bien diferentes.

El cifrado, es el proceso de convertir texto sin formato en texto cifrado mediante un algoritmo; y es solamente un aspecto de la criptografía.

Lo opuesto del cifrado, el proceso de convertir el texto cifrado a texto sin formato, se denomina descifrado.

En criptografía, podemos encontrar una serie de algoritmos de cifrado que se utilizan para convertir el texto sin formato a texto cifrado.

¿Qué tipos de criptografía existen?

Hay tres tipos básicos de criptografía:

  • Criptografía de clave simétrica.
  • Criptografía de clave asimétrica.
  • Hash.

Bien, ahora, veamos el papel de cada uno de ellos, en el momento de asegurar los datos.

Criptografía de clave simétrica

En la criptografía de clave simétrica, la clave utilizada para convertir texto sin formato en texto cifrado y la clave utilizada para convertir texto cifrado de nuevo en texto sin formato; son las mismas.

Este tipo de criptografía, es simple de implementar y más rápida que su contraparte, la criptografía de clave asimétrica.

Pero la criptografía de clave simétrica, tiene un problema de seguridad importante.

Al cifrar los datos transmitidos a través de una red, este método requiere que tanto el remitente como el receptor tengan en su poder la clave utilizada para el cifrado.

Esto crea un escenario, en el que la clave de cifrado podría verse comprometida por un tercero.

Cuando el remitente y el receptor intentan intercambiar la clave de cifrado a través de una red, un tercero puede tener la posibilidad de robar la clave.

Especialmente, cuando la red de transmisión sea Internet, el riesgo de existir un robo a la hora de intercambiar claves. Es muy alto.

Criptografía de clave asimétrica

La criptografía de clave asimétrica se introdujo para superar los problemas de seguridad de la criptografía de clave simétrica.

La criptografía asimétrica, implementa un par de claves, en lugar de una. Esas claves, son denominadas: Clave pública y clave privada.

  • La clave pública, solo se utiliza para cifrar los datos.
  • La clave privada, solo se usa para descifrar los datos.

Eso quiere decir, que la clave pública, no puede utilizarse en ningún caso; para tratar de descifrar los datos cifrados con ella o viceversa.

La especialidad de este sistema de claves por pares, es que, incluso si la clave pública se comparte entre partes externas que no sean el receptor o el remitente.

No se verá comprometida la seguridad del sistema.

Dado que la clave pública es inútil para el descifrado, robar la clave pública no te abre la posibilidad de leer los datos cifrados, que en todo momento seguirán siendo privados.

Hashing

El hash es diferente de los dos tipos de criptografía anteriores.

La criptografía simétrica y asimétrica facilitan la conversión de texto sin formato a texto cifrado y de nuevo a texto sin formato.

Sin embargo, el hash, solo tiene una opción para convertir el texto sin formato en texto cifrado.

Una vez que el texto sin formato pasa a ser un «hash», no puedes volver a convertirlo para verificar el contenido original.

Lo único que puedes hacer es, verificar si otro texto sin formato genera el mismo valor hash para ver si los dos textos sin formato son iguales.

Esto es posible, porque los algoritmos hash garantizan que cada texto plano único genera un texto cifrado único.

El hash se usa a menudo al almacenar contraseñas.

Las aplicaciones nunca almacenan la contraseña de texto sin formato en sus bases de datos. En cambio, almacenan un hash de la contraseña.

Al autenticar a un usuario, tenemos que comprobar si el hash generado por la contraseña que proporciona un usuario es igual al almacenado en la base de datos.

Si el hash de la contraseña proporcionada, es igual al hash almacenado, entonces el sistema puede autenticar al usuario.

A diferencia de la criptografía simétrica y asimétrica, el hash, no usa una clave durante el proceso de encriptado.

Cifrado con Node.js

Node.js tiene un módulo integrado, denominado crypto, que proporciona funciones para realizar operaciones criptográficas.

Este módulo, incluye un conjunto de envoltorios para las funciones de hash, HMAC, cifrado, descifrado, firma y verificación de OpenSSL.

En esta sección, veremos cómo implementar el cifrado utilizando el módulo de cifrado. Antes de comenzar, debes configurar tu entorno de proyecto Node habitual e instalar el módulo criptográfico utilizando npm.

Cifrar datos con Node.js

Podemos usar la clase Cipher del módulo de cifrado para cifrar datos. Entonces, implementemos la función de encriptación.

javascript
const crypto = require("crypto");

const algorithm = "aes-192-cbc";

const encrypt = (text) => {
  //generate encryption key using the secret.
  crypto.scrypt(process.env.SECRET, 'salt', 24, (err, key) => {
    if (err) throw err;

    //create an initialization vector
    crypto.randomFill(new Uint8Array(16), (err, iv) => {
      if (err) throw err;

      const cipher = crypto.createCipheriv(algorithm, key, iv);

      let encrypted = '';
      cipher.setEncoding('hex');

      cipher.on('data', (chunk) => encrypted += chunk);
      cipher.on('end', () => console.log(encrypted))
      cipher.on('error', (err) => console.log(err))

      cipher.write(text);
      cipher.end();
    });
  });
}

encrypt('hello World');

Al cifrar con el módulo de cifrado, tenemos la opción de generar una nueva clave cada vez que se llama al método de cifrado.

El uso de diferentes claves para el cifrado dificulta que los atacantes descifren los datos mediante la fuerza bruta.

Sin embargo, para generar una clave, usamos una clave secreta común tanto para el cifrado como para el descifrado.

Si la parte que descifra los datos, no tiene acceso a la clave secreta que se utilizó para generar la clave de cifrado, el proceso de descifrado fallará.

El algoritmo de cifrado que hemos utilizado es el algoritmo AES (Advanced Encryption Standard) de 192 bits (24 bytes).

Aquí, los 192 bits indican la longitud de la clave. Puedes ver cómo hemos pasado la longitud de la clave como 24 a la función scrypt que genera la clave.

Al crear un nuevo objeto de cifrado, pasamos un parámetro llamado vector de inicialización (IV).

Por lo general, se agrega al texto cifrado sin pasar por un proceso de cifrado. Se utiliza para evitar repeticiones en el texto cifrado para que los atacantes no puedan descifrar datos identificando patrones en los datos cifrados.

Por lo tanto, las vías siempre deben ser impredecibles y únicas. Por esta razón, esta implementación genera un nuevo IV usando la función randomFill.

Finalmente, el cifrado de datos se realiza mediante la función de escritura.

El objeto de cifrado desencadena el evento de «datos» siempre que un fragmento de datos está disponible en el flujo de datos cifrados y ese fragmento se agrega a la cadena cifrada.

Podemos detectar cuándo finaliza el cifrado activando el evento «fin». Usamos otro evento, «error», para detectar errores arrojados al cifrar el texto.

Descifrando datos con Node.js

Para descifrar datos, usamos la clase Decipher del módulo de cifrado.

Se implementa de manera similar a la forma en que se implementó el cifrado de datos.

Creamos una nueva clave de cifrado usando la clave secreta y luego comenzamos a descifrar el cifrado con la clave.

javascript
const decrypt = (encrypted, iv) => {
  //generate encryption key using secret
  crypto.scrypt(process.env.SECRET, 'salt', 24, (err, key) => {
    if (err) throw err;

    //create decipher object
    const decipher = crypto.createDecipheriv(algorithm, key, iv);

    let decrypted = '';
    decipher.on('readable', () => {
      while (null !== (chunk = decipher.read())) {
        decrypted += chunk.toString('utf8');
      }
    });
    decipher.on('end', () => console.log(decrypted));
    decipher.on('error', (err) => console.log(err))

    decipher.write(encrypted, 'hex');
    decipher.end();
  })
}

Para descifrar el texto cifrado, debe pasar el IV utilizado para cifrar los datos en la función cifrar.

Hashing con Node.js

Implementar una función hash con criptografía en Node JS es bastante simple. Aquí está la función hash que hemos creado.

javascript
const hash = text => {

  const hash = crypto.createHash('sha256');

  hash.on('readable', () => {

    const data = hash.read();
    if (data) {
      console.log(data.toString('hex'));
    }
  });

  hash.write(text);
  hash.end();
}

Sha256 es el algoritmo hash utilizado en esta implementación.

Con este algoritmo, puedes crear fácilmente un texto hash con la función de escritura.

Cuando los datos hash están disponibles en la transmisión, se activa el evento «legible» y podemos recuperar la cadena hash.

ROSEPAC

Redactor Diario Ciberninjas. Curador Digital. 🔗 Telegram 👨‍💻 Twittter 🐦 Discord 🧰