cambio de función de hash

26

Tengo las contraseñas de las cuentas de usuario almacenadas en una base de datos mediante una función de hash criptográfica insegura (antigua).

¿Cuál es el enfoque mejor / usual para cambiar la función de hash de contraseña? Solo dos ideas vienen a mi mente:

  1. Indica a todos los usuarios que cambien sus contraseñas en el próximo inicio de sesión y hagan un hash de sus contraseñas con la nueva función cuando lo hagan. Esta no es una buena opción debido a muchos problemas (usuarios inactivos, largo período de migración, implementación complicada ...)

  2. Hash los valores hash antiguos con la nueva función hash, y vuelve a escribir el método para verificar las contraseñas en la base de datos: newHash (salt + oldHash (salt + password))

Este doble hash me parece una buena idea, elegante y simple de implementar.

Me gustaría saber si hay advertencias que no estoy notando aquí. ¿Es así como se hace normalmente, o hay otro método? ¿Existe alguna vulnerabilidad criptográfica conocida en el uso de la salida de la función hash débil como entrada de la función hash fuerte.

Si es una buena idea, ¿qué pasa con la sal? ¿Estaría bien usar la misma sal para ambas funciones hash?

    
pregunta h9lpq0u 27.08.2012 - 16:01
fuente

6 respuestas

17

Personalmente, probablemente implementaría que los usuarios nuevos obtengan un hash moderno fuerte (bcrypt u otro hash criptográfico reforzado con clave) y los usuarios antiguos que tienen el hash débil envuelto alrededor de bcrypt. Antes de que las personas se quejen de la complejidad adicional de la implementación, la alternativa es forzar siempre a los nuevos usuarios a usar un algoritmo de hash débil envuelto alrededor de un algoritmo de hash fuerte, y eso significa que nunca se librará del esquema original.

Tendría algún indicador documentado del esquema de tipo hash análogo al $1$ , $2a$ , $5$ o $6$ en la cripta (cita de la página del manual de crypt):

   If  salt is a character string starting with the characters "$id$" fol‐
   lowed by a string terminated by "$":

          $id$salt$encrypted

   ... id  identifies  the  encryption
   method  used  and  this  then  determines  how the rest of the password
   string is interpreted.  The following values of id are supported:

          ID  | Method
          ─────────────────────────────────────────────────────────
          1   | MD5
          2a  | Blowfish (not in mainline glibc; added in some
              | Linux distributions)
          5   | SHA-256 (since glibc 2.7)
          6   | SHA-512 (since glibc 2.7)

En este caso, necesita tres tipos de hashes de contraseña:

  1. Los antiguos hashes rápidos y débiles
  2. Los antiguos hashes rápidos y débiles que se envuelven alrededor de un hash lento con una sal fuerte
  3. El nuevo hash lento.

El día 1, tomaría todo de la categoría 1 y lo movería a la categoría 2. Las nuevas contraseñas se incluirían en la categoría 3. Además, como personas que inician sesión, incluso puede migrar todos los hash autenticados con éxito de la categoría 2 a la categoría 3. mientras que la contraseña de texto plano está en la memoria. En algún momento, incluso puede eliminar completamente cualquier evidencia / mantenimiento heredado del esquema de hash débil. (Por ejemplo, obligar a los usuarios con cuentas que no han iniciado sesión durante más de 2 años después del cambio para restablecer sus contraseñas).

    
respondido por el dr jimbob 27.08.2012 - 16:40
fuente
10

Su propuesta 2 (tome el antiguo valor de hash como la "contraseña" para el nuevo hash) es buena si se cumplen todas las condiciones siguientes:

  • El hash antiguo es suficientemente resistente a preimages .
  • El nuevo hash usa todos los silbidos de campanas necesarios para considerarlo "robusto" (es decir, bcrypt con un muchas rondas y un nuevo salt aleatorio para cada contraseña, incluidos los cambios de contraseña para un usuario determinado).
  • El hash antiguo se puede calcular de manera lo suficientemente eficiente como para que toda la "lentitud configurable" del negocio se base exclusivamente en el nuevo hash.

