Node: Utilice el generador aleatorio del sistema en cripto

Creado en 19 mar. 2016  ·  152Comentarios  ·  Fuente: nodejs/node

randomBytes usa OpenSSL como su generador de números aleatorios. Sería más inteligente y menos propenso a

crypto revisit later security

Comentario más útil

@bnoordhuis Tratar de encontrar razones específicas para explicar posibles problemas no es un buen enfoque para los asuntos relacionados con la seguridad. Los problemas existen y no hay forma de predecir cómo evolucionará Node; por ejemplo, si la seguridad de la bifurcación podría comenzar a importar debido a cambios futuros, en ese momento la gente probablemente se habrá olvidado de este problema específico.

Deberíamos esforzarnos por lograr una implementación óptimamente segura (dentro de las limitaciones técnicas), en lugar de intentar "defender" la implementación actual cuando hay casos extremos / problemas conocidos con ella.

Esta publicación aborda eso más allá.

Todos 152 comentarios

En lugar de vincular a una publicación de blog, resuma los pros y los contras aquí.

Quizás @ joepie91 o @ paragonie-scott estarían interesados ​​en explicarlo aquí.

De "una publicación de blog":

¿Por qué no {SecureRandom, OpenSSL, havaged, & c}?

Estos son CSPRNG de espacio de usuario. Quiere usar el CSPRNG del kernel porque:

  • El kernel tiene acceso a la entropía del dispositivo sin procesar.
  • Puede prometer no compartir el mismo estado entre aplicaciones.
  • Un buen CSPRNG de kernel, como el de FreeBSD, también puede prometer que no le proporcionará datos aleatorios antes de que sea sembrado.

Además, el espacio de usuario PRNG de OpenSSL ha causado problemas en otros idiomas (PHP bajo Apache seguro) porque no es seguro para la bifurcación, lo que provocó que se repitieran números aleatorios. (Combine esto con las consecuencias de la reutilización de nonce para la mayoría de los cifrados de flujo y _boom_ su criptosistema pierde toda la privacidad).

Una apuesta más segura sería adoptar lo que hace random_bytes() PHP 7:
https://github.com/php/php-src/blob/e8f056e535813bf864743626c3a208ceafee70b9/ext/standard/random.c#L83 -L186

El PRNG de OpenSSL se genera desde / dev / {, s, u} aleatoriamente, puede obtener entropía de demonios recolectores de entropía, y la bifurcación no es un problema para node.js. Hasta ahora no veo una razón convincente para cambiar.

@ paragonie-scott Eso no parece un buen razonamiento. ¿Podrías estar más tranquilo? ;-)

@bnoordhuis Tratar de encontrar razones específicas para explicar posibles problemas no es un buen enfoque para los asuntos relacionados con la seguridad. Los problemas existen y no hay forma de predecir cómo evolucionará Node; por ejemplo, si la seguridad de la bifurcación podría comenzar a importar debido a cambios futuros, en ese momento la gente probablemente se habrá olvidado de este problema específico.

Deberíamos esforzarnos por lograr una implementación óptimamente segura (dentro de las limitaciones técnicas), en lugar de intentar "defender" la implementación actual cuando hay casos extremos / problemas conocidos con ella.

Esta publicación aborda eso más allá.

Todavía no tengo una opinión firme sobre esto. Llamé a @ joepie91 y @ paragonie-scott aquí porque expresaron consideraciones similares a las de @speakeasypuncture en un chat de IRC anteriormente.

@bnoordhuis , según entiendo sus puntos, las razones aquí son:

  1. El sistema PRNG es bueno para esto, se sabe que es estable y no ha causado muchos problemas de seguridad.
  2. Agregar un PRNG de espacio de usuario superior a eso no lo hace más seguro, pero lo hace más propenso a errores.
  3. OpenSSL no es en realidad un producto de muy alta calidad de código.
  4. El uso de OpenSSL PRNG causó serios problemas de seguridad para algunos proyectos, a saber, para Debian, Android y PHP (este último aún no se ha solucionado, por cierto), aunque eso fue principalmente culpa suya. Esos problemas no se aplican directamente a Node.js, pero esto da una sensación de inquietud.
  5. No parece haber ninguna razón _no_ para deshacerse de OpenSSL PRNG y reducir los posibles errores.

Todos, ¿me perdí de algo?

Nuevamente: todavía no tengo una opinión firme sobre esto.

Me gustaría escuchar cuáles serían los inconvenientes de este cambio, y hay algo donde (o por qué) OpenSSL PRNG podría ser mejor que el sistema PRNG.
Excluyendo el hecho de que ya se usa, por supuesto, ese tampoco es un argumento lo suficientemente bueno, ni siquiera será un cambio semi-importante. No está documentado que crypto.randomBytes() use OpenSSL.

/ cc @ nodejs / crypto.

@mscdex No estoy seguro de si se trata de una «solicitud de función», me parece una propuesta para cambiar la implementación de crypto.randomBytes() .

@ChALkeR Tu resumen me parece correcto.

Además, los generadores de números aleatorios son intercambiables en caliente sin problemas de compatibilidad, solo problemas de seguridad.

Estoy -1 en esto, no hay razones convincentes para mí.

@indutny Por favor, consulte este comentario en particular, además de varios otros en el hilo. Hay una falta de razones _no_ para hacer esto (en la medida en que alguien las haya expresado), mientras que hay razones documentadas para hacerlo.

Si cree que hay una razón _no_ para hacerlo, por favor compártala, pero "no hay razones convincentes para mí" realmente no es un argumento suficiente para un asunto relacionado con la seguridad. Incluso un pequeño defecto puede tener consecuencias desastrosas.

@ joepie91 seguro, lo siento por una respuesta demasiado corta.

¿Qué pasa con los sistemas con PRNG "bueno"? Cuantos de ellos hay? ¿Tenemos que llevar ambas implementaciones para soportarlas?

@indutny Gracias por la elaboración.

Según tengo entendido (y corríjame si no es así), OpenSSL depende del sistema PRNG para empezar. No conozco ninguna plataforma (de las que admite Node, es decir) donde OpenSSL pueda proporcionar un PRNG mejor que el que ofrece el sistema de forma nativa.

Por lo tanto, debería ser posible eliminar por completo el PRNG de OpenSSL de la ecuación y confiar exclusivamente en el sistema PRNG, como lo ha hecho PHP .

@ joepie91 ¿

Si bien eso probablemente sería bueno (aunque requiriera más investigación), no creo que sea factible. Hasta donde yo sé, la otra funcionalidad de OpenSSL se basa internamente en su propio PRNG sin capacidad para cambiar eso, a menos que queramos deshacernos de OpenSSL por completo, lo que sería una propuesta separada (y probablemente no sea viable en esta etapa, dada la falta de alternativas bien probadas).

Por lo tanto, esta propuesta específica se referiría únicamente al método randomBytes "orientado al usuario".

Ok, considerando los argumentos probablemente ahora tenga más sentido.

Aquí hay una razón para no cambiar: el PRNG de OpenSSL es una cantidad conocida, la fuerza de los PRNG específicos de la plataforma no lo es. Si la próxima versión de Windows o FreeBSD tiene un PRNG defectuoso, eso comprometerá a node.js.

Si (genérico) cree que pasar a soluciones específicas de la plataforma es el camino a seguir, haga que OpenSSL adopte su enfoque y node.js lo seguirá automáticamente. Creo que @ paragonie-scott es voluntario. Seguro que parece estar muy convencido de ello.

Si la seguridad de las horquillas puede comenzar a importar debido a cambios futuros, es probable que la gente se haya olvidado de este problema específico.

@ joepie91 La lista completa de problemas de seguridad de las bifurcaciones que deberían abordarse es tan larga que creo que es seguro decir que node.js nunca será seguro para las bifurcaciones. Hay muchas cosas que me mantienen despierto por la noche, pero esta no es una de ellas.

Si la próxima versión de Windows o FreeBSD tiene un PRNG defectuoso, eso comprometerá a node.js.

Sinceramente, no creo que este argumento tenga ningún mérito.

~ FreeBSD no solo va a enviar código roto ~~ EDITAR: FreeBSD no va a enviar código roto a _la rama del kernel ESTABLE_ , especialmente cuando ya tienen un CSPRNG perfectamente funcional, y _especialmente_ porque tienen un equipo de seguridad propio que definitivamente detectaría cualquier cambio en el CSPRNG que conduciría a una vulnerabilidad en el sistema operativo.

Voy a ser franco, aquí: intentar justificar los problemas de seguridad es francamente irresponsable y posiblemente peligroso. _Necesitas_ esforzarte por lograr una seguridad a prueba de balas, o es posible que no implementes ninguna seguridad en absoluto (Y no, no distorsiones esto para que signifique "No te preocupes por la seguridad", porque eso es simplemente una pereza).

Aprecio que es "trabajo extra" hacer un cambio como este, pero considerando que estás usando un PRNG que en realidad ha causado problemas de seguridad en el pasado, me equivocaría por el lado seguro y pasaría a algo más seguro.

ya que tienen un equipo de seguridad propio que definitivamente detectaría cualquier cambio en el CSPRNG que condujera a una vulnerabilidad en el sistema operativo

Además de ser una apelación a la autoridad, me estás pidiendo (genéricamente) que confíe en varios equipos de implementadores (las plataformas) en lugar de solo en uno (OpenSSL) para que su implementación sea correcta.

considerando que está utilizando un PRNG que en realidad ha causado problemas de seguridad en el pasado

¿Está diciendo que siente que PRNG de OpenSSL es inseguro? Si es así, ¿por qué no lo está abordando con el equipo de OpenSSL? Quejarse de eso aquí no servirá de nada.

Repetiré lo que he dicho anteriormente: haz que el proyecto upstream se mueva, y nosotros, como consumidores downstream, lo seguiremos automáticamente.

Aquí hay una razón para no cambiar: el PRNG de OpenSSL es una cantidad conocida, la fuerza de los PRNG específicos de la plataforma no lo es. Si la próxima versión de Windows o FreeBSD tiene un PRNG defectuoso, eso comprometerá a node.js.

Sin embargo, el PRNG de OpenSSL se basa en estos PRNG específicos de la plataforma, y ​​la mezcla en un PRNG roto puede debilitar el PRNG completo (combinado). ¿Cómo se soluciona el problema que ha descrito al confiar en OpenSSL?

La lista de problemas de seguridad de la bifurcación que deberían abordarse es tan larga que creo que es seguro decir que node.js nunca será seguro para la bifurcación. Hay muchas cosas que me mantienen despierto por la noche, pero esta no es una de ellas.

Esa es una suposición muy peligrosa de hacer.

Si es así, ¿por qué no lo está abordando con el equipo de OpenSSL?

Creo que la existencia de este proyecto debería dar una indicación. En esta etapa, existe un consenso bastante amplio en la comunidad de seguridad de que OpenSSL es un software terrible, y la única razón real por la que todavía se recomienda es porque es lo que se ha probado en el mundo real durante tanto tiempo. No porque sea de alta calidad o en buen estado.

@bnoordhuis :

Aquí hay una razón para no cambiar: el PRNG de OpenSSL es una cantidad conocida, la fuerza de los PRNG específicos de la plataforma no lo es. Si la próxima versión de Windows o FreeBSD tiene un PRNG defectuoso, eso comprometerá a node.js.

Este es un argumento común que la gente hace, pero en última instancia no es válido.

Incluso si evita depender del PRNG del sistema operativo, el resto de su sistema definitivamente depende de él por seguridad. Node.js se verá comprometido independientemente de lo que haga Node.js.

Solo un poco de información para todos aquí:

http://lwn.net/Articles/633805/rss

"Generador de números aleatorios FreeBSD roto durante los últimos 4 meses"

@indutny Tenga en cuenta que también afecta a las claves generadas por Node.js en FreeBSD (usando crypto.randomBytes() ):

Esto incluye, entre otros, claves ssh y claves generadas por openssl.

@bnoordhuis

Aquí hay una razón para no cambiar: el PRNG de OpenSSL es una cantidad conocida, la fuerza de los PRNG específicos de la plataforma no lo es. Si la próxima versión de Windows o FreeBSD tiene un PRNG defectuoso, eso comprometerá a node.js.

En realidad, si el CSPRNG de Windows se ve comprometido, entonces Node.JS se verá comprometido. Esto se debe a que OpenSSL se basa en el sistema CSPRNG para generarlo. No hay otra fuente de datos aleatorios de alta calidad en el sistema.

Esto significa que el CSPRNG de OpenSSL, por definición, no puede ser más fuerte que el CSPRNG del sistema. Sin embargo, puede ser más débil (como se ha visto varias veces).

La razón por la que @ paragonie-scott y otros (incluyéndome a mí) son anti-userspace-csprng es que no brindan ninguna ganancia de seguridad posible, pero introducen varios riesgos de seguridad (al aumentar el área de superficie de ataque, al aumentar el área de superficie de error, etc.).

Realmente no hay ningún beneficio en _no_ cambiar (aparte de no hacer ningún cambio). Sin embargo, como ya se ha demostrado en este hilo, el cambio tiene varias ventajas.

Mi sugerencia sería cambiar al espacio de kernel CSPRNG.

@ChALkeR esta fue una respuesta a:

FreeBSD no solo va a impulsar código roto, especialmente cuando ya tienen un CSPRNG perfectamente funcional

@indutny sí, esta suposición de @alfiepates es incorrecta:

FreeBSD no solo va a impulsar código roto, especialmente cuando ya tienen un CSPRNG perfectamente funcional, y especialmente porque tienen un equipo de seguridad propio que definitivamente detectaría cualquier cambio en el CSPRNG que pudiera generar una vulnerabilidad en el sistema operativo.

Todo el mundo comete errores, no se puede decir «{*} no sólo va a introducir un código roto» o «esta lib es mágica, brillante y nunca se romperá».

