php - online - lastpass
¿Cómo puedo guardar las contraseñas de mis usuarios de forma segura? (6)
¿Cuánto más seguro es esto que el MD5 simple? Acabo de empezar a buscar la seguridad de las contraseñas. Soy bastante nuevo en PHP.
$salt = ''csdnfgksdgojnmfnb'';
$password = md5($salt.$_POST[''password'']);
$result = mysql_query("SELECT id FROM users
WHERE username = ''".mysql_real_escape_string($_POST[''username''])."''
AND password = ''$password''");
if (mysql_num_rows($result) < 1) {
/* Access denied */
echo "The username or password you entered is incorrect.";
}
else {
$_SESSION[''id''] = mysql_result($result, 0, ''id'');
#header("Location: ./");
echo "Hello $_SESSION[id]!";
}
Con PHP 5.5 (lo que describo está disponible incluso para versiones anteriores, vea a continuación) a la vuelta de la esquina, me gustaría sugerirle que use su nueva solución incorporada: password_hash()
y password_verify()
. Proporciona varias opciones para alcanzar el nivel de seguridad de contraseña que necesita (por ejemplo, especificando un parámetro de "costo" a través de la matriz $options
)
<?php
var_dump(password_hash("my-secret-password", PASSWORD_DEFAULT));
$options = array(
''cost'' => 7, // this is the number of rounds for bcrypt
// ''salt'' => ''TphfsM82o1uEKlfP9vf1f'', // you could specify a salt but it is not recommended
);
var_dump(password_hash("my-secret-password", PASSWORD_BCRYPT, $options));
?>
regresará
string(60) "$2y$10$w2LxXdIcqJpD6idFTNn.eeZbKesdu5y41ksL22iI8C4/6EweI7OK."
string(60) "$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d."
Como puede ver, la cadena contiene la sal y el costo especificado en las opciones. También contiene el algoritmo utilizado.
Por lo tanto, al verificar la contraseña (por ejemplo, cuando el usuario inicia sesión), al usar la función gratuita password_verify()
, extraerá los parámetros criptográficos necesarios del hash de contraseña.
Cuando no se especifica una sal, el hash de contraseña generado será diferente en cada llamada de password_hash()
porque la sal se genera aleatoriamente. Por lo tanto, la comparación de un hash anterior con un nuevo generado fallará, incluso para una contraseña correcta.
La verificación funciona así:
var_dump(password_verify("my-secret-password", ''$2y$10$BjHJbMCNWIJq7xiAeyFaHOGaO0jjNoE11e0YAer6Zu01OZHN/gk6K''));
var_dump(password_verify("wrong-password", ''$2y$10$BjHJbMCNWIJq7xiAeyFaHOGaO0jjNoE11e0YAer6Zu01OZHN/gk6K''));
var_dump(password_verify("my-secret-password", ''$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d.''));
var_dump(password_verify("wrong-password", ''$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d.''));
Espero que al proporcionar estas funciones incorporadas pronto proporcione una mejor seguridad de contraseñas en caso de robo de datos, ya que reduce la cantidad de pensamiento que el programador debe poner en una implementación adecuada.
Hay una pequeña biblioteca (un archivo PHP) que le dará password_hash
PHP 5.5 en PHP 5.3.7+: ircmaxell/password_compat
Eso está bien para mí. El Sr. Atwood escribió sobre la fortaleza de MD5 frente a las tablas arcoíris , y básicamente con una sal larga como que te sientes bien (aunque algunos signos de puntuación / números al azar podrían mejorarla).
También podría mirar SHA-1, que parece estar cada vez más popular en estos días.
La forma más fácil de proteger su esquema de almacenamiento de contraseñas es mediante el uso de una biblioteca estándar .
Debido a que la seguridad tiende a ser mucho más complicada y con más posibilidades de daños invisibles que la mayoría de los programadores podrían abordar solos, usar una biblioteca estándar es casi siempre la opción más fácil y más segura (si no la única) disponible.
La nueva API de contraseña de PHP (5.5.0+)
Si está utilizando PHP versión 5.5.0 o posterior, puede usar la nueva API de hashing de contraseña simplificada
Ejemplo de código con la API de contraseña de PHP:
<?php
// $hash is what you would store in your database
$hash = password_hash($_POST[''password''], PASSWORD_DEFAULT, [''cost'' => 12]);
// $hash would be the $hash (above) stored in your database for this user
$checked = password_verify($_POST[''password''], $hash);
if ($checked) {
echo ''password correct'';
} else {
echo ''wrong credentials'';
}
(En caso de que todavía esté usando legacy 5.3.7 o posterior, puede instalar ircmaxell/password_compat para tener acceso a las funciones integradas)
Mejorando los hashes salados: agregue pimienta
Si desea seguridad adicional, la gente de seguridad ahora (2017) recomienda agregar un " pepper " a los hash de contraseña salados (automáticamente).
Hay una caída simple en la clase que implementa de forma segura este patrón. Recomiendo: Netsilik/PepperedPasswords ( github ).
Viene con una licencia de MIT, por lo que puede usarlo como desee, incluso en proyectos propietarios.
Ejemplo de código usando Netsilik/PepperedPasswords
:
<?php
use Netsilik/Lib/PepperedPasswords;
// Some long, random, binary string, encoded as hexadecimal; stored in your configuration (NOT in your Database, as that would defeat the entire purpose of the pepper).
$config[''pepper''] = hex2bin(''012345679ABCDEF012345679ABCDEF012345679ABCDEF012345679ABCDEF'');
$hasher = new PepperedPasswords($config[''pepper'']);
// $hash is what you would store in your database
$hash = $hasher->hash($_POST[''password'']);
// $hash would be the $hash (above) stored in your database for this user
$checked = $hasher->verify($_POST[''password''], $hash);
if ($checked) {
echo ''password correct'';
} else {
echo ''wrong credentials'';
}
La biblioteca estándar VIEJA
Tenga en cuenta: ¡ ya no debería necesitar esto! Esto solo está aquí para propósitos históricos.
Eche un vistazo a: Marco de hashing de contraseñas PHP portátil : phpass y asegúrese de utilizar el algoritmo CRYPT_BLOWFISH
si es posible.
Ejemplo de código que usa phpass (v0.2):
<?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 $hash (above) stored in your database for this user
$checked = $pwdHasher->CheckPassword($password, $hash);
if ($checked) {
echo ''password correct'';
} else {
echo ''wrong credentials'';
}
PHPass se ha implementado en algunos proyectos bastante conocidos:
- phpBB3
- WordPress 2.5+ y también bbPress
- la versión Drupal 7, (módulo disponible para Drupal 5 y 6)
- otros
Lo bueno es que no necesita preocuparse por los detalles, esos detalles han sido programados por personas con experiencia y revisados por mucha gente en Internet.
Para obtener más información sobre los esquemas de almacenamiento de contraseñas, lea la publicación de blog de Jeff : Probablemente está almacenando contraseñas incorrectamente.
Hagas lo que hagas si optas por el enfoque de " lo haré yo mismo, gracias ", ya no utilices MD5
o SHA1
. Son buenos algoritmos de hash, pero se consideran rotos por razones de seguridad .
Actualmente, usar crypt , con CRYPT_BLOWFISH es la mejor práctica.
CRYPT_BLOWFISH en PHP es una implementación del hash Bcrypt. Bcrypt se basa en el cifrado de bloques Blowfish, haciendo uso de su costosa configuración de teclas para ralentizar el algoritmo.
Quiero agregar:
- No limite las contraseñas de los usuarios por longitud
La compatibilidad con sistemas antiguos a menudo establece un límite para la longitud máxima de la contraseña. Esta es una mala política de seguridad: si establece restricciones, configúrelo solo para la longitud mínima de contraseñas.
- No envíe contraseñas de usuario por correo electrónico
Para recuperar una contraseña olvidada, debe enviar la dirección mediante la cual el usuario puede cambiar la contraseña.
- Actualiza los hashes de las contraseñas de los usuarios
El hash de contraseña puede estar desactualizado (los parámetros del algoritmo pueden actualizarse). Al usar la función password_needs_rehash()
puede verificarlo.
Sus usuarios estarán mucho más seguros si utiliza consultas parametrizadas en lugar de concatenar declaraciones SQL. Y la sal debe ser única para cada usuario y debe almacenarse junto con el hash de contraseña.
Una mejor manera sería que cada usuario tenga una sal única.
El beneficio de tener una sal es que dificulta que un atacante pregenere la firma MD5 de cada palabra del diccionario. Pero si un atacante se entera de que tiene una sal fija, podría pregenerar la firma MD5 de cada palabra del diccionario con el prefijo de sal fija.
Una mejor manera es cada vez que un usuario cambia su contraseña, su sistema genera una sal aleatoria y almacena esa sal junto con el registro del usuario. Hace que sea un poco más caro comprobar la contraseña (ya que debe buscar la sal antes de generar la firma MD5), pero hace que sea mucho más difícil para un atacante pregenerar MD5.