He tenido que resolver este mismo problema dos veces antes:
- Mi primera aplicación web, en realidad sabía lo suficiente para las contraseñas de los usuarios de hash MD5; Sin embargo, no sabía nada sobre la sal, y trabajé en eso más adelante.
- En realidad, la misma aplicación web, unos años más tarde, cuando decidí "actualizar" a SHA-512 desde el MD5 existente.
En ambos casos, no utilicé ninguna de tus opciones, sino la opción 3: en el próximo inicio de sesión de un usuario, usa la contraseña para generar el nuevo hash y reemplazar el antiguo (después de verificar el anterior).
En el caso de agregar una sal, esto fue bastante trivial: todo lo que hice fue poner a todos por omisión a una sal de "" (cadena vacía), que podría ser concatenada y luego picada sin tener ningún efecto en el hash resultante; una vez autenticado, generé una nueva sal para el usuario y luego volví a aplicar la contraseña, guardando ese nuevo resultado.
La actualización de MD5 a SHA-512 fue un poco más complicada, pero simplemente mirando la longitud de la cadena de la tabla (no usé una nueva columna para el nuevo hash, simplemente amplié la existente para acomodar el hash más largo) Podría decir qué algoritmo usar y luego autenticar al usuario adecuadamente; una vez autenticados, si aún estuvieran en el hash viejo, calcularía uno nuevo (y también aprovecharía la oportunidad para generar una nueva sal) y lo almacenaría.
En ambos casos, por supuesto, finalmente me encontré con la situación en la que aún existían contraseñas de "estilo antiguo". Después de esperar un período de tiempo adecuado (por ejemplo, 6 meses), simplemente decida que aquellos que no han iniciado sesión desde que se adoptó el nuevo estilo están "inactivos": genere y almacene una nueva contraseña completamente aleatoria para ellos (usando el nuevo estilo de almacenamiento, por supuesto), y si alguna vez volvieran, tendrían que usar su mecanismo de restablecimiento de contraseña para recuperar el acceso. (De manera alternativa, déjelo tal como está, pero invalídelo simplemente al eliminar el código del estilo anterior). También podría (si corresponde) enviar un correo electrónico a estos usuarios, solicitándoles que inicien sesión para completar una actualización de seguridad en su cuenta, antes de invalidar su contraseña actual.
Este enfoque implica un código adicional en la rutina de autenticación, por supuesto, pero es solo temporal: una vez que todos han actualizado (ya sea al iniciar sesión o al "forzarse" como en el párrafo anterior), puede eliminar todos Código responsable de realizar la actualización. Actualización de seguridad completa, con la mayoría de sus usuarios (y todos sus usuarios regulares) sin haber notado nada.