Pero lo que realmente debería considerarse aquí es el hecho de que OpenSSL PRNG depende del sistema PRNG. Por lo tanto, parece que bajo ninguna circunstancia podría confiar en OpenSSL PRNG más que en el sistema PRNG, lo que hace que «no podemos confiar en los PRNG del sistema, así que usemos el argumento OpenSSL» no válido.

@indutny

Me retractaré de algunos de mis comentarios, fue demasiado absoluto, pero no creo que esté mal.

Es falso vincular este artículo sin indicar el hecho de que esto ocurrió en la rama -CURRENT de FreeBSD, a diferencia de la rama -STABLE. La rama -CURRENT es la rama de última generación y, por lo tanto, ocurren errores y, en este caso, el error se detectó antes de que llegara a -STABLE.

Además, creo que se está perdiendo el sentido de esta discusión. EDITAR: Necesita prestar más atención cuando está cansado.

@ChALkeR, por supuesto, no estoy diciendo que esto sea un contraargumento. Solo quería asegurarme de que todos estén en la misma página y no confíen ciegamente en los proveedores de sistemas operativos.

@alfiepates oye, ¡no me https://github.com/nodejs/node/issues/5798#issuecomment -198833767

@indutny Ahh, maravilloso. Me retractaré también de esa parte de mi comentario: P (Por favor, perdóname, estoy una taza de café atrasado en este momento)

Sin embargo, existe el riesgo de una implementación incorrecta por nuestra parte, cuando escribamos ese nuevo código para admitir PRNG a nivel de sistema operativo. Solo un poco de alimento para los pensamientos.

@indutny True. También hay un argumento de bloqueo versus no bloqueo que debería discutirse al implementar esto (es decir, /dev/random versus /dev/urandom ). Todavía no tengo una opinión al respecto.

@indutny Seguro. Estoy casi seguro de que el borrador será incorrecto de alguna manera. Por eso es importante la revisión por pares.

Por lo que vale, ayudé con la implementación de PHP y trabajo para una empresa que audita el código criptográfico. Hay otros en este hilo que a menudo son más perceptivos que yo.

Por lo tanto, siempre que participemos, es muy probable que se detecten y rectifiquen los errores de implementación.

@ChALkeR : https://blog.cr.yp.to/20140205-entropy.html

¿Existe algún argumento serio de que agregar nueva entropía todo el tiempo es algo bueno? La página del manual de Linux / dev / urandom afirma que sin una nueva entropía el usuario es "teóricamente vulnerable a un ataque criptográfico", pero (como he mencionado en varios lugares) este es un argumento ridículo: ¿cómo puede alguien creer simultáneamente que

  • no podemos averiguar cómo expandir determinísticamente un secreto de 256 bits en un flujo interminable de claves impredecibles (esto es lo que necesitamos de urandom), pero
  • ¿Podemos averiguar cómo usar una sola clave para cifrar de forma segura muchos mensajes (esto es lo que necesitamos de SSL, PGP, etc.)?

También hay personas que afirman que es importante que los RNG proporcionen "resistencia a la predicción" contra los atacantes que, una vez, vieron todo el estado del RNG. Pero si el atacante ve el estado RNG que se utilizó para generar sus claves SSL a largo plazo, claves PGP a largo plazo, etc., ¿qué estamos ganando exactamente al generar números aleatorios impredecibles en el futuro?

También http://www.2uo.de/myths-about-urandom/

/dev/urandom es lo que quiere aquí.

Parece que /dev/random es demasiado lento en algunos sistemas, por lo que su uso supondría un cambio muy importante (y quizás incluso una regresión). Usar /dev/urandom no sería un cambio muy importante.

No estoy seguro de Windows y Linux, pero OSX y FreeBSD usan Yarrow, creo que FreeBSD cambió a Fortuna. Ambos algoritmos están hechos por la misma persona y son bastante fiables.
Mejor que los generadores de espacio de usuario

enlace interesante:
Generador de números aleatorios de Linux

Partiendo de las vigas ... ¿habría una razón por la que no tendría sentido implementar esto en LibUV y ser un consumidor posterior a su implementación?

¿Habría alguna razón por la que no tendría sentido implementarlo en LibUV y ser un consumidor posterior a su implementación?

Si puede garantizar la rápida adopción de Node.js de esta API (¿aparentemente nueva?) En LibUV, probablemente sería mejor, ya que puede haber otras aplicaciones que dependan de ella.

Esto significa que el CSPRNG de OpenSSL, por definición, no puede ser más fuerte que el CSPRNG del sistema.

Eso no es cierto. / dev / urandom no es la única fuente de entropía, especialmente cuando tienes egd instalado. Incluso cuando no lo hace, todavía se obtienen algunos bits adicionales de entropía al mezclar los resultados de getpid (), gettimeofday (), etc.

Además, y me estoy repitiendo por tercera vez, si todos sienten que el PRNG de OpenSSL está tan horriblemente roto, entonces, ¿por qué no se están ocupando de eso con el proyecto OpenSSL? Si OpenSSL cambia, nosotros cambiamos, ¿qué es tan difícil de entender aquí?

Además, y me estoy repitiendo por tercera vez, si todos sienten que el PRNG de OpenSSL está tan horriblemente roto, ¿por qué no se están ocupando de eso con el proyecto OpenSSL?

Eso ya se ha abordado. OpenSSL es una pieza de software generalmente mediocre que solo está realmente estancada porque ya la estamos usando y es un poco menos horrible que rodar nuestro propio código en la mayoría de los casos ... no es una base de código fantástica y donde ya tenemos una gran CSPRNG (/ dev / urandom) no tiene sentido usar código que haya causado problemas de seguridad en el pasado.

Podemos sentarnos a hurgar en OpenSSL hasta que hagan algo (lo que no sucederá en un período de tiempo razonable) o podemos decir "oye, hay un problema" y arreglar lo que tenemos el poder de arreglar.

Entonces, lo que está sugiriendo es que, al contrario de décadas de buenas prácticas de ingeniería de software, solucionamos los problemas en las hojas en lugar de en la raíz. Creo que puedes adivinar por mi tono cómo me siento al respecto.

Además, y me estoy repitiendo por tercera vez, si todos sienten que el PRNG de OpenSSL está tan horriblemente roto, ¿por qué no se están ocupando de eso con el proyecto OpenSSL?

Bien, aquí tienes: https://github.com/openssl/openssl/issues/898

Pueden leer este hilo para el contexto.

Se considera una buena forma dar un resumen en el informe de error, pero gracias, agradezco que se haya tomado el tiempo de abrir uno.

Se considera una buena forma dar un resumen en el informe de errores.

Tenga la seguridad de que son _bien_ conscientes de los déficits en su espacio de usuario RNG. Se critica con bastante frecuencia. Anticipo que se cerrará rápidamente como WONTFIX.

todavía hay algunos bits extra de entropía obtenidos al mezclar los resultados de getpid (), gettimeofday (), etc.

¿Ninguno de los dos me parece particularmente aleatorio o impredecible?

Entonces, lo que está sugiriendo es que, al contrario de décadas de buenas prácticas de ingeniería de software, solucionamos los problemas en las hojas en lugar de en la raíz.

Esas mismas décadas de buenas prácticas de ingeniería de software reconocen que si la raíz no está dispuesta a solucionar el problema, no se deja el problema persistiendo, sino que se repara en las hojas.

+1
screen shot 2016-03-20 at 12 10 08 pm

No hay ningún argumento convincente en contra del uso de fuentes del núcleo, ya que OpenSSL ya se está sembrando a partir de ellas. Según: https://github.com/nodejs/node/issues/5798#issuecomment -198932579 +1

Disfruto particularmente la idea de que este problema está burbujeando hasta hacer (u) aleatorio más rápido en el kernel de Linux

@bnoordhuis

Eso no es cierto. / dev / urandom no es la única fuente de entropía, especialmente cuando tienes egd instalado. Incluso cuando no lo hace, todavía se obtienen algunos bits adicionales de entropía al mezclar los resultados de getpid (), gettimeofday (), etc.

En primer lugar, getpid() y gettimeofday() no proporcionan suficiente aleatoriedad para fines de CS. Y solo proporcionan entropía de una sola vez con fines de siembra (y como 4 bits de entropía).

En cuanto a EGD, obtiene su entropía del kernel. Y sí, /dev/urandom no es el único dispositivo para acceder a la entropía administrada por el kernel. Pero el hecho de que existan otros métodos no significa que depender de un CSPRNG de espacio de usuario sea algo bueno. Especialmente cuando se considera que un compromiso del kernel es, por definición, un compromiso de los procesos secundarios.

Entonces, si bien hay beneficios para el espacio del kernel CSPRNG (ningún compromiso del área de usuario filtrará el estado), no hay beneficios del espacio de usuario CSPRNG (ya que cualquier compromiso contra el que se defendería por definición estaría expuesto, por lo tanto, no puede defenderse de ellos ).

Si OpenSSL cambia, nosotros cambiamos, ¿qué es tan difícil de entender aquí?

Si esa es la posición del proyecto, esa es su prerrogativa (todo lo que podemos hacer es recomendar e intentar mostrarle por qué creemos que esa postura es incorrecta). Sin embargo, según este hilo, parece que esa no es realmente la posición del proyecto, sino solo su vista personal (a menos que me falte algo).

Ok, entonces, uno de los posibles inconvenientes que se ha mencionado en https://github.com/openssl/openssl/issues/898#issuecomment -199355257 es que /dev/urandom es aproximadamente 50 veces más lento que AES-128-CTR_DRBG (los números mencionados son ~ 160 Mbps y ~ 8 Gbps). Sin embargo, ahora no estoy seguro de cómo funciona en comparación con lo que OpenSSL usa internamente.

¿Es eso crítico para nosotros? En caso afirmativo, ¿cómo lo abordaría esta propuesta?

¿Es eso crítico para nosotros?

No.

¿Cómo lo abordaría esta propuesta?

Si OpenSSL 1.1 (o posterior) adopta una función RAND_sys_bytes() como se describe en el otro hilo, utilícela en lugar de RAND_bytes() y llámelo cerrado.

Actualización: en realidad, crypto.randomBytes() da 175 Mbps en mi PC, mientras que /dev/urandom da 157 Mbps.

Esos están bastante cerca, por lo que _quizás_ cambiar a / dev / urandom internamente no tendrá un impacto significativo en el rendimiento. Sin embargo, esto debe probarse cuando se implemente y en varias plataformas. Si nos preocupamos por el rendimiento de crypto.randomBytes() , eso es.

Si nos preocupamos por el rendimiento de crypto.randomBytes() , eso es.

Dentro de lo razonable, debería hacerlo. Si solo necesita obtener 32 bytes en menos de un milisegundo, es probable que un límite superior en el ancho de banda medido en MB / s frente a GB / s no marque la diferencia. Por el contrario, una diferencia que haga que una aplicación tome 0.5 segundos adicionales por ejecución sería un factor decisivo para la mayoría de las personas.

Anticipo que se cerrará rápidamente como WONTFIX.

Debes sentirte tonto.

Actualización: en realidad, crypto.randomBytes() da 175 Mbps en mi PC, mientras que /dev/urandom da 157 Mbps.

¿Puede compartir cómo realizó esta prueba? por ejemplo, dd frente a node . Como señalo a continuación, mis números de rendimiento son muy diferentes.

Si solo necesita obtener 32 bytes en menos de un milisegundo, es probable que un límite superior en el ancho de banda medido en MB / s frente a GB / s no marque la diferencia. Por el contrario, una diferencia que haga que una aplicación tome 0.5 segundos adicionales por ejecución sería un factor decisivo para la mayoría de las personas.

Si necesita una única vez, tomar 32 bytes de vez en cuando está bien. Mi máquina puede hacer eso en cuestión de microsegundos usando randomBytes() , pero tan pronto como le pido que capture 512 MB de rendimiento de 32 bytes consecutivos, cae a más de 4 ms por cada paquete de 32 bytes. Lo he perfilado para asegurarme de que el nodo no era la causa y que sha1_block_data_order_ssse3 consumía el 25% del rendimiento. No me he tomado el tiempo para profundizar y evaluar completamente dónde se gasta cada tic.

El punto aquí es que el rendimiento es importante y que obtener un rendimiento alto y constante es más complejo de lo que parece. Depender únicamente de /dev/urandom causaría una enorme regresión de rendimiento en mi máquina. Actualmente puedo hacer ~ 300 Mbps usando randomBytes() reuniendo trozos de 1 Mb, pero ejecutando:

$ time sudo < /dev/urandom dd bs=1048576 count=10 > /dev/null

y obtengo solo 96 Mbps (sí, intenté variaciones y este fue el rendimiento máximo que pude obtener).

Entonces, ¿podemos proporcionar un argumento sólido para cambiar implementaciones si el impacto en el rendimiento fuera tan grande (como si alguien pudiera demostrar empíricamente que la seguridad mejorará con la nueva implementación, o es hipotético mixto en este punto)? ¿O debería posponerse esta discusión hasta que se haya mejorado el rendimiento de /dev/urandom ?


Aquí está el punto de referencia rápido que reuní y que tiene varias variaciones:

'use strict';

const crypto = require('crypto');
const print = process._rawDebug;
const SIZE = 1024 * 1024 * 512;

var t = process.hrtime();
crypto.randomBytes(SIZE);
printTime();

//const CHUNK = 32;
//var t = process.hrtime();
//(function runner(n) {
  //if ((n + CHUNK) >= SIZE)
    //return printTime();
  //crypto.randomBytes(CHUNK, () => runner(n + CHUNK));
//}(0));

//var t = process.hrtime();
//for (var i = 0; i < 16777216; i++) {
  //crypto.randomBytes(32);
//}
//t = process.hrtime(t);
//print(((t[0] * 1e3 + t[1] / 16777216) / 1e4).toFixed(3) + ' ms/32 bytes');

function printTime() {
  t = process.hrtime(t);
  const mbps = (SIZE / 1024 / 1024) * 8 / (t[0] + t[1] / 1e9);
  print(mbps + ' Mbps');
}

