password online example ejemplo desencriptar decrypt java performance spring-mvc spring-security bcrypt

java - online - Deterioro del rendimiento de BCrypt



desencriptar bcrypt java (2)

Tenemos tres aplicaciones web (estándar Spring MVC-Hibernate) que se ejecutan dentro de un servidor Jboss 6.1. Las tres aplicaciones comparten un método de autenticación común que se compila como un JAR y se incluye dentro de cada archivo WAR. Nuestro método de autenticación utiliza org.springframework.security.crypto.bcrypt.BCrypt para hacer hash de las contraseñas de los usuarios, consulte a continuación:

hashedPassword.equals(BCrypt.hashpw(plainTextPassword, salt));

Opciones de inicio de JBOSS

set "JAVA_OPTS=-Xms2048m -Xmx4096m -XX:PermSize=256m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -verbosegc -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:gc.txt -XX:+UseParallelOldGC

Problema: parece que cuando se reinicia el servidor, Bcrypt.hashpw tarda 100 ms en descifrar la contraseña. Sin embargo, después de algún tiempo (no hay patrón), de repente, el rendimiento de Bcrypt.hashpw aumenta de 100 ms a 10 segundos. No hay ninguna razón obvia para esto.

Más información:

  • Versión Hibernate: 4.2.4.Final
  • Versión de primavera: 4.0.5.RELEASE Primavera
  • Versión de seguridad: 3.2.4.RELEASE

¿Alguien más ha visto este problema antes?


Problema: parece que cuando se reinicia el servidor, Bcrypt.hashpw tarda 100 ms en descifrar la contraseña. Sin embargo, después de algún tiempo (no hay patrón), de repente, el rendimiento de Bcrypt.hashpw aumenta de 100 ms a 10 segundos. No hay ninguna razón obvia para esto.

El problema es que /dev/random veces bloquea y cuando lo hace parecerá ser aleatorio :) Lo más confuso es que al intentar probar cómo funciona, se enfrentará al Efecto Observador, es decir, al intentar observar un comportamiento aleatorio. estás generando entropía y esto puede llevar a un montón de confusión, es decir, mis resultados no serán los mismos que los tuyos, etc. También es por esto que parece que no hay un patrón ...

Le demostraré el problema y le mostraré cómo recrearlo (dentro de lo razonable) en sus propios servidores para que pueda probar las soluciones. Intentaré proporcionar un par de soluciones, tenga en cuenta que esto está en Linux, pero el mismo problema ocurrirá en cualquier sistema que requiera entropía para generar números aleatorios y se agote.

En Linux /dev/random hay un flujo de bytes aleatorios. A medida que lees la secuencia, agotas la entropía disponible. Cuando alcanza un cierto punto lee desde /dev/random block. Puedes ver la entropía disponible usando este comando

cat /proc/sys/kernel/random/entropy_avail

Si ejecuta la siguiente secuencia de comandos bash y también supervisa entropy_avail , notará que la entropía se reduce drásticamente a medida que la secuencia de comandos bash la consume.

while : do cat /dev/random > /dev/null done

Esto también debería darle una pista sobre cómo volver a crear este problema en sus servidores, es decir, ejecutar el script de bash anterior para reducir la entropía disponible y el problema se manifestará.

Si desea ver cuántos bytes por segundo está creando su sistema, puede usar pv para medirlo, es decir,

pv /dev/random

Si deja que pv ejecute, tiene un efecto, está consumiendo el flujo aleatorio de bytes, lo que significa que otros servicios podrían comenzar a bloquearse. Tenga en cuenta que pv también está mostrando su salida, por lo que también podría estar aumentando la función de entrada disponible en el sistema :).

En sistemas con poca o ninguna entropía, pv /dev/random parecerá lento en el glaciar. También he experimentado que las máquinas virtuales a veces tienen problemas importantes con la generación de entropía.

Para recrear el problema usa la siguiente clase ...

import java.security.SecureRandom; import org.mindrot.jbcrypt.BCrypt; public class RandTest { public static void main(String[] args) { SecureRandom sr = new SecureRandom(); int out = 0; String password = "very-strong-password-1729"; String hashed; for (int i = 0; i < 200000 ; i++) { hashed = BCrypt.hashpw(password, BCrypt.gensalt()); //If we print, we''re generating entroy :) System.out.println(hashed); } } }

Descargué bcrypt a un directorio local. Lo compilé y lo ejecuté como sigue

javac -cp ./jBCrypt-0.4/src/ RandTest.java java -cp ./jBCrypt-0.4/src/:. RandTest

Si luego ejecuta la secuencia de comandos bash anterior mientras ejecuta RandTest , verá grandes pausas donde el sistema está bloqueando esperando más entropía. Si ejecutas strace verás lo siguiente ...

1067 [pid 22481] open("/dev/random", O_RDONLY|O_LARGEFILE) = 12 11068 [pid 22481] fstat64(12, {st_mode=S_IFCHR|0666, st_rdev=makedev(1, 8), ...}) = 0 11069 [pid 22481] fcntl64(12, F_GETFD) = 0 11070 [pid 22481] fcntl64(12, F_SETFD, FD_CLOEXEC) = 0 ..... 11510 [pid 22481] read(12, "/320/244/317RB/370", 8) = 6

El programa está leyendo desde /dev/random . El problema con la prueba de entropía es que puede estar generando más mientras intenta probarla, es decir, el efecto de observador.

Arreglos

La primera solución es cambiar de usar /dev/random a /dev/urandom es decir

time java -Djava.security.egd=file:///dev/./urandom -cp ./jBCrypt-0.4/src/:. RandTest

Una solución alternativa es recrear el dispositivo /dev/random como un dispositivo /dev/urandom . Puede encontrar cómo hacer esto desde la página de manual, es decir, en lugar de crearlas ...

mknod -m 644 /dev/random c 1 8 mknod -m 644 /dev/urandom c 1 9 chown root:root /dev/random /dev/urandom

eliminamos uno y lo falsificamos, es decir

rm /dev/random mknod -m 644 /dev/random c 1 9 chown root:root /dev/random

/dev/random ahora es en realidad /dev/urandom

La clave a recordar es que la prueba de datos aleatorios que requiere el ingreso desde el sistema que está probando es difícil debido al efecto de observador.


Una posible explicación es que el SeedGenerator de SecureRandom está causando los retrasos.

La implementación de Springs BCrypt uses SecureRandom que a su vez usa un SeedGenerator que a su vez puede usar el bloqueo /dev/random . Here hay una buena descripción de esas clases.

Ese informe de errores también informa sobre los problemas de rendimiento en BCrypt y los rastrea al generador de semillas, mostrando los stacktraces completos. La implementación de BCrypt es diferente, pero el seguimiento de pila por debajo de SecureRandom debe ser idéntico a la implementación de Spring. Su solución fue reducir la frecuencia de resiembra de BCrypt.