Tenga en cuenta que el MD5, aunque está completamente dañado con respecto a las colisiones, todavía parece razonablemente sólido con respecto a las preimágenes.

Todavía sería mejor para sus intereses incluir un campo de "tipo de hash" en su base de datos, para que las migraciones se puedan manejar sin problemas. Por ejemplo, podría aplicar su hash-de-hash, y luego planificar una migración a un esquema de hashing de contraseña que use solo el nuevo hash nuevo: las contraseñas se actualizarán al nuevo esquema cada vez que se creen o cambien, por un Migración gradual. Más adelante (por ejemplo, en un año), puede configurar una actualización forzada (el usuario debe volver a ingresar la contraseña en el próximo inicio de sesión) para las contraseñas que aún utilizan el formato antiguo.

Incluso si no te gustan las migraciones (¿a quién le gusta?), parece prudente prever una posible futura migración, si las condiciones en ese momento te obligan a realizar la migración (por ejemplo, una devastadora ruptura criptoanalítica).

    
respondido por el Thomas Pornin 27.08.2012 - 17:38
fuente
7

Yo usaría bcrypt como el nuevo hash. De lo contrario, su solución de "envolver" los hashes antiguos debería ser segura, dado que usa una buena sal para bcrypt. He visto que esta solución funciona bien varias veces cuando los sistemas desean actualizar la forma en que tienen sus contraseñas.

    
respondido por el Oleksi 27.08.2012 - 16:13
fuente
6

Si no quiere molestarse en usar la antigua función hash, pero tampoco quiere forzar a todos a cambiar su contraseña, hay una solución elegante.

Agregue una columna / valor a cada perfil de usuario. Llamemos si HashVersion

Cuando el usuario inicie sesión por primera vez desde su migración, el sistema podrá detectar que está utilizando la antigua función hash. Por lo tanto, si la contraseña proporcionada por el usuario coincide con su hash, entonces tome la contraseña de texto sin formato y con su nuevo algoritmo, reiniciando las sales y demás. Y luego subes a HashVersion para que sepas que ahora está usando la nueva función hash.

En mi opinión, esta es la mejor solución, especialmente si su función hash anterior era realmente insegura.

    
respondido por el Earlz 27.08.2012 - 19:49
fuente
2

Mientras el hash antiguo sea decente (MD5 o DES-Crypt está bien, CRC32 no lo es), este enfoque es seguro. El uso de la misma sal tampoco debería dar lugar a problemas, suponiendo que la sal sea lo suficientemente buena, es decir, (casi) globalmente única.

Para la función hash externa, recomiendo usar uno de scrypt, bcrypt o PBKDF2.

    
respondido por el CodesInChaos 27.08.2012 - 16:09
fuente
1

Encontrarás docenas de aplicaciones de código abierto que han resuelto este problema. Wordpress viene rápidamente a la mente, pero hay otros también. Incluso Microsoft Windows utiliza esta misma técnica. La solución general es esta:

  • La salida de cada función hash compatible se distingue fácilmente; ya sea verificando el formato de salida o la longitud, o (de manera más apropiada) anteponiendo alguna cadena de identificación (por ejemplo, sha1:salt:_hash_output____ ) o agregando un nuevo campo a su base de datos para identificar el tipo de hash.
  • Continúas admitiendo la autenticación a través de todas las funciones hash utilizadas anteriormente, pero todos los hash nuevos solo mostrarán la versión preferida.
  • Opcionalmente, si un usuario se autentica con una versión de hash anterior, la contraseña autenticada se volverá a aplicar con el algoritmo preferido y se actualizará el hash almacenado.
respondido por el tylerl 28.08.2012 - 05:13
fuente

Lea otras preguntas en las etiquetas