@trevnorris

  1. Simplemente use dd if=/dev/urandom of=/dev/null status=progress . No sudo , no time . Imprime los resultados en MB / s, también bytes y segundos.
  2. Su prueba muestra 155 Mbps aquí. Usé uno similar, pero basado en devolución de llamada, 100 fragmentos, cada uno de 1 MiB de tamaño, directamente en la respuesta:

js var start = process.hrtime(); var next = (i) => crypto.randomBytes(1024 * 1024, () => { if (i <= 0) { var end = process.hrtime(start); console.log(8 * 100 / (end[0] + end[1] * 1e-9)); } else { next(i - 1); } } ); next(100);

_ (Nota: Se envió una versión parcial anterior de esto por correo electrónico, ignórelo. Maldito GitHub.) _

Oye, voy a intervenir por última vez en este hilo:

No voy a nombrar ningún nombre, pero el tono del discurso en este hilo (y en algunos casos externamente, he visto algunos ... tweets interesantes) corre el riesgo de volverse menos civilizado. Si bien no estoy tratando de desviar la conversación hacia "how2discuss", creo que es importante que tengamos en cuenta que (en mi opinión) deberíamos tener el mismo objetivo común: garantizar que el nodo sea lo más seguro posible.

La seguridad se encuentra en una posición bastante singular en la que los compromisos rara vez son aceptables; Si bien las decisiones mediocres de la interfaz de usuario solo conducirán a una mala experiencia del usuario, o la optimización incompleta puede hacer que un proceso se ejecute durante más tiempo o fijar algunos núcleos, la mala seguridad conduce a un _ riesgo de vida real_. Para ser franco: la seguridad de mierda hace que maten a la gente. Node.js se implementa en situaciones en las que la seguridad es importante y, por lo tanto, los desarrolladores de Node.js tienen la responsabilidad de garantizar que la seguridad esté a la altura.

No se trata de egos, no se trata de "No me gusta cómo estás haciendo XYZ", no se trata de nada de eso. Se trata de riesgos que conllevan consecuencias en la vida real. Hay personas que comentan en este hilo que consideran la seguridad como su principal empleo a tiempo completo y que son muy buenos en eso. Los animo a todos a que investiguen los antecedentes de los que están en este hilo haciendo sugerencias, no como una excusa para desacreditar sus sugerencias, sino para poner a un ser humano detrás de estas palabras.

Me saldré de este hilo ya que no tengo mucho para agregar en cuanto a la implementación, pero estoy más que dispuesto (en una fecha posterior) a hablar sobre cómo asegurarme de que estas discusiones se mantengan encaminadas en el futuro.

Aprecio lo que están haciendo todos ustedes.

Actualización: en realidad, crypto.randomBytes () da 175 Mbps en mi PC, mientras que / dev / urandom da 157 Mbps.

@ChALkeR Pruébelo con 3 o 4 instancias ejecutándose simultáneamente. Un gran problema con / dev / urandom es que es un recurso compartido; puede producir una producción a una cierta tasa, pero esa tasa se divide por el número de consumidores.

Además, / dev / urandom ha visto algunas mejoras de escalabilidad a lo largo de los años, pero admitimos kernels desde 2.6.18.

@ChALkeR

Simplemente use dd if = / dev / urandom of = / dev / null status = progress

Lamentablemente, status=progress no está disponible. ¿Qué versión de kernel / dd está ejecutando?

Su prueba muestra 155 Mbps aquí. Usé uno similar, pero basado en devolución de llamada, 100 fragmentos, cada uno de 1 MiB de tamaño

No dudo que lo haga, pero también le hago saber que en mi caja puedo generar a ~ 300-400 Mbps. Demostrar que será más complejo generar puntos de referencia de rendimiento confiables y que podemos correr el riesgo de hacerlo lo suficientemente lento como para que no se utilice.

Cuando los usuarios leen publicaciones de blogs que indican que el PRNG de Math.random() se ha solucionado, es posible que comiencen a hacer cosas como las siguientes:

const buf = Buffer(SIZE);
var idx = 0;
while ((idx = buf.writeUInt32LE(Math.random() * (-1 >>> 0), idx)) < SIZE);

Que, por cierto, genera datos a 1300 Mbps.

Irónicamente, el ciclo anterior while prueba bien la aleatoriedad. Usando dieharder en un archivo de 512 MB generado a partir del bucle while anterior, y a partir de la salida de /dev/urandom . A continuación se muestra una tabla con ambos resultados. El primer conjunto es del bucle while anterior. El segundo es de /dev/urandom .

#=============================================================================#
#            dieharder version 3.31.1 Copyright 2003 Robert G. Brown          #
#=============================================================================#
   rng_name         ||     filename                                  ||           filename
 file_input_raw     ||      /tmp/random_data.bin                     ||            /tmp/urandom_data.bin
#==============================================================================================================================#
        test_name   ||ntup| tsamples |psamples|  p-value |Assessment ||ntup| tsamples |psamples|  p-value |Assessment
#==============================================================================================================================#
     dab_bytedistrib||   0|  51200000|       1|0.09731279|  PASSED   ||   0|  51200000|       1|0.19394655|  PASSED
             dab_dct|| 256|     50000|       1|0.76785422|  PASSED   || 256|     50000|       1|0.70144164|  PASSED
       dab_filltree2||   0|   5000000|       1|0.21736330|  PASSED   ||   0|   5000000|       1|0.58799138|  PASSED
       dab_filltree2||   1|   5000000|       1|0.94496905|  PASSED   ||   1|   5000000|       1|0.97227096|  PASSED
        dab_filltree||  32|  15000000|       1|0.49546955|  PASSED   ||  32|  15000000|       1|0.62787597|  PASSED
        dab_filltree||  32|  15000000|       1|0.91901131|  PASSED   ||  32|  15000000|       1|0.80891168|  PASSED
        dab_monobit2||  12|  65000000|       1|0.69102119|  PASSED   ||  12|  65000000|       1|0.05164031|  PASSED
    diehard_2dsphere||   2|      8000|     100|0.45060252|  PASSED   ||   2|      8000|     100|0.45652347|  PASSED
    diehard_3dsphere||   3|      4000|     100|0.27961199|  PASSED   ||   3|      4000|     100|0.49351845|  PASSED
   diehard_birthdays||   0|       100|     100|0.48110599|  PASSED   ||   0|       100|     100|0.19910323|  PASSED
   diehard_bitstream||   0|   2097152|     100|0.99536763|   WEAK    ||   0|   2097152|     100|0.79115717|  PASSED
diehard_count_1s_byt||   0|    256000|     100|0.20484695|  PASSED   ||   0|    256000|     100|0.78195702|  PASSED
diehard_count_1s_str||   0|    256000|     100|0.75812248|  PASSED   ||   0|    256000|     100|0.54848822|  PASSED
       diehard_craps||   0|    200000|     100|0.23976205|  PASSED   ||   0|    200000|     100|0.24913827|  PASSED
       diehard_craps||   0|    200000|     100|0.97521323|  PASSED   ||   0|    200000|     100|0.99211351|  PASSED
      diehard_operm5||   0|   1000000|     100|0.75459685|  PASSED   ||   0|   1000000|     100|0.87415332|  PASSED
 diehard_parking_lot||   0|     12000|     100|0.72516127|  PASSED   ||   0|     12000|     100|0.51744758|  PASSED
  diehard_rank_32x32||   0|     40000|     100|0.04089185|  PASSED   ||   0|     40000|     100|0.55049357|  PASSED
    diehard_rank_6x8||   0|    100000|     100|0.76009470|  PASSED   ||   0|    100000|     100|0.86409689|  PASSED
        diehard_runs||   0|    100000|     100|0.83761343|  PASSED   ||   0|    100000|     100|0.08393408|  PASSED
        diehard_runs||   0|    100000|     100|0.96494601|  PASSED   ||   0|    100000|     100|0.79795717|  PASSED
     diehard_squeeze||   0|    100000|     100|0.21902504|  PASSED   ||   0|    100000|     100|0.45034347|  PASSED
 marsaglia_tsang_gcd||   0|  10000000|     100|0.00061302|   WEAK    ||   0|  10000000|     100|0.00000000|  FAILED
 marsaglia_tsang_gcd||   0|  10000000|     100|0.74541958|  PASSED   ||   0|  10000000|     100|0.91843104|  PASSED
     rgb_kstest_test||   0|     10000|    1000|0.55923481|  PASSED   ||   0|     10000|    1000|0.01354922|  PASSED
      rgb_lagged_sum||   0|   1000000|     100|0.36751921|  PASSED   ||   0|   1000000|     100|0.93757630|  PASSED
rgb_minimum_distance||   0|     10000|    1000|0.00000000|  FAILED   ||   0|     10000|    1000|0.00000000|  FAILED
    rgb_permutations||   5|    100000|     100|0.30443228|  PASSED   ||   5|    100000|     100|0.64178140|  PASSED
         sts_monobit||   1|    100000|     100|0.85916197|  PASSED   ||   1|    100000|     100|0.98321093|  PASSED
            sts_runs||   2|    100000|     100|0.96656242|  PASSED   ||   2|    100000|     100|0.37000645|  PASSED
          sts_serial||  10|    100000|     100|0.17108872|  PASSED   ||  10|    100000|     100|0.78291929|  PASSED
          sts_serial||  10|    100000|     100|0.43352488|  PASSED   ||  10|    100000|     100|0.80215761|  PASSED
          sts_serial||   1|    100000|     100|0.85916197|  PASSED   ||   1|    100000|     100|0.98321093|  PASSED
          sts_serial||  11|    100000|     100|0.56250044|  PASSED   ||  11|    100000|     100|0.46751929|  PASSED
          sts_serial||  11|    100000|     100|0.96681711|  PASSED   ||  11|    100000|     100|0.72513734|  PASSED
          sts_serial||  12|    100000|     100|0.80290859|  PASSED   ||  12|    100000|     100|0.71128922|  PASSED
          sts_serial||  12|    100000|     100|0.97395930|  PASSED   ||  12|    100000|     100|0.84596100|  PASSED
          sts_serial||  13|    100000|     100|0.05460794|  PASSED   ||  13|    100000|     100|0.61265757|  PASSED
          sts_serial||  13|    100000|     100|0.06000085|  PASSED   ||  13|    100000|     100|0.68475462|  PASSED
          sts_serial||  14|    100000|     100|0.24213451|  PASSED   ||  14|    100000|     100|0.22612266|  PASSED
          sts_serial||  14|    100000|     100|0.43303295|  PASSED   ||  14|    100000|     100|0.34819106|  PASSED
          sts_serial||  15|    100000|     100|0.70772349|  PASSED   ||  15|    100000|     100|0.38347196|  PASSED
          sts_serial||  15|    100000|     100|0.94036403|  PASSED   ||  15|    100000|     100|0.79931573|  PASSED
          sts_serial||  16|    100000|     100|0.18413544|  PASSED   ||  16|    100000|     100|0.21397317|  PASSED
          sts_serial||  16|    100000|     100|0.51409929|  PASSED   ||  16|    100000|     100|0.28934397|  PASSED
          sts_serial||   2|    100000|     100|0.86549774|  PASSED   ||   2|    100000|     100|0.34830172|  PASSED
          sts_serial||   3|    100000|     100|0.61116626|  PASSED   ||   3|    100000|     100|0.55936667|  PASSED
          sts_serial||   3|    100000|     100|0.81261243|  PASSED   ||   3|    100000|     100|0.91339662|  PASSED
          sts_serial||   4|    100000|     100|0.04777919|  PASSED   ||   4|    100000|     100|0.10701052|  PASSED
          sts_serial||   4|    100000|     100|0.67123232|  PASSED   ||   4|    100000|     100|0.14444634|  PASSED
          sts_serial||   5|    100000|     100|0.17241503|  PASSED   ||   5|    100000|     100|0.03073699|  PASSED
          sts_serial||   5|    100000|     100|0.73980051|  PASSED   ||   5|    100000|     100|0.86069674|  PASSED
          sts_serial||   6|    100000|     100|0.61426714|  PASSED   ||   6|    100000|     100|0.73662496|  PASSED
          sts_serial||   6|    100000|     100|0.61541617|  PASSED   ||   6|    100000|     100|0.74861872|  PASSED
          sts_serial||   7|    100000|     100|0.37869368|  PASSED   ||   7|    100000|     100|0.18601122|  PASSED
          sts_serial||   7|    100000|     100|0.47181049|  PASSED   ||   7|    100000|     100|0.86052350|  PASSED
          sts_serial||   8|    100000|     100|0.00960323|  PASSED   ||   8|    100000|     100|0.55658027|  PASSED
          sts_serial||   8|    100000|     100|0.34149403|  PASSED   ||   8|    100000|     100|0.99697626|   WEAK
          sts_serial||   9|    100000|     100|0.03105746|  PASSED   ||   9|    100000|     100|0.04533251|  PASSED
          sts_serial||   9|    100000|     100|0.93545391|  PASSED   ||   9|    100000|     100|0.12295836|  PASSED

Incluso probado bien en los resultados de rng de cacert.org (busque "v8 4.9.385 Math.random ()"). Quizás deberíamos cambiar a eso. :-PAG

@trevnorris Eso sería solo otro espacio de usuario PRNG que sería un punto adicional de falla en la parte superior del sistema PRNG ...

Aún no he analizado tus resultados de dieharder .

dd --versions dice «dd (coreutils) 8.25». Si no tiene status=progress , simplemente inicie watch killall -USR1 dd en una pestaña separada; enviará USR1 señales a dd cada 2 segundos, y dd imprime el progreso cuando recibe una señal USR1 .

@ChALkeR Estoy usando 8.23, y un buen truco.

Ese sería solo otro PRNG de espacio de usuario que sería un punto adicional de falla en la parte superior del sistema PRNG ...

Perdón. :-P estaba destinado a implicar / so: trollface: y que me sorprendió que Math.random() hubiera obtenido calificaciones tan altas en una rigurosa prueba de análisis de aleatoriedad. Y para sugerir que las personas pueden ver resultados como este y sentirse justificados al elegir lo anterior, while loop over randomBytes() porque nuestra implementación es mucho más lenta.

