¿Cómo puedo estar seguro con un salt global?

10

Si entendí lo básico del hashing y el almacenamiento de contraseñas, lo que necesitamos es:

  1. una sal "fuerte"
  2. una "verdadera" sal aleatoria
  3. una sal única por contraseña
  4. una función hashing de contraseña con un alto costo de CPU

Hasheamos las contraseñas usando 1, 2, 3 y 4 usando PHP crypt() y CRYPT_BLOWFISH con un costo "medio".

Tenemos una nueva necesidad: necesitamos poder comparar los hashes porque hemos notado que los fraudes / spam / estafadores de bajo nivel usan las mismas contraseñas. No necesitamos conocer la contraseña de un abusador, sino solo saber que un perfil usa la misma contraseña que un abusador identificado previamente.

Por lo tanto, estamos pensando en tener 2 campos en nuestra base de datos:

  • contraseñaA: utilizada para el procedimiento de inicio de sesión (este campo usaría 1, 2, 3 y 4)

crypt($password, '$2y$06$' . $uniqueSalt);

  • contraseñaB: se utiliza para "comparar" (este campo lo utilizaríamos 1, 2 y 4)

crypt(md5(md5($password) . $globalSaltA) . $globalSaltB, '$2y$10$' . $globalSaltC);

Las sales globales A y B se almacenarán solo en el código de la aplicación.

Para compensar el punto 3 faltante por la contraseñaB, hemos aumentado el "costo", que es mucho más alto.

Tras el comentario, comprendí cuán insegura es esta estrategia si un atacante obtiene un acceso completo (base de datos + código) en el servidor. Sin embargo, si el atacante solo obtiene la base de datos, estamos bien.

Las compañías que detectan el fraude de tarjetas de crédito tienen el mismo problema con los números de las tarjetas de crédito. No pueden almacenarlos, pero necesitan compararlos.

Entonces, ¿qué estrategia / solución aconsejarías?

    
pregunta Toto 07.10.2013 - 16:33
fuente

4 respuestas

12

El problema principal: si su servidor puede comparar de manera eficiente una contraseña con hash con (potencialmente) todas las contraseñas con hash para todos los usuarios, entonces un atacante también puede hacerlo. Un atacante que tome una copia de los archivos / base de datos de su servidor estará en posición de ejecutar un ataque de diccionario sin conexión, es decir, crear una contraseña potencial y buscar una coincidencia.

El hash de contraseña normal utiliza un sal por contraseña para evitar ataques paralelos: queremos que el atacante pague el precio computacional completo de la función de hash (que se encarece en muchas iteraciones) para cada contraseña y cada cuenta de usuario. Sin embargo, si varios hashes de contraseña utilizan el mismo salt, entonces el atacante puede probar una contraseña potencial contra todos ellos por el costo de una invocación de función hash. Por lo tanto, su "sal global" debilita sustancialmente el esquema: le permite al atacante atacar 1000 cuentas por el costo de atacar una.

El punto importante: su problema es uno de temporalidad. De hecho, realmente no desea comparar una nueva contraseña de usuario con todas las contraseñas de todos los demás usuarios; lo que desea es comparar la contraseña elegida por cada usuario en el momento del registro con una lista limitada de "contraseñas de delincuentes conocidos". Desafortunadamente, cuando un usuario registrado entra en estado de "delincuente", ya está registrado y su contraseña no se ha mantenido, solo el hash. Entonces, realmente, le gustaría poder acceder a la contraseña utilizada para el registro después de el registro se ha realizado.

Una posible solución: usar custodia, también conocida como encriptación asimétrica . Crear un par de claves RSA. Almacena la clave pública en el servidor. NO almacene la clave privada correspondiente en el servidor; en cambio, guárdelo en otro lugar, por ejemplo en una computadora portátil que se mantiene fuera de línea (o tal vez solo en algunas unidades flash USB).

Cuando un usuario se registra, hash su contraseña como de costumbre (con PBKDF2, muchas iteraciones, una nueva sal aleatoria, etc.). Pero, también, cifre la contraseña (no el hash) con la clave RSA, y almacene el resultado del cifrado en su base de datos, junto con el hash. El cifrado solo necesita la clave pública, y es aleatorio, por lo que esta versión cifrada no le da un impulso adicional a un atacante que obtiene una copia del contenido de la base de datos. Cuando un usuario inicia sesión, se utiliza el hash de contraseña, como de costumbre.

Cuando un usuario resulta ser un spammer, obtenga la clave privada y descifre la contraseña en custodia. De esa manera, obtiene la "contraseña incorrecta" y puede agregarla a la lista de contraseñas para rechazarla al registrarse. Esa lista se puede mantener como texto claro: ya que las cuentas correspondientes se han cerrado, no hay problema con eso. Tenga cuidado de hacer el descifrado en una máquina "segura", preferiblemente fuera de línea: realmente no desea ver que la clave privada sea robada.

