Prueba de trabajo como contraseña, ¿es una buena idea?

2

Nuestros usuarios inician sesión con nombre de usuario / contraseña y tienen una cookie que les permite permanecer conectados. Se espera que nuestros usuarios ejecuten versiones actualizadas de JS.

Suponiendo que alguien saque nuestra base de datos en algún momento,

¿Es una buena idea reducir la entropía de nuestras contraseñas almacenadas al hacer que los usuarios realicen una prueba razonable de la tarea de trabajo al iniciar sesión y enviarla como contraseña, y aumentar la dificultad a lo largo de los años?

Lo que esto hace:

  • protege a los usuarios para que no se agrieten sus contraseñas débiles y se asocien con sus identidades en línea

Lo que esto no hace:

  • proporcionar una clave de sesión
  • proporcionar protección DDoS
  • proporcionar cualquier otro servidor de seguridad

registro / inicio de sesión en el lado del cliente:

h = password
d = "0000f"
do: 
  h = hash (h + username + salt)
while (h > d)

send("login", username, h)

inicio de sesión del servidor:

d = "0000f"
listen("login", username, h)
if h > d:
  user = database.get(username)
  if user.pass == h:
    send("accepted", true)
    session.user = user

inicio de sesión en el lado del cliente 2:

listen("accepted", accepted)
if accepted:
  set cookie("user", user)
  set cookie("h", h)

La ventaja de esto es que el usuario no tiene que volver a enviar su contraseña para actualizar la dificultad.

He implementado este protocolo, pero no lo he visto en ningún otro lugar. Y la primera ley de la criptodinámica es "Nunca harás tu propia".

Si esto funciona, me encantaría verlo incorporado en un certificado para mostrar al usuario que el servidor almacena los secretos del usuario de manera responsable.

    
pregunta powersupply 02.08.2017 - 23:33
fuente

2 respuestas

2

No soy un experto aquí, solo comparto mis pensamientos ya que tu idea es clara y me gustaría explorarla.

Como se señala en @PwdRsch , la palabra clave talk14 a [video] , [diapositivas y código de muestra] a partir de 2014 (aunque no sea la charla más fuerte I he visto) es exactamente sobre este tema.

Tengo algunos problemas con tu esquema tal como son. Primero, para evitar ataques de repetición, realmente debe hacer que el servidor genere un nonce para cada inicio de sesión y lo envíe al cliente (ya que los nonces no necesitan ser clave) y no desea presentar un DoS fácil. obténgalos de /dev/urandom en lugar del habitual /dev/random )

Segundo, tanto el atacante como el usuario honesto deben hacer un trabajo de O (hash_prefix = '0000'), que será una penalización mucho mayor para el usuario honesto en su teléfono inteligente que para el atacante en su 12 Plataforma de hash GPU. Darle la ventaja al atacante es malo.

Solucionemos esto haciendo algo como esto:

lado del cliente:

h = "0"
d = "0000f"
hashed_pw = pbkdf2( password )
do: 
  h = hash (h + username + hashed_pw + nonce)
while (h > d)

send("login", username, h)

lado del servidor:

listen("login", username, h)
user = database.get(username)
if "0000f" > hash (h + username + user.hashed_pw + nonce)
  send("accepted", true)
  session.user = user

Aquí el servidor tiene que hacer O (1) trabajo (una única iteración de hash), el cliente honesto debe hacer O (hash_prefix = '0000') trabajo, y el atacante debe hacer un trabajo exponencial en la longitud del contraseña: O (2 password_length-1 ) * O (hash_prefix = '0000').

Habiendo endurecido un poco tu algoritmo (pero pasar una hora mirándolo de ninguna manera implica que está listo para usar), veamos lo que está logrando. Supongo que su modelo de amenaza es protegerse contra los ataques de fuerza bruta en línea para evitar que las cuentas de sus usuarios se vean comprometidas.

Drive-by / low-hanging fruit

En este escenario de ataque, el atacante está buscando a los usuarios lo suficientemente tontos como para usar una contraseña en el más común listas de contraseñas . Aquí, la aceleración exponencial de forzar al atacante a adivinar la contraseña desaparece porque no están adivinando un número exponencial de contraseñas. Entonces, para cualquier usuario con una contraseña débil, este esquema no hace nada porque unos pocos milisegundos extra de hashing son insignificantes para el atacante.