No es raro que los PRNG que no pertenecen a CS obtengan una buena puntuación en el análisis de aleatoriedad.
Sin embargo, eso no los hace adecuados para criptografía; por eso, no
solo tiene que ser indistinguible de la aleatoriedad, pero también impredecible
y no subvertible.
El 23 de marzo de 2016 05:50, "Trevor Norris" [email protected] escribió:

@ChALkeR https://github.com/ChALkeR Estoy usando 8.23 ​​y un buen truco.

Eso sería solo otro PRNG de espacio de usuario que sería una señal adicional
punto de falla en la parte superior del sistema PRNG ...

Perdón. :-P estaba destinado a implicar / so [image:: trollface:] y que yo estaba
sorprendido Math.random () hubiera obtenido calificaciones tan altas en un riguroso
prueba de análisis de aleatoriedad. Y para sugerir que las personas pueden ver resultados como este
y siéntete justificado al elegir lo anterior while loop over randomBytes ()
porque nuestra implementación es mucho más lenta.

-
Recibes esto porque te mencionaron.
Responda a este correo electrónico directamente o véalo en GitHub
https://github.com/nodejs/node/issues/5798#issuecomment -200192891

El humor es bueno, pero a menos que el calendario indique el 1 de abril, mantengamos la discusión de "usemos Math.random () para cripto" al mínimo.

El humor es bueno, pero a menos que el calendario indique el 1 de abril, mantengamos la discusión de "usemos Math.random () para cripto" al mínimo.

Aflojar. No hubo una conversación seria sobre su uso en core. Mi punto es que si nuestra implementación es tan lenta que es inutilizable, los usuarios comenzarán a recurrir a métodos como este. Eso es de lo que hablo en serio, y la historia ha demostrado que los usuarios tomarán este tipo de acción si nuestra API no funciona como es necesario y no hay alternativa. No refutes que está en ellos, porque es nuestra responsabilidad asegurarnos de que nuestra API sea aceptable.

No es raro que los PRNG que no pertenecen a CS obtengan una buena puntuación en el análisis de aleatoriedad, pero eso no los hace adecuados para la criptografía; por eso, no solo tienen que ser indistinguibles de la aleatoriedad, sino también impredecibles y no subvertibles.

Luego, comparta cómo se puede analizar correctamente la aleatoriedad para ver si es adecuada para el uso criptográfico.

Vale la pena referirse a la reescritura de LibreSSL de la funcionalidad de OpenSSL. Lo primero que intenta su función getentropy () (en Linux) es extraer de / dev / urandom:

https://github.com/libressl-portable/openbsd/blob/37759485f52993eb812898ccd70fc42cd92cdad5/src/lib/libcrypto/crypto/getentropy_linux.c#L114

Aparentemente, OpenSSL también es un bit de Android .

Parece que se publicó un nuevo artículo sobre PRNG de OpenSSL, hace unos días:

En este trabajo demostramos varias debilidades del generador de números aleatorios (RNG) en la biblioteca criptográfica OpenSSL. Mostramos cómo el RNG de OpenSSL, a sabiendas en un estado de baja entropía, potencialmente filtra secretos de baja entropía en su salida, que nunca fueron alimentados intencionalmente al RNG por el código del cliente, lo que presenta vulnerabilidades incluso cuando en el escenario de uso dado se respeta el estado de baja entropía por la aplicación del cliente. Pasando a la funcionalidad criptográfica central del RNG, mostramos cómo la funcionalidad de OpenSSL para agregar entropía al estado del RNG falla en ser efectivamente una función de mezcla. [...]

@ joepie91 He escaneado el papel. ¿La premisa principal parece ser que partir de un estado de baja entropía reduce la eficacia del PRNG? Eso parece evidentemente cierto. Node.js llama a RAND_poll() al inicio, así que creo que somos inmunes a eso (siempre que la entropía del sistema sea confiable).

Realmente no entiendo su otro hallazgo sobre la reducción de la entropía de 256 a 240 bits. ¿Se basa en que el atacante pueda observar los estados intermedios del PRNG?

EDITAR: ¿O es el problema de que RAND_bytes() usa el contenido preexistente del búfer de salida como entrada para el grupo de entropía? Desactivamos eso en nuestras compilaciones.

Veo que esto no se convirtió en el Nodo 6. ¿Quizás podríamos impulsar un verdadero CSPRNG en el Nodo 7?

@ paragonie-scott

Por cierto, este comentario de @trevnorris :

Mi punto es que si nuestra implementación es tan lenta que es inutilizable, los usuarios comenzarán a recurrir a métodos como este.

es similar a las razones de usar /dev/urandom lugar de /dev/random , consulte http://www.2uo.de/myths-about-urandom/ «¿Qué hay de malo en bloquear?».

Las razones para no hacerlo más lento aquí son bastante similares. Si bien una diferencia del 20% probablemente sería aceptable, hacerlo varias veces más lento probablemente se consideraría una regresión, y los usuarios recurrirían a _varios trucos_.

@ paragonie-scott

Veo que esto no se convirtió en el Nodo 6. ¿Quizás podríamos impulsar un verdadero CSPRNG en el Nodo 7?

No creo que se llegue a un acuerdo sobre la detección de plataforma aquí para la fuente de aleatoriedad, por lo que probablemente primero debería llevarse a uno de los departamentos que maneja la abstracción de la plataforma para cosas similares, por ejemplo, OpenSSL o libuv.

Todavía estoy esperando una respuesta sobre cómo determinar si los datos son "adecuados para criptografía". Dado que aprobar calificaciones en las pruebas de aleatoriedad aparentemente no es lo suficientemente bueno.

@trevnorris El NIST ha publicado un artículo sobre este mismo tema y mantiene una página web algo fácil de digerir que cubre CSRNG.

Pero, en mi opinión, esto no debería preocuparle, ya que la aleatoriedad del sistema (implementada con sensatez) está diseñada específicamente para abstraer esto.

Sin embargo, sí, estaría algo de acuerdo con @ChALkeR en que la abstracción de la plataforma probablemente debería ser manejada por una dependencia separada, pero eso también es algo en lo que no estoy del todo calificado para comentar, por lo que aquí es donde cesa mi entrada.

@alfiepates Gracias por los enlaces. El punto es que tengo mucha curiosidad por saber cómo se puntúa Math.random() . Nada realmente importante. :)

@trevnorris Math.random() es absolutamente predecible después de observar varios valores.

@indutny seguro, solo estoy interesado en ver eso por mí mismo después de que obtuvo una puntuación tan alta en las pruebas dieharder .

No existe una prueba que pruebe si una función dada es aleatoria. Solo hay pruebas que prueban que no es aleatorio.

Es decir, ninguna prueba le dirá si está bien. Es importante tener esto en cuenta cuando se habla de criptografía y números aleatorios (específicamente CSPRNG).

@trevnorris Es importante darse cuenta de que un CSPRNG no solo debe ser resistente al análisis, sino también a los intentos de manipulación dirigidos (por ejemplo, mediante la entropía de la fuente de 'envenenamiento'). Ninguna prueba de aleatoriedad mostrará esto. Determinar si los datos aleatorios son "suficientemente buenos" es en gran parte una cuestión de teoría.

@bnoordhuis En realidad, aún no he leído el artículo debido a limitaciones de tiempo, más bien pensé que lo publicaría en este hilo por su relevancia.

Solo un pensamiento, si alguien quisiera ser malicioso y tuviera acceso de publicación a la dependencia de alguien, podría hacer un parche silenciosamente:

require('crypto').randomBytes = () => Buffer('pawnd')

y arruinar la criptografía de todos en una sola línea. tal vez debería haber una protección contra esto?

@ carlos8f Hmm. Si eso funciona, funcionaría con _cualquier_ dependencia, y ni siquiera necesitaría comprometer una de terceros (debido a la caché requerida).

@ carlos8f ¿qué hay de ejecutar require('child_process').spawn desde la dependencia? También parece ser un compromiso de seguridad bastante serio. En mi opinión, existe cierta confianza que las personas depositan en las dependencias que instalan, esto no es algo de lo que el núcleo sea responsable.

@indutny cierto, pero eso sería más notable de un ataque. El módulo criptográfico del núcleo de parches de mono no debería estar permitido en mi opinión. por lo menos debería escupir una advertencia a la consola.

@ carlos8f bueno, tener acceso a require('fs') es suficiente para parchear el binario de node.js ...

@indutny sí, intenté lanzar un programa de nodo criptográfico el otro día y simplemente se rieron de él. nadie se toma en serio la seguridad de los nodos, especialmente si proviene de la comunidad de seguridad.

PD: estoy tratando de revivir la conversación sobre la firma de paquetes, pero al ver cosas como esta, me alejo en silencio ...

@ carlos8f No se trata solo de node, se trata de java, go, python, ruby ​​y casi cualquier cosa que tenga administradores de paquetes. Cualquier código que no haya sido escrito por miembros de la empresa debe considerarse inseguro, a menos que se demuestre lo contrario.

Una apuesta más segura sería adoptar lo que hace random_bytes () de PHP 7:

LOL que estamos en el año 2016, y PHP es lo que aspiramos a ser. Y al menos en PHP, no se pueden redefinir aleatoriamente partes del sistema de misión crítica como random_bytes () sin obtener una excepción adecuada en producción. El nodo _podría_ tener una mejor seguridad, pero elige no hacerlo, porque la seguridad es siempre un problema de otra persona. lamentablemente, las empresas no auditan su código, pero es por eso que los piratas informáticos nos mantenemos en el negocio muahaha.

El módulo criptográfico del núcleo de parches de mono no debería estar permitido en mi opinión.

Hay casos de uso legítimos, como la instrumentación y la supervisión del rendimiento.

Traté de lanzar un programa de nodo criptográfico el otro día y simplemente se rieron de él. nadie se toma en serio la seguridad de los nodos, especialmente si proviene de la comunidad de seguridad.

No llamaría a / r / crypto una comunidad de seguridad. Tal vez "un montón de idiotas que saben lo suficiente para ser peligrosos".

Para ser justos, eso se aplica a la mayoría de los subreddits relacionados con la tecnología con más de unos pocos cientos de suscriptores. Cuanto más grandes se vuelven, más regresan a la media.

Ninguna prueba de aleatoriedad mostrará esto. Determinar si los datos aleatorios son "suficientemente buenos" es en gran parte una cuestión de teoría.

Esto me fastidia. Tener un generador aleatorio adecuado es _ tan_ importante, sin embargo, todavía no he podido encontrar una manera de probar sólidamente empíricamente una implementación. Lo que hace que la línea "suficientemente buena" sea subjetiva e interminable (por ejemplo, este hilo).

El módulo criptográfico del núcleo de parches de mono no debería estar permitido en mi opinión.

Hay casos de uso legítimos, como la instrumentación y la supervisión del rendimiento.

Cualquiera puede congelar ese objeto, así que, como @bnoordhuis , considero que esto es un trabajo para el usuario.

Creo que el nodo podría tener algo para congelar todos sus objetos de preocupación de seguridad / módulos / * y evitar modificaciones no deseadas ...
process.freeze() ?

@trevnorris

Esto me fastidia. Tener un generador aleatorio adecuado es muy importante, pero todavía no he podido encontrar una manera de probar una implementación de manera empírica y sólida. Lo que hace que la línea "suficientemente buena" sea subjetiva e interminable (por ejemplo, este hilo).

Por eso vinculé el artículo del NIST. Es bastante difícil saber si un conjunto de números es aleatorio si todo lo que tienes es ese conjunto de números, pero si das el método por el cual se genera el conjunto de números, puedes empezar a decidir si obtienes aleatoriedad o no. .

Claro, no hay una "caja mágica de prueba de aleatoriedad", pero el documento del NIST define un conjunto de reglas para probar las implementaciones de CSPRNG.

@trevnorris : Esto me fastidia. Tener un generador aleatorio adecuado es muy importante, pero todavía no he podido encontrar una manera de probar una implementación de manera empírica y sólida. Lo que hace que la línea "suficientemente buena" sea subjetiva e interminable (por ejemplo, este hilo).

Aparte de lo que dijo @alfiepates , esto realmente no es diferente de la seguridad en general, por mucho que apesta (y sí, estoy de acuerdo en que esto es irritante). En el código del mundo real, no hay pruebas de que el código sea seguro, definitivamente no a través de pruebas empíricas; solo puede seguir tratando de encontrar debilidades y corregirlas tan pronto como las encuentre, incluso si parecen pequeñas o insignificantes. Los "escáneres de vulnerabilidades" son famosos por su inutilidad por esta razón.

Es la misma razón por la que tanto para los CSPRNG como para otras herramientas, el consejo general es "usar la cosa probada en batalla que no se sepa que esté rota", ya que es más probable que se haya acercado a la "seguridad perfecta" que la que no es de batalla. -opciones probadas, asumiendo que no hay información explícitamente contradictoria disponible. Es todo lo que puede hacer, de verdad, y tiene que hacerse con rigor.

@llafuente : Cualquiera puede congelar ese objeto, así que como @bnoordhuis considero que esto es un trabajo para el usuario.

Sin embargo, ¿cómo se asegura de que esto suceda _antes_ que cualquier otra cosa tenga la oportunidad de alterarlo? Debería esperar que el usuario haga esto explícitamente en el nivel superior de su código de aplicación, y eso inevitablemente se olvidará.

Preferiría verlo congelado de forma predeterminada (al menos hasta el punto de no permitir modificar las propiedades _existentes_, ya que, por ejemplo, promisificar podría ser necesario), con una marca de tiempo de ejecución para permitir que ciertos archivos o módulos omitan esto. Eso cubriría la instrumentación y el monitoreo del rendimiento, que son cosas que generalmente se habilitan explícitamente en tiempo de ejecución en un entorno específico.

