¿Alguna razón por la que no debería estar usando sal y hash antes de pasar bCrypt?

1

He estado leyendo sobre el almacenamiento de contraseñas y demás, y he llegado a la conclusión de que necesito usar bCrypt. Tengo una implementación funcionando correctamente, pero me pregunto cuál es la mejor manera de seguir adelante con mi aplicación.

El sistema de almacenamiento de contraseñas anterior era simplemente hashing y salado. En realidad, para mí es más fácil mantener este sistema y la capa bCrypt en la parte superior que reescribirlo solo con bCrypt.

Sin embargo, sigo leyendo que la combinación de diferentes algoritmos de hash es una mala idea, así que quería obtener alguna aclaración, ya que no puedo pensar en ninguna razón para no implementar de esta manera:

  • Hash (contraseña + sal + pimienta) * 1000 iteraciones - SHA-256
  • El hash resultante se ejecuta a través de bCrypt con su propia salazón y un factor de trabajo definido.
  • hash final almacenado en DB junto con sal original
  • Para verificar la contraseña, se reinventa como se indicó anteriormente antes de pasar la verificación de hash bScrypt.

¿Hay alguna razón por la que no debería estar haciendo las cosas de esta manera y debería abandonar la contraseña original + sal + pimienta en favor de simplemente dar la contraseña simple a bCrypt?

Gracias

    
pregunta Gary 21.05.2014 - 17:46
fuente

1 respuesta

3

No hay ninguna debilidad de seguridad evidente con tus esquemas. El original (aparte de posiblemente no almacenar un número de versión con sus hash para que pueda actualizar su esquema a más rondas o un nuevo pimiento si es necesario), o el nuevo con capas de bcrypt. Bcrypt puede tomar 72 bytes de entrada, por lo que no hay problema al usar sha256 como hash.

Tendría cuidado si codificas la salida de tu sha256hash reforzado con clave antes de alimentarlo a bcrypt. En principio, es probable que sea mejor mantenerlo en forma binaria; si estuviera usando sha512, eso permitiría que se usaran todos los bytes (como 72 bytes = 576 bits). Concedido con sha-256, no importa mientras lo hagas correctamente. Un hash sha256 tiene 32 bytes de largo (en binario con letras no imprimibles), 44 bytes de largo después de la codificación base64, 64 bytes de largo (en hexadecimal), pero 88 bytes si codifica en base al hash codificado en hexadecimal (que sería parcialmente seguridad truncada y ligeramente debilitada: por ejemplo, en lugar de 256 bits de seguridad inherente, tiene 72/88 * 256 ~ 209 bits).

Tenga en cuenta que si un usuario tiene una contraseña de entropía extremadamente alta (por ejemplo, 400 bits de entropía) que en principio requeriría ~ 2 ^ 400 de tiempo para descifrar, usando sha256 como paso intermedio, solo tomará tiempo ~ 2 ^ 256 antes de que sea probable encontrar alguna contraseña que funcione. Concedido 2 ^ 256 es completamente seguro en estos días (ya que es algo significativamente mayor que ~ 2 ^ 80, por lo que esta diferencia no tiene relevancia práctica)

Se vuelve más complicado y potencialmente más molesto de mantener (dado que puede argumentar que esto es algo bueno, si alguna vez se filtró su base de datos, sería más difícil para un atacante obtener una GPU para forzar la fuerza bruta). Si alguna vez actualiza su sistema y las cosas no funcionan perfectamente, hay muchos más puntos en los que las cosas podrían salir mal. Si aparece un nuevo desarrollador y los hashes aparecen en la forma de bcrypt, pueden asumir que solo son bcrypt y cambiar algo que rompe el sistema.

Una alternativa sería mantener ambos sistemas en su lugar y actualizar a los usuarios a bcrypt en su próximo inicio de sesión exitoso.

def login(username, password):
    user = get_user(username)
    if user.uses_old_hash():
        calculated_old_hash = sha256_1000_round(password, salt=user.salt)
        if constant_time_string_compare(user.hash, calculated_old_hash):
            calculated_new_hash = bcrypt.hashpw(password, salt=bcrypt.gensalt(12))
            user.hash = calculated_new_hash
            print "Login Successful"
            return True
        else:
            print "Login Failed"
            return False
    else:
        hash = user.hash
        calculated_new_hash = bcrypt.hashpw(password, salt=hash)
        if constant_time_string_compare(hash, calculated_new_hash):
            print "Login Successful"
            return True
        else:
            print "Login Failed"
            return False
    
respondido por el dr jimbob 21.05.2014 - 18:38
fuente

Lea otras preguntas en las etiquetas