password - ¿Estoy usando la función crypt() de PHP correctamente?
password_verify (5)
He estado usando crypt()
PHP como una forma de almacenar y verificar las contraseñas en mi base de datos. Uso el hash para otras cosas, pero crypt()
para las contraseñas. La documentación no es tan buena y parece que hay mucho debate. Estoy usando Blowfish y dos sales para cifrar una contraseña y almacenarla en la base de datos. Antes de almacenar el salt y la contraseña cifrada, (como un hash con sal), me di cuenta de que era redundante porque el salt forma parte de la cadena de contraseña cifrada.
Estoy un poco confundido sobre cómo los ataques de tabla arco iris funcionarían en crypt()
, de todos modos, esto se ve correcto desde el punto de vista de seguridad. Utilizo un segundo salt para adjuntar a la contraseña para aumentar la entropía de las contraseñas cortas, probablemente exagerar, pero ¿por qué no?
function crypt_password($password) {
if ($password) {
//find the longest valid salt allowed by server
$max_salt = CRYPT_SALT_LENGTH;
//blowfish hashing with a salt as follows: "$2a$", a two digit cost parameter, "$", and 22 base 64
$blowfish = ''$2a$10$'';
//get the longest salt, could set to 22 crypt ignores extra data
$salt = get_salt ( $max_salt );
//get a second salt to strengthen password
$salt2 = get_salt ( 30 ); //set to whatever
//append salt2 data to the password, and crypt using salt, results in a 60 char output
$crypt_pass = crypt ( $password . $salt2, $blowfish . $salt );
//insert crypt pass along with salt2 into database.
$sql = "insert into database....";
return true;
}
}
function get_salt($length) {
$options = ''ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789./'';
$salt = '''';
for($i = 0; $i <= $length; $i ++) {
$options = str_shuffle ( $options );
$salt .= $options [rand ( 0, 63 )];
}
return $salt;
}
function verify_password($input_password)
{
if($input_password)
{
//get stored crypt pass,and salt2 from the database
$stored_password = ''somethingfromdatabase'';
$stored_salt2 = ''somethingelsefromdatabase'';
//compare the crypt of input+stored_salt2 to the stored crypt password
if (crypt($input_password . $stored_salt2, $stored_password) == $stored_password) {
//authenticated
return true;
}
else return false;
}
else return false;
}
Debería echar un vistazo a PHPASS: http://www.openwall.com/phpass/ Es un marco de hashing de contraseñas que utiliza crypt () que se usa en proyectos como Wordpress y phpBB.
También hay un excelente artículo en este sitio web sobre hash, salazón y estiramiento de contraseñas utilizando crypt (): http://www.openwall.com/articles/PHP-Users-Passwords
ACTUALIZACIÓN: Actualmente hay una alternativa para la biblioteca PHPASS. En la próxima versión de PHP hay funciones especiales para hash y verificar contraseñas (usando bcrypt): http://www.php.net/manual/en/ref.password.php . Hay una biblioteca de compatibilidad que implementa estas funciones para PHP 5.3.7+: https://github.com/ircmaxell/password_compat
Esto es un uso incorrecto de crypt () porque está utilizando una primitiva en desuso. Blowfish es muy viejo, twish es el reemplazo e incluso eso es viejo porque el pez tres está casi finalizado. Debería estar usando un miembro de la familia sha2, sha256 o sha512 son ambas buenas opciones. crypt () se puede usar con sha256 o sha512, debe usar los parámetros CRYPT_SHA256 CRYPT_SHA512 respectivamente.
Además, sus sales tienen una relación entropía / tamaño muy pequeña, solo está utilizando un conjunto alfanumérico que es una broma porque las tablas de arco iris alfanuméricas son las más comunes. Debería usar un byte completo que base256, y recomiendo un salt que tenga 256 bytes de longitud. Tenga en cuenta que todas las funciones hash son binarias seguras por definición, por lo que no debería preocuparse por los bytes nulos y similares.
La idea de una tabla de arco iris es que un atacante puede hacer una tabla con todas las contraseñas posibles y sus hashes en casa.
P.ej
PASSWORD HASH
iloveSO gjroewjgo
password knbnogjwm
secret gjroehghe
jbieber rewgroewj
etc.
Con esta tabla, el atacante puede convertir rápidamente cualquier hash en una contraseña. La tabla de arco iris utiliza algunos trucos para que no se almacenen todos los hashes, pero de todos modos los calcula de antemano.
Al usar un salt, incluso cuando lo almacena con la contraseña, hace esto mucho más difícil. En lugar de marcar cada palabra en un diccionario, el atacante ahora tendría que escribir cada palabra con cada sal . Con una sal lo suficientemente larga, esto da suficientes combinaciones para que no sea factible calcular todos estos hashes.
Por lo tanto, una sal no debe ser una contraseña adicional, conocida solo por la aplicación, sino por cambiar la función hash para que no sea estándar.
Su uso de la crypt()
está bien. crypt($input, $stored) == $stored
es la forma en que está diseñado para ser utilizado.
Su función get_salt()
no es excelente, ya que utiliza la función rand()
menudo es deficiente. Debes considerar usar una función aleatoria más fuerte, como openssl_random_pseudo_bytes()
, en su lugar.
Use SHA-512 (si está disponible) con una sal que incluya time () y openssl_random_pseudo_bytes (). Crypt es consolidado / eficiente porque devuelve la sal insertada con la cadena hash.