Eso es seguridad falsa. Una forma obvia de eludirlo es generar gdb o abrir /proc/self/mem y voltear los bits de protección. Estoy seguro de que puedes pensar en más.

Sin embargo, nos estamos saliendo del tema.

FYI: discusión similar en Ruby - https://bugs.ruby-lang.org/issues/9569

Los RNG del espacio de usuario son peligrosos. Permítanme reiterar lo que un par de personas ya han dicho: ¡en Linux desea sembrar desde /dev/urandom ! Lo ideal sería seguir el camino, por ejemplo, libsodium maneja los RNG en diferentes plataformas, pero no voy a dictar nada, leyendo este hilo no estaba seguro de si debería reír o llorar.

Un mantenedor central incluso sugirió "agregar entropía" a través de egd . Algo que solo puedo describir como "seguridad vudú". De hecho, tuve que buscar en Google egd , porque no recordaba:

Un espacio de usuario que sustituye a / dev / random, escrito en perl.
[...]
egd-0.6 tenía un problema de seguridad importante que hacía que solo usara una pequeña fracción de la entropía que reunía. Todos los usuarios deben actualizar de inmediato.

Entonces recordé por qué existe: hace mucho tiempo, antes de que los lenguajes frontend de un solo hilo estuvieran de moda para escribir "microservicios" sensibles a la seguridad en, SunOS (es decir, Solaris) carecía de un generador de números aleatorios suministrado por el núcleo. Recuerdo que no pude compilar OpenSSH en esta cosa por eso y tuve que recurrir a algún demonio de recopilación de rng / entropía pirateado en ese entonces. Decidí usar telnet(1) lugar. Lo cual, en retrospectiva, fue una sabia elección, porque solo habría agregado seguridad por la oscuridad. Y no conectó la máquina a Internet. Tenía ~ 14 años en ese entonces y me gustaba mucho SPARC. También hay uno en Rexx si aún ejecuta OS / 2 o un Mainframe para desarrollar dependencias de nodos inútiles: http://r6.ca/RexxEGD/

Como ya le han dicho varias personas: el RNG en OpenSSL no es seguro para la bifurcación, ya que este lenguaje depende de la bifurcación para el rendimiento, no es prudente utilizar un RNG de espacio de usuario que tiene debilidades conocidas. El artículo reciente sobre las debilidades de RNG en OpenSSL ya estaba vinculado en el hilo, pero nuevamente: https://eprint.iacr.org/2016/367.pdf ya que parece que @bnoordhuis no leyó más allá del resumen o simplemente no lo hizo ' t captar su significado. _Sí, eso afectará la seguridad del nodo_. Creo que se ha solucionado (lo que no significa que esta versión no estará disponible durante mucho tiempo en los sistemas heredados, ..) - sin embargo, demuestra cómo un RNG de Userspace puede fallar en proporcionar la seguridad adecuada para un idioma en su conjunto. Sugerir demonios de recolección de entropía de tierras de usuarios es simplemente una locura. Hay tantos vectores de ataque. Entonces, o cree que el kernel en el que se está ejecutando funciona correctamente (de lo contrario, ¿por qué ejecutaría el lenguaje X en él de todos modos? ¿Recuerda la conferencia del premio Turing de Ken Thompson ? para el sistema operativo en el que está ejecutando. Si compila, en este caso a través de varios pasos, no solo tiene que confiar en sus compiladores y enlazadores, debe confiar en el sistema operativo en el que se están ejecutando y también en libc [por cierto, también el klibc]) y _may_ piensa en usar alternativas de seguridad adicionales como las implementadas por libsodium o estás confiando en la seguridad vudú para todo tu ecosistema.

Para ser honesto: realmente no me importa node.js y cada vez que necesito instalar algún servicio que depende de cinco administradores de módulos / paquetes diferentes e instala más de 200 dependencias, me pregunto por qué me estoy molestando. Pero sé que la gente ejecuta node en producción, por lo que puede ser aconsejable pensar en cuestiones sensibles a la seguridad en el lenguaje principal y la biblioteca.

Un espacio de usuario que sustituye a / dev / random, escrito en perl.

Creo que está confundiendo el programa con el protocolo.

el RNG en OpenSSL no es seguro para la bifurcación, ya que este lenguaje depende de la bifurcación para el rendimiento

¿Qué diablos te hace decir eso? Por favor, aclare sus datos. La única vez que el nodo se bifurca es para llamar a execve () inmediatamente después.

El artículo reciente sobre las debilidades de RNG en OpenSSL ya estaba vinculado en el hilo, pero nuevamente: https://eprint.iacr.org/2016/367.pdf ya que parece que @bnoordhuis no leyó más allá del resumen o simplemente no lo hizo ' t captar su significado.

¿Qué tal si lo explicas en lugar de hacer comentarios despectivos? Además del tono de su publicación, los errores fácticos me hacen reacio a tomarlo en serio.

Creo que está confundiendo el programa con el protocolo.

¿Qué protocolo? ¿Se refiere a https://www.openssl.org/docs/manmaster/crypto/RAND_egd.html? Si es así, de nuevo; ¿Por qué querría agregar entropía desde una fuente de espacio de usuario? ¿Cuáles son exactamente los casos de uso?

¿Qué diablos te hace decir eso? Por favor, aclare sus datos. La única vez que el nodo se bifurca es para llamar a execve () inmediatamente después.

Bien. No es un tenedor tradicional. child_process tiene los siguientes métodos:

  • .fork() :

Es importante tener en cuenta que los procesos secundarios generados de Node.js son independientes del principal, con la excepción del canal de comunicación IPC que se establece entre los dos. Cada proceso tiene su propia memoria, con sus propias instancias V8. Debido a las asignaciones de recursos adicionales necesarias, no se recomienda generar una gran cantidad de procesos secundarios de Node.js.

  • .spawn() : similar a popen(3) - abre una tubería bidireccional a una subcapa, ¿correcto? Soy consciente de cómo funciona esto en libuv, pero no estoy seguro de si se maneja exactamente igual en node.js; libuv utiliza subprocesos y grupos de subprocesos. mente: el OpenSSL PRNG tampoco es seguro para subprocesos: https://wiki.openssl.org/index.php/Random_Numbers#Thread_Safety
  • .send() : un desarrollador puede estar compartiendo incorrectamente el estado entre los niños a través de IPC.

Estos parecen ser rastreados a través de PID (¿son internos a node.js o PID de SO reales?). Asumiría que el último dado una subcapa está abierto desde otro proceso, pero ciertamente no estoy tan familiarizado con los componentes internos de node.js como usted. libuv usa OS PID si no recuerdo mal.

La documentación también contiene un método waitpid .

Más adelante en la línea, leí un poco del código central de nodejs:
https://github.com/nodejs/node/blob/master/src/node_crypto.cc#L234 -265

// Ensure that OpenSSL has enough entropy (at least 256 bits) for its PRNG.
// The entropy pool starts out empty and needs to fill up before the PRNG
// can be used securely.  Once the pool is filled, it never dries up again;
// its contents is stirred and reused when necessary.
//
// OpenSSL normally fills the pool automatically but not when someone starts
// generating random numbers before the pool is full: in that case OpenSSL
// keeps lowering the entropy estimate to thwart attackers trying to guess
// the initial state of the PRNG.
//
// When that happens, we will have to wait until enough entropy is available.
// That should normally never take longer than a few milliseconds.
//
// OpenSSL draws from /dev/random and /dev/urandom.  While /dev/random may
// block pending "true" randomness, /dev/urandom is a CSPRNG that doesn't
// block under normal circumstances.
//
// The only time when /dev/urandom may conceivably block is right after boot,
// when the whole system is still low on entropy.  That's not something we can
// do anything about.
inline void CheckEntropy() {
  for (;;) {
    int status = RAND_status();
    CHECK_GE(status, 0);  // Cannot fail.
    if (status != 0)
      break;

    // Give up, RAND_poll() not supported.
    if (RAND_poll() == 0)
      break;
  }
}

Si recuerda el resumen del documento al que se hizo referencia anteriormente, ese es exactamente el problema en cuestión:

Resumen: En este trabajo demostramos varias debilidades del generador de números aleatorios (RNG) en la biblioteca criptográfica OpenSSL. Mostramos cómo el RNG de OpenSSL, a sabiendas en un estado de baja entropía, potencialmente filtra secretos de baja entropía en su salida, que nunca fueron alimentados intencionalmente al RNG por el código del cliente, lo que presenta vulnerabilidades incluso cuando en el escenario de uso dado se respeta el estado de baja entropía por la aplicación del cliente. Pasando a la funcionalidad criptográfica central del RNG, mostramos cómo la funcionalidad de OpenSSL para agregar entropía al estado del RNG falla en ser efectivamente una función de mezcla. Si se supuso erróneamente que un estado inicial de baja entropía del RNG tenía 256 bits de entropía en base a estimaciones de entropía incorrectas, esto hace que los intentos de recuperarse de este estado tengan éxito solo a largo plazo pero fracasen a corto plazo. Como resultado, el nivel de entropía de las claves criptográficas generadas se puede limitar a 80 bits, aunque miles de bits de entropía podrían haber sido alimentados previamente al estado RNG. [...]

https://github.com/nodejs/node/blob/master/src/node_crypto.cc#L268 -275:

bool EntropySource(unsigned char* buffer, size_t length) {
  // Ensure that OpenSSL's PRNG is properly seeded.
  CheckEntropy();
  // RAND_bytes() can return 0 to indicate that the entropy data is not truly
  // random. That's okay, it's still better than V8's stock source of entropy,
  // which is /dev/urandom on UNIX platforms and the current time on Windows.
  return RAND_bytes(buffer, length) != -1;
}

https://www.openssl.org/docs/manmaster/crypto/RAND_bytes.html dice:

RAND_bytes () devuelve 1 en caso de éxito, 0 en caso contrario. El código de error se puede obtener mediante ERR_get_error. RAND_pseudo_bytes () devuelve 1 si los bytes generados son criptográficamente fuertes, 0 en caso contrario. Ambas funciones devuelven -1 si no son compatibles con el método RAND actual.

Así que creo que el cheque debería ser return RAND_bytes(buffer, length) == 0; - /dev/urandom es sin duda una mejor opción que un OpenSSL PRNG roto, ¿no lo crees? No sé si a node le importa Windows, pero RAND_poll es increíblemente lento debido a un error de caminata en el montón: https://rt.openssl.org/Ticket/Display.html?id=2100&user=guest&pass=guest

Permítanme concluir diciendo que todos los criptógrafos e ingenieros de software de seguridad que he hablado y la mayoría de los idiomas prefieren sembrar directamente desde urandom. Posiblemente haciendo uso de construcciones seguras y portátiles como la de libsodium : https://github.com/jedisct1/libsodium/blob/master/src/libsodium/randombytes/sysrandom/randombytes_sysrandom.c

En futuras versiones del Kernel de Linux, /dev/urandom contará con una construcción DRBG basada en ChaCha20 similar a la de arc4random de OpenBSD. Pero estos parches solo tienen unas pocas semanas y hay un par de personas trabajando en mejoras adicionales. De todas formas. Es seguro de usar y de semilla, ¿puedo preguntar por qué está usando específicamente el RNG de OpenSSL? Incluso algunos de sus mantenedores me dijeron "no lo use". Su RNG tampoco es de uso general, está destinado a ser utilizado para el interior del protocolo específico SSL / TLS.

Material de lectura recomendado: https://emboss.github.io/blog/2013/08/21/openssl-prng-is-not-really-fork-safe/

¿Qué protocolo? ¿Se refiere a https://www.openssl.org/docs/manmaster/crypto/RAND_egd.html? Si es así, de nuevo; ¿Por qué querría agregar entropía desde una fuente de espacio de usuario? ¿Cuáles son exactamente los casos de uso?

EGD el protocolo es implementado por varios programas que recolectan o distribuyen entropía, por ejemplo, VM de baja entropía que obtienen su estado inicial de un RNG de hardware en la red.

Bien. No es un tenedor tradicional.

De hecho, no lo es. Que OpenSSL no sea seguro para la bifurcación no es relevante porque el nodo no se bifurca.

Si recuerda el resumen del documento al que se hizo referencia anteriormente, ese es exactamente el problema en cuestión:

Consulte https://github.com/nodejs/node/issues/5798#issuecomment -209326548 - si cree que mi comprensión del documento y por qué creo que el nodo no se ve afectado es incorrecta, explíquelo en detalle.

/ dev / urandom es ciertamente una mejor opción que un OpenSSL PRNG roto, ¿no lo crees?

El contexto lo es todo. El código que pegó las semillas Math.random () de V8 y la semilla de la tabla hash. Si pensaba que tenía algo que ver con el módulo de cifrado, no es así.

Supongo que es consciente de esto, pero Math.random () no es criptográficamente fuerte, es solo un simple PRNG. La semilla hash es para mitigar los ataques de colisión de tablas hash, principalmente para colisiones de clave de cadena en objetos JS en modo diccionario.

Si el nodo no anuló los valores predeterminados, V8 intentará abrir / dev / urandom pero felizmente continuará con una entropía casi cero si falla, lo cual, según el contrato de Math.random (), es perfectamente aceptable.

La situación en Windows era aún peor en el momento de escribir este artículo (los procesos generados con un segundo de diferencia generarían los mismos números aleatorios) y aún no es genial: usa rand_s / RtlGenRandom, que no pretende ser muy aleatorio. Una vez más, perfectamente aceptable pero no exactamente genial.

Sabiendo lo que sabe ahora, ¿no estaría de acuerdo en que el RNG de OpenSSL es mejor?

Permítanme concluir diciendo que todos los criptógrafos e ingenieros de software de seguridad que he hablado y la mayoría de los idiomas prefieren sembrar directamente desde urandom.

La siembra desde / dev / urandom (y / dev / random y / dev / srandom) es exactamente lo que hace OpenSSL. ¿Por qué entonces lo consideras tan roto?

En futuras versiones de Linux Kernel / dev / urandom contará con una construcción DRBG basada en ChaCha20 similar a la de arc4random de OpenBSD.

