security - que - ¿Cómo implemento Salt en mi inicio de sesión para contraseñas?
hash contraseñas php (8)
Como mencionaste, los algoritmos hash funcionan solo en una dirección (o solo si son lo suficientemente fuertes :-D)
Para su pregunta acerca de la salazón, recomendaría una contraseña con una cadena de sal estática y algunos datos dinámicos de la base de datos , que no deberían cambiar una vez que se haya creado.
Esta es una forma muy segura de almacenar contraseñas, ya que incluso si la base de datos está en peligro, los hackers / crackers aún necesitan obtener su hachís de cadena estático y deben adivinar cómo aplicó toda la salazón.
Por ejemplo, digamos que tiene una tabla de users
con estas columnas:
id
username
password
created_at
las columnas id y created_at una vez llenadas nunca deben cambiarse ..
por lo tanto, cuando usa la contraseña del usuario, puede hacer tan simple como:
<?php
$staticSalt = ''!241@kadl;ap]['';
$userPass = ''my new pass'';
// assuming $user variable is already populated with DB data
// we will generate new hash from columns and static salt:
$genPass = sha1($user[''id''] . $userPass . $user[''created_at''] . $staticSalt);
?>
Espero que este ayude :) aplausos
Quiero implementar una sal en mi sistema de inicio de sesión, pero estoy un poco confundido sobre cómo se supone que funciona. No puedo entender la lógica detrás de esto. Entiendo que md5 es un algoritmo unidireccional y que todas las funciones con las que me he encontrado parecen mezclar todo. Si este es el caso, ¿cómo se puede volver a obtener la contraseña para comparar? Mi mayor pregunta es, ¿cómo saltear la contraseña de un usuario es más seguro que simplemente usar la contraseña? Si alguna vez se comprometió una base de datos, el hash junto con la sal está en la base de datos. ¿No es esto todo lo que un hacker necesitaría?
También encontré otra publicación aquí en SO, donde otro desarrollador dijo:
"Asegúrese de que su sal y algoritmo se almacenen por separado de la base de datos"
Me gustaría almacenar la sal en la base de datos. ¿Es esto realmente un problema si lo hago?
Estoy buscando ayuda para entender cómo funciona esto y también cuál podría ser la mejor práctica. Cualquier ayuda es muy apreciada.
EDITAR: Quiero agradecer a todos por sus respuestas e ideas. Aunque ahora estoy más confundido, ciertamente ha sido una experiencia de aprendizaje para mí. Gracias de nuevo chicos.
El objetivo de una sal es evitar que los atacantes amorticen el costo de un ataque de fuerza bruta a través de los sitios (o mejor aún, al usar una sal diferente para cada usuario: todos los usuarios de un sitio) a través de tablas de arcoiris precalculadas.
Con hash simple, un atacante puede calcular una tabla de este tipo una vez (una operación muy larga y costosa) y luego usarla para buscar contraseñas rápidamente para cualquier sitio. Cuando un sitio usa una sal fija, el atacante tiene que calcular una nueva tabla específicamente para ese sitio. Cuando un sitio utiliza una sal diferente para cada usuario, el atacante puede dejar de molestarse con las tablas del arcoíris: tendrá que aplicar fuerza bruta a cada contraseña por separado.
Almacenar las sales por separado no es necesario para obtener esta ventaja. En teoría, sería aún más seguro porque neutralizaría la debilidad del diccionario o las contraseñas cortas. En la práctica, no vale la pena preocuparse porque al final del día, necesita acceder a las sales en algún lugar para verificar las contraseñas. Además, tratar de separarlos llevaría a sistemas más complejos, y cuanto más complejo es un sistema, más oportunidades hay de agujeros de seguridad.
Editar: Mis recomendaciones concretas:
- Genera una sal pseudoaleatoria larga para cada usuario y almacena en el DB
- Use un hash basado en bcrypt
- idealmente, no lo implemente usted mismo, utilice una biblioteca existente en su lugar
Las contraseñas hash tienen como objetivo mantener esas contraseñas en secreto de sus propios administradores.
1) Mantener las contraseñas de texto sin formato en su base de datos estaría bien, excepto que el administrador puede usar sus contraseñas para obtener acceso a otro sistema.
2) Puede usar una sola sal global, que se combina con las contraseñas (anteponiéndolas o XORing) y luego hash para el almacenamiento en la base de datos. Pero eso es vulnerable a un administrador malicioso Y una tabla de arco iris diseñada para esa sal.
3) Puede tener una sal por separado para cada usuario: la base de datos se usará para almacenar la sal y el hash derivado de la combinación contraseña / sal. Esto evitará un ataque de arco iris, pero los ataques de fuerza bruta aún serán posibles.
4) Finalmente, puede mantener su función de hash en secreto usando una solución de hashing de hardware de velocidad limitada.
Eso es tan bueno como puedes hacer. Debido a la naturaleza humana, las contraseñas tienen un dominio limitado y son vulnerables a los ataques de fuerza bruta. Estamos tratando de evitar que los administradores obtengan las contraseñas de los usuarios y luego las utilicen en otros sistemas a los que no deberían tener acceso.
Algunas otras notas:
a) Puedes usar bcrypt en la combinación contraseña / sal para ralentizar el ataque de fuerza bruta del atacante. Pero dado que asumimos administradores, pueden ser pacientes.
b) Mantener la sal separada del hash de la contraseña no es una defensa efectiva, después de todo, asumimos los administradores.
c) Usar datos existentes como sal es un poco mejor, pero dudo que los datos existentes tengan tanta entropía como una sal aleatoria.
Las otras respuestas son buenas, así que solo mencionaré un punto menor que nadie más ha mencionado. No desea utilizar la misma sal para cada contraseña porque si dos personas tienen la misma contraseña, tendrán el mismo hash. Eso es exponer la información que un atacante puede explotar.
Podría usar la misma sal para cada usuario junto con la buena idea de Juraj de combinar la contraseña con otros campos de base de datos no cambiantes (únicos para un usuario). Pero ten cuidado porque esta información está ligada a la contraseña. Si tuviera que asociar el nombre de usuario + la contraseña para garantizar un hash único, no podría cambiar el nombre de usuario sin crear un nuevo usuario y exigirle que establezca una nueva contraseña.
Como ejemplo de tener una sal única por usuario y almacenarla junto con el hash de contraseña, señalaré /etc/shadow en su sistema Linux típico.
root@linux:/root# cat /etc/shadow | grep root
root:$1$oL5TTZxL$RhfGUZSbFwQN6jnX5D.Ck/:12139:0:99999:7:::
Aquí, el oL5TTZxL es la sal y RhfGUZSbFwQN6jnX5D.Ck/ es el hash. La contraseña de texto sin formato es raíz en este caso, y el algoritmo hash que usa mi sistema es el algoritmo de contraseña BSD basado en MD5. (Los sistemas más nuevos que los míos tienen mejores algoritmos hash)
No obtiene la contraseña para comparar. Cifras la contraseña cuando intentan iniciar sesión y comparas el valor almacenado con el nuevo valor encriptado.
Olvídate de usar sales (en parte por el motivo que mencionas), utiliza bcrypt en su lugar:
Para una buena explicación, vea: http://codahale.com/how-to-safely-store-a-password/
Salar la contraseña de un usuario es posiblemente más seguro que simplemente usar la contraseña, ya que puede proteger contra ataques previos a la computación.
Por ejemplo, si un pirata informático obtiene acceso a su base de datos y las contraseñas no están saturadas, puede buscar los hashes en su base de datos de hashes (ver http://en.wikipedia.org/wiki/Rainbow_table ) para obtener el contraseñas originales
Una función hash siempre devuelve el mismo valor para la misma cadena de entrada. Digamos que mi usuario (Alice) tiene la contraseña secret
. Hashing secret
usando md5()
conduce al siguiente hash
5ebe2294ecd0e0f08eab7690d2a6ee69
Usando un diccionario (una lista de palabras comunes y contraseña) o uno de los varios sitios que le ofrecen ese servicio, el atacante (Mallory) puede descubrir fácilmente que la contraseña es secreta cuando ve en su diccionario que 5ebe2294ecd0e0f08eab7690d2a6ee69 = secret
.
El proceso de salazón antes de hash hace que sea más difícil usar un ataque de diccionario sin conocer su sal. Considera lo siguiente:
<?php
$salt = ''@!#%$@#$@SADLkwod,sdaDwqksjaoidjwq@#@!'';
$hash = md5($salt . ''secret'');
El hash resultante ahora es b58ad809eece17322de5024d79299f8a
pero la contraseña de Alice sigue siendo secret
. Ahora si Mallory pone sus manos en el hash salado, es probable que no encuentre la respuesta en su diccionario. Si lo hace, el diccionario le dará la respuesta incorrecta.
Nunca almacene una sal estática en su base de datos. Preferiblemente almacénelo con la configuración de su aplicación (que, por cierto, no debería estar disponible en la web).
Si va a utilizar una sal dinámica, necesitará usar la base de datos. Use una columna no nula de datos válidos existentes para construir su sal (la cadena de nombre de usuario encriptada con blowfish basada en una clave de cifrado secreta suele ser criptográficamente segura). No use una columna separada para la sal. Si no puede usar una columna existente, incorpore su sal en la misma columna que su hash. Por ejemplo, use los primeros 32 caracteres para su sal de 128 bits y luego los últimos 40 para su hash de 160 bits. La siguiente función generará dicho hash:
function seeded_sha1($string, $seed_bits) {
if(($seed_bits % 8) != 0) {
throw new Exception(''bits must be divisible by 8'');
}
$salt = '''';
for($i = 0; $i < $seed_bits; $i+=8) {
$salt .= pack(''c'', mt_rand());
}
$hexsalt = unpack(''h*hex'', $salt);
return $hexsalt[''hex''] . sha1($salt . $string);
}
function compare_seeded_sha1($plain, $hash) {
$sha1 = substr($hash, -40);
$salt = pack(''h*'', substr($hash, 0, -40));
$plain_hash = sha1($salt . $plain);
return ($plain_hash == $sha1);
}
Si un atacante ingresa en su base de datos mediante la inyección de SQL, al menos los hash que recupera no serán útiles, ya que él / ella no tendrá acceso a la configuración de su aplicación. Si tu servidor se enruta, es más o menos un juego sin importar lo que hagas.
Nota: Hay otros tipos de ataques posibles en md5()
lo que se usa un algoritmo de hashing más seguro, sha1()
por ejemplo. O, mejor aún, utilice el marco hash de contraseñas de PHP portátil , que se ha diseñado teniendo en cuenta la seguridad y es compatible con prácticamente cualquier versión de PHP.
require(''PasswordHash.php'');
$pwdHasher = new PasswordHash(8, FALSE);
// $hash is what you would store in your database
$hash = $pwdHasher->HashPassword( $password );
// $hash would be the $hashed stored in your database for this user
$checked = $pwdHasher->CheckPassword($password, $hash);
if ($checked) {
echo ''password correct'';
} else {
echo ''wrong credentials'';
}