Ataques dirigidos

Aquí el atacante está tratando de ingresar en una cuenta específica . Si realmente están adivinando contraseñas al azar, esto las ralentizará, pero dado que la demora de la red y fail2ban ya hacen que un ataque de ingeniería social / phishing sea mejor que una fuerza bruta en línea, no estoy seguro de que esté agregando valor aquí tampoco. Habilite 2FA con Google Authenticator si está preocupado por esto.

Conclusión: La idea es clara y he disfrutado pensando en esto, pero

  1. No estoy seguro de que esté agregando mucho valor.
  2. "No ruedes el tuyo". Encontré algunos agujeros en el esquema, por lo que necesitaría dedicar mucho tiempo y esfuerzo a endurecerlo antes de poder utilizarlo en producción.
respondido por el Mike Ounsworth 03.08.2017 - 03:14
fuente
0

Creo que las diferentes partes de su plan varían en utilidad de "esa es una forma diferente de hacerlo, pero no dañará nada" a "eso es una vulnerabilidad grave de seguridad". En detalle:

Posiblemente fuera de la norma

Normalmente no hago hash de la contraseña del lado del cliente. Dicho esto, creo que hay otras aplicaciones que hacen hash del lado del cliente por razones de rendimiento, por lo que esto no es una locura. Sin embargo, creo que en este caso ha tomado algunas decisiones como resultado de su hashing del lado del cliente que es malo.

Diferente, pero probablemente esté bien

Tener una función de trabajo creciente es perfectamente normal e incluso bueno. La idea es que a medida que cambian los tiempos, aumenta el valor de trabajo en todo el sistema para que sea más difícil descifrar las contraseñas. Como es obvio que entiendes, cuantas más "iteraciones" tengas que pasar para crear el hash, más difícil será descifrar una contraseña, ya que cualquier intento de craqueo tiene que coincidir con tu número de iteraciones. En términos de realmente hacer eso, hay algunas consideraciones importantes aquí:

1) (en realidad, un nitpick). El hashing repetido en realidad no cambia tu entropía en absoluto. Alta entropía = más seguro, por lo tanto, si su algoritmo disminuye la entropía (como dijo en su respuesta), eso sería algo malo. De cualquier manera, su función de trabajo en aumento no aumenta ni disminuye la entropía.

2) El problema con su plan, porque hace las cosas del lado del cliente, es que no puede ajustar la función de trabajo con el tiempo para tener en cuenta los avances en la potencia de cálculo. Con el lado del servidor es muy fácil actualizar su función de trabajo a lo largo del tiempo. Si desea que el cracking sea más costoso, simplemente vuelva a calcular el hash de la contraseña con una función de trabajo superior la próxima vez que el usuario inicie sesión. Luego, puede almacenar tanto la contraseña como la función de trabajo en la base de datos. Debido a que su servidor nunca ve la contraseña, no puede actualizar el hash sin un avance adicional entre el cliente y el servidor.

Agujero de seguridad potencialmente grande

Este es un problema gigantesco, creo:

set cookie("h", h)

El problema es que está enviando el hash al cliente en una cookie. La otra parte del problema es que el servidor acepta este mismo hash directamente para iniciar sesión en el usuario. Por lo tanto, está almacenando efectivamente la contraseña del usuario en una cookie, que es el lugar menos seguro que existe. Alguien que logró robar esa cookie podría iniciar sesión como usuario hasta que el usuario cambie su contraseña.

Normalmente, lo único que almacena en la cookie es un ID de sesión, y en el lado del servidor usted asocia ese ID de sesión con el usuario que inició sesión. Si la identificación de la sesión es robada (o incluso se sospecha que ha sido comprometida), simplemente puede invalidar la identificación de la sesión. El atacante pierde todo acceso y el usuario legítimo solo tiene que volver a iniciar sesión.

Nunca, bajo ninguna circunstancia, almacene la contraseña o el hash de la contraseña en una cookie. Ambos deben ser completamente olvidados (del lado del cliente) después de un inicio de sesión exitoso.     

respondido por el Conor Mancone 03.08.2017 - 03:19
fuente

Lea otras preguntas en las etiquetas