Ya he comentado sobre eso antes, pero para reiterar: eso no ayuda mientras todavía admitimos 2.6.18 y 2.6.32. No se aceptan regresiones de rendimiento en núcleos más antiguos.

¿Puedo preguntar por qué está utilizando específicamente el RNG de OpenSSL? Incluso algunos de sus mantenedores me dijeron "no lo use".

Le agradecería si pudiera respaldar esa afirmación con nombres y lugares. Nunca escuché a ninguno de los desarrolladores de OpenSSL afirmar eso públicamente.

EGD el protocolo es implementado por varios programas que recolectan o distribuyen entropía, por ejemplo, VM de baja entropía que obtienen su estado inicial de un RNG de hardware en la red.

¿Puede agregar una referencia a esa declaración? ¿A qué te refieres exactamente?

De hecho, no lo es. Que OpenSSL no sea seguro para la bifurcación no es relevante porque el nodo no se bifurca.

¿Ha leído más abajo? Mi punto es que el nodo se basa en libuv, libuv usa subprocesos, OpenSSL no es seguro para subprocesos. También es bastante fácil producir una bomba de horquilla con nodo usando spawn() en modo separado.

El contexto lo es todo. El código que pegó las semillas Math.random () de V8 y la semilla de la tabla hash. Si pensaba que tenía algo que ver con el módulo de cifrado, no es así.

¿Contexto? El código que pegué tiene un comentario sobre él que dice que usa /dev/urandom ¿por qué se generaría desde Math.random() ? Eso es una locura dado que es su interfaz de cifrado principal. Me refiero a https://github.com/nodejs/node/blob/master/src/node_crypto.cc#L268-275 - si esta no es su fuente de entropía, ¿dónde está?

Si el nodo no anuló los valores predeterminados, V8 intentará abrir / dev / urandom pero felizmente continuará con una entropía casi cero si falla, lo cual, según el contrato de Math.random (), es perfectamente aceptable.

No entiendo esta oración. Y /dev/urandom no bloquea ni "se queda sin entropía" en ningún sentido que sea relevante para la seguridad de nodejs.

Sabiendo lo que sabe ahora, ¿no estaría de acuerdo en que el RNG de OpenSSL es mejor?

No. Eche un vistazo a libsodium .

La siembra desde / dev / urandom (y / dev / random y / dev / srandom) es exactamente lo que hace OpenSSL. ¿Por qué entonces lo consideras tan roto?

Debido a que no se detiene allí, se siembra a partir de él y luego se mezcla en la "entropía" de la tierra del usuario que puede manipularse fácilmente, por lo tanto, produce una salida predecible. Vea el último enlace en mi comentario anterior. Hay muchos otros ejemplos.

Ya he comentado sobre eso antes, pero para reiterar: eso no ayuda mientras todavía admitimos 2.6.18 y 2.6.32. No se aceptan regresiones de rendimiento en núcleos más antiguos.

Estoy absolutamente de acuerdo con eso. Estos son parches en los que se está trabajando en este momento, no estarán disponibles por un tiempo. ¿Puede explicar qué regresiones de rendimiento está experimentando específicamente en kernels más antiguos?

Le agradecería si pudiera respaldar esa afirmación con nombres y lugares. Nunca escuché a ninguno de los desarrolladores de OpenSSL afirmar eso públicamente.

No lo he hecho a propósito, pensé que era obvio. ¿Por qué crees que tanto LibreSSL como BoringSSL (que ahora alimentan a todo Google, incluidas las aplicaciones de escritorio [por ejemplo, Chrome], etc.) se han cambiado a otros diseños de RNG?

OpenSSL no es seguro para subprocesos

Esto está mal.

También es bastante fácil producir una bomba de horquilla con nodo usando spawn () en modo separado.

Irrelevante. ¿Por qué lo mencionas?

¿Contexto? El código que pegué tiene un comentario encima que dice que usa / dev / urandom ¿por qué se generaría desde Math.random ()?

Creo que debería volver atrás y leer lo que escribí de nuevo (pista: no 'de'). Por favor, ponga más esfuerzo en sus respuestas, ¿quiere?

Debido a que no se detiene allí, se siembra a partir de él y luego se mezcla en la "entropía" de la tierra del usuario que puede manipularse fácilmente, por lo tanto, produce una salida predecible.

¿Puedes explicar? Si por 'manipular' te refieres a 'adjuntar con ptrace', entonces la salida predecible es la menor de tus preocupaciones. Si te refieres a 'errores de programa explotables', el kernel tampoco es ajeno a eso.

¿Puede explicar qué regresiones de rendimiento está experimentando específicamente en kernels más antiguos?

Intente leer desde / dev / urandom de varios procesos simultáneamente y verá lo que quiero decir. Es lento, muy lento, y puede tener un impacto dramático en el rendimiento general del sistema, no solo en los lectores.

No lo he hecho a propósito, pensé que era obvio.

Espero que entiendas que no seré capaz de aceptar tu palabra.

Esto se está volviendo improductivo, rápido.

Tengo mucho trabajo en mi plato en este momento, pero una vez que esté hecho, espere un parche para que podamos dejar de discutir el ámbito teórico.

El parche que estoy imaginando hará exactamente lo que hace libsodium 1.0.11 y más reciente (aún no lanzado):

  • Ventanas:

    • CryptGenRandom

  • OpenBSD:

    • getentropy()

    • arc4random_buf()

  • Linux:

    • Si getrandom(2) está disponible, utilícelo

    • De lo contrario:

    • Encuesta /dev/random hasta que esté disponible para ser leído. Esto nos dice que el urandom está sembrado y, por lo tanto, es seguro de usar sin tener en cuenta la "entropía agotada".

      La única razón por la que me molesto con esto es la posibilidad distinta de cero de que alguien escriba aplicaciones Node.js que puedan competir contra el proceso de arranque de Linux. Si esto no es una preocupación, rechazaré este paso.

    • Leer desde /dev/urandom

  • Otros BSD (también OS X):

    • Simplemente lea /dev/urandom , porque se bloquea hasta que se inserta (como debería hacer Linux, pero no lo hace)

@azet
Varias correcciones, para aclarar el malentendido aquí:

  1. No OpenSSL no es seguro para subprocesos, pero algunas partes de él (incluido el generador de números aleatorios).
  2. El hecho de que el nodo use libuv, que libuv tenga un grupo de subprocesos y ese nodo use OpenSSL RAND_bytes() por crypto.randomBytes() _no implica_ que las llamadas a crypto.randomBytes() se realicen desde el grupo de subprocesos .

_Actualización: _ He cometido un error aquí, consulte la explicación a continuación: https://github.com/nodejs/node/issues/5798#issuecomment -222373530.

@ paragonie-scott Gracias. Sin embargo, no estoy seguro de extraer la abstracción de la plataforma aquí en lugar de una dependencia (openssl o libuv, por ejemplo). Además, lo que propuso afectará la velocidad y puede causar una caída significativa del rendimiento en Linux, lo cual es malo incluso desde el lado de la seguridad. Sin embargo, quizás necesitemos pruebas.

@bnoordhuis

Esto está mal.

No, no es. ¿Qué versión de OpenSSL usa nodejs? git-master? Eche un vistazo al historial de confirmaciones en general del RNG en cuestión: https://github.com/openssl/openssl/commits/master/crypto/rand/md_rand.c

La nueva API de subprocesos se agregó a 1.1.0-pre5 el 8 de marzo de este año: https://github.com/openssl/openssl/commit/8eed7e873bb54ab46b15e6efa3aff416e02f4d7f

Antes de eso, tenía que llamar explícitamente CRYPTO_set_locking_callback algo que no sabía que el nodo estaba haciendo con el OpenSSL RNG. ¿Quizás me estoy perdiendo algo?

Creo que debería volver atrás y leer lo que escribí de nuevo (pista: no 'de'). Por favor, ponga más esfuerzo en sus respuestas, ¿quiere?

Entonces, ¿siembra de urandom y se mezcla en Math.random ()? Sigue siendo un diseño completamente inaceptable.

Intente leer desde / dev / urandom de varios procesos simultáneamente y verá lo que quiero decir. Es lento, muy lento, y puede tener un impacto dramático en el rendimiento general del sistema, no solo en los lectores.

Soy consciente de que / dev / urandom está actualmente lento. Ese no es el punto. Como se sugirió anteriormente: eche un vistazo a libsodium , solo usa random / urandom como semilla. Las versiones más recientes de OpenSSL han mejorado mucho, pero muchos sistemas no incluyen versiones de última generación.

Espero que entiendas que no seré capaz de aceptar tu palabra.

Seguro. Nuevamente: mire su registro de confirmación, los de BoringSSL, etcétera. No voy a nombrar a los desarrolladores. - Ni siquiera importa, el desarrollo y los cambios son públicos.

Por cierto: todavía estoy esperando una respuesta sobre EGD, no estoy seguro de a qué te refieres.

@ChALkeR

El hecho de que el nodo use libuv, que libuv tenga un grupo de subprocesos y que el nodo use OpenSSL RAND_bytes () para crypto.randomBytes () no implica que las llamadas a crypto.randomBytes () se realicen desde el grupo de subprocesos.

Gracias por la información. Entonces, ¿cómo funciona si varios procesos secundarios quieren leer desde crypto.randomBytes() ?

@azet cada proceso hijo comienza desde cero sin compartir nada excepto una posible entrada / salida

// The only time when /dev/urandom may conceivably block is right after boot,
// when the whole system is still low on entropy.  That's not something we can
// do anything about.

Independientemente del resto de la discusión, esto es objetivamente incorrecto. / dev / urandom no bloquea. Detesto referirme a la página de manual generalmente pobre, pero de random (4):

A read from the /dev/urandom device will not block waiting for more entropy.  If there is not sufficient entropy, a pseudorandom number generator is used to create the requested bytes

/dev/urandom nunca bloquear es solo un problema para los programas que pueden ejecutarse durante el proceso de arranque del kernel de Linux y los dispositivos integrados. Hay dos soluciones para esto:

  1. Si getrandom(2) está disponible, utilícelo y abandone el urandom. Esto hace lo correcto: bloquea hasta que haya suficiente entropía disponible, luego nunca vuelve a bloquear. También es inmune al agotamiento del descriptor de archivo, por lo que es la solución preferida.
  2. Encuesta /dev/random hasta que esté disponible, y luego lee desde /dev/urandom para siempre. Linux siembra el grupo de entropía de desbloqueo (urandom) antes del grupo de bloqueo. Esto significa que una vez que pueda sondear con éxito /dev/random , entonces /dev/urandom se ha sembrado con al menos 128 bits de entropía. A continuación, puede leer con seguridad desde urandom sin ninguna preocupación en el mundo.

Nunca es aceptable leer desde /dev/random y usar algo hacky como egd o haveged para "alimentar entropía" al sistema.

@indutny

cada proceso hijo comienza desde cero sin compartir nada excepto una entrada / salida posiblemente estándar. Entonces solo siembra la entropía del RNG del kernel.

Gracias por la explicación, y probé esto en una máquina de 12 núcleos / 2 hilos y 128 GB durante la noche. Y parece estar bien dada una versión de OpenSSL reciente y bien mantenida (debian jessie). Por cierto, la única razón por la que este es el caso, por lo que puedo decir, es que se agregó https://github.com/openssl/openssl/commit/3cd8547a2018ada88a4303067a2aa15eadc17f39 en 2013 para mitigar un problema en Android. Con versiones anteriores, es posible que aún haya sido posible explotar el problema de superposición de PID y la seguridad de subprocesos inexistente en el RNG, si no me equivoco.

La cosa es, como se explicó antes, según su mecanismo de siembra, si RAND_bytes devuelve cualquier cosa menos -1 (es decir, 0 para baja entropía o p. Ej. Un estado RNG de usuario roto) - si entiendo a @bnoordhuis correctamente, el respaldo sería una semilla de urandom que se mezcla en Math.random() que es un diseño completamente inaceptable y predecible, no importa que la semilla sea de buena calidad en este caso. En su lugar, simplemente acepta el estado RNG roto, que también es completamente loco.

@technion

Independientemente del resto de la discusión, esto es objetivamente incorrecto. / dev / urandom no bloquea.

Estoy de acuerdo.

@ paragonie-scott

/ dev / urandom nunca bloquear es solo un problema para los programas que pueden ejecutarse durante el proceso de arranque del kernel de Linux y los dispositivos integrados.

A menos que esté planeando ejecutar el nodo en initramfs, realmente no hay razón para pensar en eso. En cuanto a los dispositivos integrados: depende en gran medida, esto suele ser un error del fabricante. Todavía tienen fuentes de ruido e interrupciones, alguien simplemente se olvidó de configurar el kernel correctamente o enviar un parche. En cualquier caso, esto no es nada sobre lo que el propio nodo pueda hacer, es un problema de flujo ascendente adecuado. No me gusta la idea de la encuesta, getrandom(2) está perfectamente bien ya que es la nueva interfaz en Linux, pero como tal: no está disponible en todas partes. En lugar de escribir su propia solución, le sugiero que importe sysrandom de libsodium. Este es un código examinado que funciona.

Nunca es aceptable leer desde / dev / random y usar algo hacky como egd o haveged para "alimentar entropía" al sistema.

Exactamente. Y, por lo tanto, no estoy seguro de a qué se refiere @bnoordhuis . Todos estos han quedado obsoletos, la interfaz OpenSSL es antigua y se ha eliminado su soporte.

En lugar de escribir su propia solución, le sugiero que importe sysrandom de libsodium. Este es un código examinado que funciona.

Acordado. Previamente porté una parte significativa de la libsodium sysrandom a 7 de PHP random_bytes() . Tenía la intención de hacer lo mismo aquí.

