Esquema de seguridad del control de cordura, ¿es seguro? ¿Hay crucero?

-1

Este artículo: La vida en un mundo posterior a la base de datos: usar crypto para evitar las escrituras DB

Me pidió que escribiera este url-crypt módulo Node.js para convertir un Secreto en cadenas seguras de la base64 de urlsafe.

Piense en un enlace de verificación de correo electrónico que no necesite almacenar sus datos en la base de datos. O bien, un token JWT cuyas reclamaciones son secretas en lugar de base64.

La idea es cifrar y almacenar una cantidad razonable de datos (< 512 caracteres) en < 2k caracteres de base64 (una URL) para que pueda ser descifrado más tarde.

Publiqué esto en npm y luego pensé. ¿Es seguro? La inseguridad sería inútil para otros: - /

Cómo funciona:

var urlCrypt = require('url-crypt')('super-secret-key');

var data = { hello: 'world', this: 'is a test', of: 'url-crypt' };
var base64 = urlCrypt.cryptObj(data);
var backAgain = urlCrypt.decryptObj(base64);
expect(backAgain).to.eql(data);

Lo que hace: urlCrypt.cryptObj(obj) :

  • Convierte obj a JSON
  • Gzips el JSON
  • Crea 30 bytes de sal
  • Encripta [salt] [gzip] con aes-256-cbc y un pbkdf2 de clave
  • Convierte a base64

Y de vuelta.

El código es 2 funciones, todo un archivo.

Algunas preguntas específicas:

  1. Aquí agrega algo de jitter como protección contra los ataques de diccionario. ¿Esto lo hace más fuerte?

  2. Aquí usa pbkdf2 para hacer la clave aes. La sal es constante. ¿El pbkdf2 de esta manera lo hace más fuerte? Añadir un parámetro de configuración de sal parece simplemente hacer una clave más larga.

  3. Aquí pone algunos datos aleatorios frente al datos reales Si supiera los datos reales ({email: "[email protected]"}) pensé que sería más fácil adivinar el secreto. Este dato aleatorio es para proteger contra eso. ¿Ayuda esta sal?

  4. Aquí repite el aes-256- cbs. ¿Esto es útil? La repetición hace que el token de finalización sea más largo (lo que hace que haya menos datos en la URL), ¿es esto extraño?

  5. ¿Cuál es la mejor manera de hacer que la computación sea más difícil, sin alargar el token?

  6. ¿Hay alguna manera de mejorar esto? O cualquier complejidad que pueda eliminarse.

Gracias! Es mi primer módulo centrado en la seguridad, así que quería que se revisara la cordura.

    
pregunta Michael Cole 21.02.2015 - 08:35
fuente

1 respuesta

2

Hay varias cuestiones fundamentales.

En primer lugar, no inventes tus propios protocolos de seguridad, especialmente cuando eres un lego. Sé que esto se ha dicho cientos de veces antes, sé que todos estamos cansados de escucharlo, pero es una regla muy importante. Si realmente considera utilizar su código en producción (lo que parece ser el caso), ya está cometiendo un gran error.

En segundo lugar, la premisa es defectuosa. En el artículo, este enfoque se comercializa como una alternativa fácil y liviana para almacenar datos en una base de datos. Pero no es ni fácil ni ligero. Hacer que la criptografía sea correcta es extremadamente difícil, requiere conocimiento experto y trabajo duro. Por otro lado, la configuración de una base de datos es una cuestión de unos pocos minutos y puede ser realizada por cualquier persona con conocimientos básicos de SQL. En algunos casos especiales, podría obtener un beneficio de rendimiento al evitar una base de datos del lado del servidor, pero esto debe medirse en la aplicación concreta y compararse con las desventajas. No veo ninguna indicación de que realmente hayas hecho esto.

En tercer lugar, hay cuestiones conceptuales. Habla de secretos y cifrado, pero parece que lo que realmente desea es autenticación e integridad, es decir, debe asegurarse de que los datos de la URL provengan de usted y no hayan sido manipulados. El cifrado generalmente no impide la manipulación, solo proporciona confidencialidad (no veo por qué necesitaría eso en su caso). Si desea las tres propiedades al mismo tiempo, las cosas se vuelven aún más complejas. Ahora necesita modos de cifrado avanzados como el modo de contador de Galois de AES que pueden o no ser compatibles con su entorno. Se recomienda no crear su propia combinación de cifrado / MAC. Incluso los grandes proyectos de software lo han estropeado, por lo que, como un solo programador sin antecedentes criptográficos, las posibilidades de cometer un error son enormes.

Tampoco ha pensado en el problema de revocar un token. ¿Qué pasa si descubres que un token ha sido comprometido? ¿Qué pasa si un usuario le pide que lo cancele inmediatamente? Ya que no tienes control sobre las fichas una vez que las has emitido, esto no es posible. Todo lo que puede hacer es esperar a que el token caduque, pero esto no es una opción. Por lo tanto, es probable que necesite una base de datos del lado del servidor de algún tipo, en cuyo punto todo el ejercicio se vuelve inútil.

Por último, pero no menos importante, hay muchos problemas técnicos en su código:

  • Usar una sal constante es simplemente incorrecto (como ya se ha dicho). Ni siquiera me queda claro por qué querría usar una clave basada en contraseña en lugar de una clave puramente aleatoria.
  • No hay un vector de inicialización aleatorio, que de nuevo es un defecto fatal. NodeJS intenta obtener un IV del material clave, pero como su sal PBKDF2 es constante, el IV también es constante.
  • Estás usando los métodos incorrectos. Si lees el manual , verás que el método crypto.createCipher() realmente espera una contraseña , no una llave. A continuación, deriva una clave y un vector de inicialización a partir de esta contraseña (utilizando un algoritmo bastante débil). Para cifrar los datos con una clave personalizada, se usa crypto.createCipheriv() .
  • No, agregar datos de basura o lanzar un montón de repeticiones no ayuda. Hacer cosas aleatorias con la esperanza de que aumente la seguridad generalmente no es útil para la criptografía.
respondido por el Fleche 21.02.2015 - 13:10
fuente

Lea otras preguntas en las etiquetas