Una advertencia: los spammers son como las bacterias, ya que tienden a evolucionar con respecto a las restricciones externas. Si filtra a los spammers basándose en su costumbre de reutilizar contraseñas para el registro, pronto los capacitará para generar contraseñas aleatorias. Por lo tanto, predigo que si instala un sistema de este tipo, dejará de ser efectivo para expulsar a los spammers después de un tiempo relativamente corto; después de eso, solo tendrá un peso muerto en su base de datos (no mucho, porque un mensaje corto cifrado RSA con una clave RSA de 2048 bits es solo de 256 bytes, pero el peso muerto es igual).

    
respondido por el Thomas Pornin 10.10.2013 - 01:06
fuente
3

No puedes. Deshace la seguridad de tener una sal única (o cualquier sal para esa materia) por completo. El punto de tener una sal única es que evita el uso de una tabla de arco iris para identificar la contraseña. El almacenamiento con una sal global permite que la tabla sea atacada con una tabla de arco iris y, en muchos casos, identifique la contraseña original.

La alternativa a esto es generar una lista de sales para probar una nueva contraseña (las asociadas con los spammers anteriores). Hace que la creación de un nuevo usuario sea una operación un poco más difícil ya que tiene que ejecutar el hash de contraseña varias veces, sin embargo, es la única forma segura de hacer lo que está hablando. La creación de nuevos usuarios también debe ser la única vez que necesita hacer este paso, por lo que no debería ser demasiado, demasiado grande como un éxito. También recomendaría hacerlo solo cuando otros indicadores parecen admitir que es un usuario de correo no deseado si desea reducir aún más el impacto.

También puede almacenar contraseñas incorrectas después de identificarlas para mantener la lista corta. Por ejemplo, el usuario anterior con salt 1234 tenía un hash abcd. Cuando un nuevo usuario envía la contraseña "ImSpam" y la prueba contra salt 1234, ve que está abcd y ahora conoce la contraseña real para ese salt, por lo que puede dejar de verificarla y no permitir la contraseña por completo. Esto debería mantener la lista relativamente corta. También es posible que los antiguos usuarios de spam envejezcan potencialmente, ya que si ese spammer no te ha atacado en mucho tiempo, es muy probable que se hayan rendido.

    
respondido por el AJ Henderson 07.10.2013 - 16:48
fuente
0

Llamemos a los hashes únicamente salados "mejor" y a los hashes globales / salados solo "peor". Por razones de rendimiento, es posible que desee mantener los mejores hashes en la base de datos de usuarios para que pueda autenticar a los usuarios rápidamente. Recomiendo mover los hashes "peores" a un servidor diferente y más seguro con una interfaz delgada, simple y autenticada que consta de dos métodos, AddPassword (userId, password) y Blacklist (spammerUserId).

AddPassword simplemente informará el éxito o el fracaso. La lista negra agregaría la identificación del spammer a la lista negra y devolvería una lista de todos los ID de usuario que coincidan con la contraseña del spammer. Pero tenga cuidado: cualquiera que tenga acceso puede ejecutar un diccionario contra su método de Lista Negra, envenenando a los usuarios legítimos y obteniendo listas de contraseñas que coincidan.

Internamente, puede almacenarlos como desee: texto cifrado, salado, cifrado o sin cifrar. Solo tienes que mantener esa máquina bien cerrada.

    
respondido por el John Deters 09.10.2013 - 01:12
fuente
0

Como ya dijo @AJHenderson, la respuesta simple es que no puedes. Entiendes por qué se necesita una sal única, y no te estás perdiendo ningún truco matemático para esto, es realmente imposible en combinación con una sal única. Dicho esto, así es como resolvería el problema:

1. Yo agregaría un nuevo campo de base de datos llamado algo como UnsaltedPassword y lo llenaría con todos los valores NULL. Cada vez que alguien se registra o cambia su contraseña, rellénela con un hash de la contraseña, solo que sin sal y diez veces más fuerte que el otro método de hashing.

2. Modifique el procedimiento de inicio de sesión para que compruebe si el usuario tiene un valor NULO en ese campo y, si lo tiene, rellene el campo. Si esto causara demasiada carga, realice la función de hash solo para ciertas cuentas, como personas con un postcount bajo o simplemente por azar (por ejemplo, realice el hash con una probabilidad de 1 en 10).

3. Por último, agregaría la comprobación de contraseñas duplicadas cada vez que se rellene el campo y también la verificación en una lista negra. Las personas con duplicados pueden estar marcadas (posiblemente también se les puede decir que usan una contraseña débil), y la lista negra se elimina de inmediato (o si se elimina, si es posible).

Los cambios de contraseña no ocurren tan a menudo en comparación con los inicios de sesión (todas las veces que se debe ejecutar la otra función hash con sal), por lo que creo que tiene sentido tener dos campos hash diferentes en La base de datos para diferentes propósitos. También debería ser factible diez veces más fuerte, o tal vez podría hacer aún más (lo que aspiraría a tener un tiempo de hashing de 1 a 2 segundos, ya que es prácticamente un contrato de una sola vez). Probablemente sea más caro para los atacantes descifrarlos que solo aplicar la sal única.

    
respondido por el Luc 09.10.2013 - 23:04
fuente

Lea otras preguntas en las etiquetas