@azet
Por cierto, cometí un error en el comentario anterior. De hecho, las solicitudes a RAND_bytes provienen del grupo de subprocesos si se especifica la devolución de llamada. Sin embargo, OpenSSL rng no es seguro para subprocesos solo a menos que la seguridad de subprocesos esté garantizada con CRYPTO_set_locking_callback (consulte https://wiki.openssl.org/index.php/Random_Numbers#Thread_Safety) y algunos bits más. Node.js los está haciendo desde https://github.com/nodejs/node/commit/97cada0e6a130791ceafaa750f9009d8fdaaadbb.

Además, OpenSSL RAND_bytes no es seguro para la bifurcación, pero eso no nos afecta, porque Node.js no se bifurca, ejecuta nuevas instancias.

Un poco tarde para la fiesta, pero si esto ayuda, la gente de Chromium tuvo una discusión similar sobre los CSPRNG. Si lo leí correctamente, descartaron RC4 / ARC4 de OpenBSD para fuentes de espacio de kernel.

La implementación actual (como se aclara aquí ) parece tomar la entropía basada en hardware, si está disponible, antes de volver a ser independiente urandom . Específicamente, prueba la presencia de RDRAND Intel's Digital Random Number Generator (DRNG) y, si está disponible, lo combina con urandom y ChaCha20.

Creo que esto es similar a lo que @ paragonie-scott pretende parchear, pero no estoy seguro de si se han abordado las fallas de RC4.

Gracias a todos por hacer todo lo posible para mantenernos seguros. 👍

Editar : Intel ya no lo llama RDRAND por varias razones. ;)

Parece que Linux urandom ahora estará basado en ChaCha20: http://lkml.iu.edu/hypermail/linux/kernel/1607.3/00275.html

(Relacionado libremente): otra prng del espacio de usuario ha caído:
https://lists.gnupg.org/pipermail/gnupg-announce/2016q3/000395.html

/ cc @saghul : ¿algo como https://github.com/nodejs/node/issues/5798#issuecomment -222329062 tendría sentido en libuv?

@ChALkeR Creo que sí. Además, estaba planeando hacerlo yo mismo, ya que implementé algo similar para otro proyecto no hace mucho tiempo.

La clave será documentar las garantías que prometemos. Intentaré hacer un breve resumen esta semana para que la conversación comience allí.

Aún no está 100% listo, pero los comentarios son más que bienvenidos: https://github.com/libuv/libuv/pull/1055

Para aquellos que creen que el /dev/urandom Linux no puede tener problemas de seguridad: https://www.schneier.com/blog/archives/2013/10/insecurities_in.html (y otros).

No he visto una sola razón convincente en este hilo para alejarme del PRNG de OpenSSL, es una capa de abstracción de plataforma sobre las fuentes de entropía específicas de la plataforma ... parece exactamente lo que queremos.

Además, es fácil quejarse de algún tipo de "baja calidad" percibida de OpenSSL, pero sugerir que el equipo de Node.js tiene una mejor experiencia criptográfica que sus desarrolladores, y que deberíamos estar escribiendo nuestra propia capa de abstracción PRNG es un poco frágil. , En mi opinión. Ciertamente no obtendríamos el escrutinio que ellos reciben.

Para aquellos que creen que / dev / urandom de Linux no puede tener problemas de seguridad: https://www.schneier.com/blog/archives/2013/10/insecurities_in.html (y otros).

Ese no es el argumento, en absoluto. El argumento es este:

  1. Todo su sistema operativo ya depende del CSPRNG del kernel (por ejemplo, /dev/urandom ) para ser seguro. Si eso es inseguro, todo su sistema está regado.
  2. Agregar un segundo espacio de usuario PRNG no crea una defensa en profundidad contra la falla del CSPRNG del sistema operativo, solo crea un punto adicional de falla .
  3. Dado que el PRNG del espacio de usuario de OpenSSL tiene muchos problemas (es decir, no es seguro para la bifurcación, lo que arruinó la seguridad de las aplicaciones PHP que dependían de su PRNG), hay más urgencia para salir de un PRNG del espacio de usuario a favor del CSPRNG del kernel. que si fuera un espacio de usuario PRNG mejor diseñado.

Ese es un argumento muy diferente al de "nunca habrá un defecto /dev/urandom ".

Varios expertos en seguridad han intervenido en este hilo. El consenso está unánimemente a favor de utilizar el CSPRNG del kernel sobre el espacio de usuario PRNG de OpenSSL.

No he visto una sola razón convincente en este hilo para alejarme del PRNG de OpenSSL

Vinculé varios artículos de investigación arriba. ¿Los leíste todos?

es una capa de abstracción de plataforma sobre fuentes de entropía específicas de la plataforma ... parece exactamente lo que queremos.

Si eso fuera cierto, no habría ninguna queja. Pero eso no es lo que está pasando bajo el capó. RAND_bytes() OpenSSL se siembra con 32 bytes de urandom, luego mantiene su propio estado PRNG interno (mezclado con SHA1 por defecto, pero el código admite la mezcla con MD5) y nunca vuelve a tocar el CSPRNG del kernel.

Lo que quieres es algo como el sysrandom de libsodium. @bascule escribió anteriormente una gema de Ruby, llamada sysrandom, que es un reemplazo seguro de SecureRandom de Ruby (nombre inapropiado, también usa OpenSSL).

Escribí sobre esto en una publicación de blog titulada apropiadamente, Cómo generar números aleatorios seguros en varios lenguajes de programación .

Además, es fácil quejarse de algún tipo de "baja calidad" percibida de OpenSSL, pero sugerir que el equipo de Node.js tiene una mejor experiencia criptográfica que sus desarrolladores, y que deberíamos estar escribiendo nuestra propia capa de abstracción PRNG es un poco frágil. , En mi opinión.

Tienes razón. Deberíamos usar libsodium's, que hace el trabajo mejor que cualquier otra implementación que haya visto.

Ciertamente no obtendríamos el escrutinio que ellos reciben.

Hasta el año pasado, me lo hubiera tomado como una broma, con Heartbleed y todo eso.

Agregar un segundo espacio de usuario PRNG no crea una defensa en profundidad contra la falla del CSPRNG del sistema operativo, solo crea un punto adicional de falla.

El espacio de usuario ofrece una defensa contra los problemas de bloqueo en urandom, como le han dicho, y es una de las objeciones a que OpenSSL cambie a la lectura directa de urandom.

Un PRNG bien construido no puede agregar entropía mágicamente, pero tampoco resta mágicamente.

El nodo que implementa su propia abstracción de plataforma para la entropía también agrega un punto adicional de falla no bien revisada, por lo que este punto no es convincente sin demostrar que OpenSSL actualmente tiene fallas de seguridad _que afectan el nodo_ y deben corregirse sin pasar por alto.

Dado que el PRNG del espacio de usuario de OpenSSL tiene muchos problemas (es decir, no es seguro para la bifurcación, lo que arruinó la seguridad de las aplicaciones PHP que dependían de su PRNG), hay más urgencia para salir de un PRNG del espacio de usuario a favor del CSPRNG del kernel. que si fuera un espacio de usuario PRNG mejor diseñado.

Irrelevante, el nodo no se bifurca, ¿por qué la gente sigue mencionando esto?

¿Hay otras críticas relevantes?

Varios expertos en seguridad han intervenido en este hilo.

Debe tener en cuenta que es imposible en este hilo distinguir entre expertos en seguridad y personas que simplemente los juegan en Internet. También que los expertos en seguridad _son_ contribuyentes a OpenSSL.

¿Quiénes crees que son los expertos en seguridad y por qué?

Aparte: suponiendo que no lo estemos haciendo ya, podría ser una buena idea agregar el paquete sodium a nuestras ejecuciones CITGM. No parece tener una tonelada de uso, pero sí una cantidad decente, y parece exactamente el tipo de cosas que podrían ayudarnos a encontrar algunos casos de esquina inusuales. (Además, estoy seguro de que les estaríamos haciendo un favor a los mantenedores si identificamos plataformas inusuales donde el módulo no funciona o les notificamos con anticipación que una próxima versión de Node.js romperá su paquete). / ping @TheAlphaNerd

¿Quiénes crees que son los expertos en seguridad y por qué?

En ningún orden _particular_:

  • Dan J Bernstein, profesor de criptografía que ayudó a traernos:

    • Salsa20

    • ChaCha20

    • Poli1305

    • X25519 sobre Curve25519

    • SipHash

  • Tanja Lange, quien es la profesora que encabeza las iniciativas mundiales de investigación en criptografía post-cuántica.
  • Thomas Ptacek (@tqbf), que dirigió una empresa de pruebas de penetración de aplicaciones / criptomonedas durante años y basó su publicación de blog "use urandom" en la difícil situación y el conocimiento de los expertos de la industria que usted y yo no podemos simplemente hacer clic para hacer una pregunta rápida sin escribir primero un contrato de $ X0,000
  • Matthew D Green (@matthewdgreen), profesor de criptografía conocido por el ataque de falsificación de iMessage, la auditoría TrueCrypt y el proyecto zcash
  • Daira Hopwood (@daira), por su trabajo en proyectos como SPHINCS y zcash
  • JP Aumasson (@veorq), quien ayudó a traernos (entre otras cosas):

    • BLAKE y BLAKE2

    • SipHash

    • NORX (participación de la tercera ronda del CAESAR, que creo que será finalista)

  • Anthony Ferrara (@ircmaxell) quien:

    • Escribió la biblioteca de hash de contraseñas utilizada por PHP

    • Ha contribuido con muchos consejos prácticos de seguridad para varios proyectos de código abierto, además de proporcionar una gran cantidad de respuestas correctas de StackOverflow sobre cripto / seguridad.

  • Aaron Zauner (@azet), cuyas contribuciones en Github son independientes
  • Steve Weis (@sweis), con quien me topé antes de informar sobre ataques de texto cifrado elegido en aplicaciones móviles de "mensajería cifrada"
  • Filippo Valsorda (@FiloSottile), quien descubrió Heartbleed pero también ha publicado muchas otras estupendas investigaciones sobre criptografía, incluido un exploit práctico de Bleichenbacher'06 contra una implementación de RSA en Python. (EDITAR: estaba equivocado en este punto).
  • Solar Designer (@solardiz), un investigador de seguridad ampliamente conocido

Además, considero que vale la pena mencionar a muchas personas que considero colegas porque:

  1. Investigan estos temas
  2. Si me equivoco, lo dirán

Y entonces la lista se expande para incluir:

  • Sven Slootweg (@ joepie91)
  • Taylor Hornby (@Defuse)
  • Adam Caudill (@adamcaudill)
  • Aaron Toponce (@atoponce)
  • Alfie (@alfiepates)
  • Zofrex (@zofrex)

No dude en preguntarle a cualquiera de esa lista si prefiere el espacio de usuario PRNG de OpenSSL o el CSPRNG del kernel del sistema operativo para fines de criptografía. Te garantizo que obtendrás el 100% a favor del urandom (y el equivalente urandom).

Siéntase libre de intentar encontrar criptógrafos y expertos en seguridad del mundo real para ofrecer una opinión disidente. En general, tendrá más éxito en encontrar personas que estén de acuerdo conmigo que en desacuerdo conmigo (solo en este punto en particular).

(Corregí un error en mi comentario anterior y quería hacer saber que probablemente hay entre 50 y 100 personas más que podría haber incluido allí también, pero la lista es lo suficientemente larga).

De acuerdo, también obtuve las opiniones de alguien que conozco que es un experto en seguridad (el requisito es un historial exitoso de _breaking_ sistemas), y están de acuerdo con usted (y lo conocen): la mejor práctica actual es la lectura directa de O / S fuentes de entropía.

Sin embargo, si eso es lo mejor para Node.js, no está tan claro, hay otros factores a considerar.

  1. ¿Se propone modificar solo crypto.randomBytes() , o también reemplazar la fuente de entropía utilizada durante los intercambios SSL / TLS por OpenSSL? Si no hacemos que la implementación HTTPS de OpenSSL / Node.js omita el espacio de usuario PRNG, entonces no obtendremos una victoria para los casos de uso comunes de Node.js.
  2. Siguiendo con eso ... si OpenSSL cambia en sentido ascendente para hacer lectura directa (como parecen tener interés en hacerlo) ... entonces podemos aprovechar eso tanto para HTTPS como para crypto.randomBytes() sin trabajo (que no sea una actualización de OpenSSL).
  3. El rendimiento sigue siendo una preocupación. En ausencia de una vulnerabilidad actual en OpenSSL, obtendríamos una ventaja de seguridad teórica, pero perderíamos el rendimiento real. Esto debería abordarse. Quizás convenciéndonos a nosotros mismos de que el rendimiento de HTTPS no se ve afectado y que crypto.randomBytes() no se usa lo suficiente como para que nos preocupemos (o nos demos cuenta).
  4. El mantenimiento sigue siendo una preocupación. Si Node asume la carga de mantener una capa de abstracción para la recolección de entropía del sistema, nuestro código de abstracción podría convertirse en el nuevo eslabón más débil en la cadena de aleatoriedad. Mientras que si lo subimos a OpenSSL (o incluso a libsodium), podemos beneficiarnos de su trabajo. Traer un subdepósito completamente nuevo (libsodium) es un precio alto para simplemente eliminar un problema teórico.

1, 2 y 4: RAND_system_bytes() no está implementado a partir de 1.1.0 (que se acaba de lanzar), y estaremos esperando un rato hasta que salga la 1.2.0. Pero arreglarlo en OpenSSL en lugar de en cada idioma sería la solución ideal.

3: Si los dos están en conflicto, la seguridad debe tener prioridad sobre el rendimiento cuando se trata de criptografía. Sin embargo, una penalización significativa en el rendimiento solo invita a los ataques DoS (que es un problema de seguridad). Así que estoy de acuerdo, esto debería abordarse.

Arreglar el problema en sentido ascendente sería la mejor solución (ya que pagaría por muchos lenguajes de programación), pero en ausencia de una solución ascendente, ¿qué hacemos?

A. ¿Seguir usando un PRNG de espacio de usuario y no exponer una interfaz CSPRNG alternativa?
B. ¿Arreglarlo en la capa de intérprete, como lo hizo PHP?

Eso lo debe decidir el equipo de Node. Estoy saltando sobre el repositorio de OpenSSL para discutir la preparación de un parche para exponer esta API en la próxima versión.

Me gustaría aclarar que, si bien libuv podría obtener esta API, no implementé
con este tema en mente. Nodo no necesita usarlo.

Además, incluso si el parche libuv aterriza mañana (lo que no sucederá
de todos modos) está dirigido a master, no a v1.x. Eso significa que, en principio,
será parte de libuv 2.0. Esto es intencional, por lo que tenemos un poco más
margen de maniobra para realizar cambios en caso de que se descubran problemas con la implementación.

El 16 de septiembre de 2016 a las 23:52, "Scott" [email protected] escribió:

1, 2 y 4: RAND_system_bytes () no está implementado a partir de 1.1.0 (que
fue lanzado), y estaremos esperando un tiempo hasta que salga 1.2.0.
Esa sería la solución ideal.

3: Si los dos están en conflicto, la seguridad debe tener prioridad sobre
rendimiento en lo que respecta a la criptografía. Sin embargo, una significativa
la penalización de rendimiento solo invita a los ataques DoS (que es un problema de seguridad).
Así que estoy de acuerdo, esto debería abordarse.

Solucionar el problema en sentido ascendente sería la mejor solución (ya que pagaría
reenviar a muchos lenguajes de programación), pero en ausencia de un
solución upstream, ¿qué hacemos?

A. Siga usando un PRNG de espacio de usuario y no exponga un CSPRNG alternativo
¿interfaz?
B. ¿Arreglarlo en la capa de intérprete, como lo hizo PHP?

Eso lo debe decidir el equipo de Node. Estoy saltando sobre el OpenSSL
repositorio para discutir la preparación de un parche para exponer esta API en el próximo
versión.

-
Recibes esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/nodejs/node/issues/5798#issuecomment -247717511, o silenciar
la amenaza
https://github.com/notifications/unsubscribe-auth/AATYGKYZE_uzOGuvyEgLZUs257XOxBJyks5qqw-UgaJpZM4H0YGk
.

@ sam-github: ¿Se propone modificar solo crypto.randomBytes () o también reemplazar la fuente de entropía utilizada durante los intercambios SSL / TLS por OpenSSL? Si no hacemos que la implementación HTTPS de OpenSSL / Node.js omita el espacio de usuario PRNG, entonces no obtendremos una victoria para los casos de uso comunes de Node.js.

Solo quiero señalar aquí que hay muchos casos de uso _no-HTTPS_ comunes para crypto.randomBytes en el nodo, desde la generación de UUID hasta otras implementaciones de cifrado (no OpenSSL), hasta la selección de números aleatorios de tipo lotería, etcétera. Incluso _si_ el problema quedara sin resolver para HTTPS, todavía habría una clara victoria en otras áreas.

Para @ joepie91 , he visto una implementación de UUID v4 que usa math.random, así que sí, un valor predeterminado seguro que se extraiga de la entropía del sistema sería fantástico.

Como otro ejemplo del uso de crypto.randomBytes () en una configuración que no es HTTPS, lo estoy usando en un generador de contraseñas: https://github.com/atoponce/nodepassgen.

ping @ nodejs / crypto ... ¿debería permanecer abierto?

No, cerremos.

este problema sigue sin resolverse y ha habido una valiosa discusión sobre cómo resolver el problema.
problemas similares en, por ejemplo, ruby, conducen a cambiar a enfoques similares a libsodium: https://bugs.ruby-lang.org/issues/9569

La implementación de OpenSSL permanece, que yo sepa, en gran parte sin probar y específicamente optimizada para satisfacer las necesidades de implementación de TLS para números aleatorios rápidos. la mayoría de los lenguajes (por ejemplo, python) optan por usar el dispositivo /dev/urandom en las distribuciones de Linux. libsodium es consciente de la plataforma y evita la sobrecarga de manipular y mantener rutas de código específicas de distribución. libsodium también ha sido revisado y es utilizado por muchas personas y proyectos para proporcionar una capa de abstracción para obtener números pseudo aleatorios criptográficamente seguros.

Insto al equipo central a utilizar la forma revisada de libsodium, compatible con la plataforma, para obtener números pseudoaleatorios seguros: https://github.com/jedisct1/libsodium/blob/master/src/libsodium/randombytes/randombytes.c

Vuelva a abrir este problema de seguridad relevante.

¿Cuál fue el motivo para cerrar este tema?

Si lo entiendo correctamente (que es un gran "si" cuando se trata de criptografía y problemas relacionados):

Especialmente dada la actividad en https://github.com/openssl/openssl/issues/898 bastante recientemente, y ese progreso allí podría significar una solución adecuada aquí que aún puede usar las API de OpenSSL, estaría a favor de mantener esto abierto.

@ nodejs / crypto Creo que deberíamos mantenerlo abierto hasta que se solucione. La última discusión fue que OpenSSL ellos mismos se estaban moviendo en esta dirección, y esperábamos simplemente heredar su solución. De https://github.com/openssl/openssl/issues/898 , de hecho parece que están avanzando (lentamente, pero con un progreso reciente). Pero si OpenSSL 1.1 no cambia esto, podríamos revisar si el nodo debería usar alguna otra forma de obtener pseudoaleatorio.

Como un puñado de personas (incluidos los colaboradores) han intervenido acerca de querer continuar la discusión. Estoy reabriendo

Dicho esto, creo que esto podría ser parte de una conversación más amplia sobre openssl ... ¿quizás podamos buscar mejorar su implementación en sistemas que tienen soporte?

afaict libsodium no se podrá iniciar si no tiene soporte para fips

afaict libsodium no se podrá iniciar si no tiene soporte para fips

Reemplazar OpenSSL por completo con Libsodium podría no ser un comienzo.

¿Es el cumplimiento de FIPS-140-2 un requisito obligatorio absoluto? Porque el modo ECB es compatible con FIPS, y seguro que no quiere que la gente se encripte de esa manera.

Cualquier cambio en OpenSSL, incluso si mejora en este espacio, se mostrará en una nueva versión principal, que se mueve mucho, mucho más lento que Node. Si hicieron un gran lanzamiento mañana, tomará años llegar a algunas distribuciones. No siento que quieras esperar por esto.

Si hicieron un gran lanzamiento mañana, tomará años llegar a algunas distribuciones.

Node.js no usa el OpenSSL del sistema operativo. Node.js se envía con su propia copia de OpenSSL .

Podría estar abierto a empaquetar libsodium además de openssl, pero ese debería ser su propio problema porque habrá numerosos detalles para discutir.

Estamos seguros de que no vamos a enviar algo de cosecha propia y hasta que openssl crezca las API necesarias, no hay nada procesable. Estoy cerrando esto de nuevo y lo estoy bloqueando para evitar que este hilo ya enorme se haga más grande.

@MylesBorins Re: cumplimiento de FIPS: si libsodium randombytes.c no es compatible y si se desea el cumplimiento de FIPS, eso podría arreglarse con una marca de tiempo de ejecución que cambie el impl a OpenSSL (ya que no dejaremos de empaquetar OpenSSL de todos modos ). Además, vea este enlace .

Tenga en cuenta que openssl 1.1 no será compatible con FIPS durante bastante tiempo, por lo que los usuarios de FIPS deberán ceñirse a un nodo construido en 1.0. cf. https://www.openssl.org/blog/blog/2016/07/20/fips/

Todavía tengo la esperanza de que OpenSSL se encargue de esto por nosotros, no estoy diciendo que debamos estar pensando en libsodium para 8.x, pero no creo que FIPS sea un bloqueador _si_ buscamos un PRNG en otra parte. Además, no estoy seguro de que las semillas aleatorias estén cubiertas por FIPS, de todos modos, eso requeriría un poco de investigación.

Tenga en cuenta que OpenSSL acaba de obtener un compromiso para usar DRGB con AES-CTR de NIST SP 800-90A como https://github.com/openssl/openssl/commit/75e2c877650444fb829547bdb58d46eb1297bc1a. Podemos usarlo con la fuente de siembra específica del sistema operativo (por ejemplo, / dev / urandom) mediante un indicador de definición predeterminado de OPENSSL_RAND_SEED_OS .
Creo que es mejor para nosotros esperar a la próxima versión de OpenSSL-1.1.1.

[Argumentos editados a favor y en contra basados ​​en comentarios]

Voy a intentar resumir la conversación y los argumentos que han ocurrido sobre este tema. Lo siento si me perdí tu publicación, puedo enmendarla.

Preliminares

@speakeasypuncture inicialmente abrió este problema.
Según @ joepie91 , este problema es sobre crypto.randomBytes Node. ( Declaración ).

Declaración de emisión

El crypto.randomBytes del nodo puede no ser criptográficamente seguro.

  • Los sistemas operativos exponen un "sistema" RNG (Generador de números pseudoaleatorios criptográficamente seguro o CSPRNG) que ofrece la mejor fuente de aleatoriedad en el sistema.
  • En lugar de utilizar el sistema RNG, Node.js se basa en OpenSSL por crypto.randomBytes .
  • OpenSSL no puede ser más seguro que el sistema RNG y puede ser menos seguro. El uso de OpenSSL de un CSPRNG de espacio de usuario sobre el CSPRNG del kernel es innecesario y simplemente agrega una capa de vulnerabilidad.

No creo que nadie haya afirmado que el CSPRNG de OpenSSL esté roto actualmente, aunque @ChALkeR señaló algunas razones por las que podría no ser confiable.

Propuesta

Node debe considerar una implementación alternativa para números aleatorios que definitivamente se deriva de forma segura.

  1. @azet dice que libsodium es una mejor opción para números aleatorios que OpenSSL, porque libsodium se sometió a una revisión.
  2. @FiloSottile aquí y @ircmaxell aquí agregan que evitar la dependencia de un CSPRNG de espacio de usuario, ya sea derivado de un CSPRNG de kernel o no, reduciría la superficie de ataque de Node.

Argumentos en contra

Los principales argumentos de los mantenedores de Node (y puede que esté leyendo un poco entre líneas) parecen ser:

  • @bnoordhuis aquí y @ sam-github aquí : si la seguridad de Node se rompe debido a problemas en OpenSSL, parece que la respuesta correcta es buscar mejoras en OpenSSL. @shigeki dice aquí que se están realizando esfuerzos en este sentido.
  • Inercia del código. La implementación basada en OpenSSL funciona. Cambiar la implementación a una derivada de otra biblioteca significa invertir tiempo y energía en el desarrollo y mantenimiento.

Presión de grupo

  • @azet dijo que Python usa el sistema CSPRNG en lugar de un CSPRNG de espacio de usuario.
  • @ paragonie-scott señaló la implementación de PHP ( enlace ), y @azet señaló a Ruby's .
  • @bnoordhuis indicó que implementar la lógica PRNG en Node directamente parecía indeseable.

Mis impresiones

  • Parece poco probable que esta propuesta resulte en movimiento por parte de los mantenedores de Node hasta que la API de OpenSSL esté disponible.
  • Parece que la adopción de libsodium conduciría a una rotación de código innecesaria porque la API de OpenSSL está en camino, aunque quizás lentamente.
  • Mientras tanto, si los desarrolladores preocupados por la seguridad no confían en OpenSSL, pueden usar un módulo npm o un complemento que acceda directamente a fuentes de aleatoriedad específicas de la plataforma.

Existe una propuesta ascendente para hacer que OpenSSL cree el equivalente de randombytes_sysrandom() de libsodium (que usa el CSPRNG del sistema operativo) que Node podría usar en lugar del espacio de usuario PRNG. Esto no vale la pena, está estancado hasta que OpenSSL haga algo.

Cambiar un PRNG de espacio de usuario por otro PRNG de espacio de usuario no es una solución. Pasar por alto el espacio de usuario y utilizar el CSPRNG del sistema operativo es la solución.

Esto no vale la pena, está estancado hasta que OpenSSL haga algo.

No es procesable en este momento y no lo será por mucho tiempo. Los elementos inactivos obstruyen el rastreador de errores, así que cerraré esto por ahora. Podemos volver a visitar cuando actualizamos a una versión de openssl que admita esta nueva API.

@bnoordhuis ¿Cómo vamos a recordar volver a visitarlo, entonces?

¿Quizás es necesario introducir una etiqueta separada para los elementos inactivados temporalmente que se cerraron solo por eso, para que no olvidemos volver a visitar?

Repasamos el registro de cambios con un peine de dientes finos cada vez que actualizamos (al menos yo lo hago), por lo que es poco probable que tal cambio pase desapercibido.

¿Quizás es necesario introducir una etiqueta separada para los elementos inactivados temporalmente que se cerraron solo por eso, para que no olvidemos volver a visitar?

No me opongo completamente.

Gracias por resumir, pero no creo que eso capte el punto. No estamos abogando por volver a implementar algo que está en una biblioteca (por el motivo que sea), sino por eliminar la biblioteca por completo. La biblioteca implementa un CSPRNG de espacio de usuario además de la entropía del kernel, puede ser bueno o malo, no importa, estamos defendiendo no usar uno en absoluto.

Lo que dices es válido sobre las primitivas, que deben implementarse en algún lugar, pero aquí estamos hablando de eliminar una capa de un sistema, donde cada capa es un punto de falla independiente.

En cuanto a "ellos son los que saben sobre seguridad", OpenSSL está sujeto a una gran cantidad de legado, BoringSSL y libsodium son ampliamente considerados como implementaciones modernas seguras, y esos usan el kernel CSPRNG.

@FiloSottile Gracias, modifiqué mi publicación. Grita si aún no estás satisfecho con mis declaraciones.

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

srl295 picture srl295  ·  3Comentarios

stevenvachon picture stevenvachon  ·  3Comentarios

mcollina picture mcollina  ·  3Comentarios

willnwhite picture willnwhite  ·  3Comentarios

danielstaleiny picture danielstaleiny  ·  3Comentarios