29 de abril de 2015

Login PHP con crypt() y Blowfish

En esta entrada se utilizara la función crypt() y Blowfish, otra opción muy aceptable es utilizar password_hash(), dejo este link con una explicación del tema en Login PHP con password_hash(), pasando a la función crypt() con Blowfish como algoritmo de hash lo que se busca es mejorar un método común para proteger passwords como este:
<?php
function hash_password($password, $salt) 
{
    $hash = hash_hmac('SHA512', $password, $salt);
    for ($i = 0; $i < 5000; $i++) 
    {
        $hash = hash_hmac('SHA512', $hash, $salt);
    }
    
    return $hash;
}

$nombre = $_POST['nombre'];
$password = $_POST['password'];

$salt = str_replace('=', '.', base64_encode(mcrypt_create_iv(20)));
$hash = hash_password($password, $salt);
var_dump($hash);
?>
Por una codificación mas fuerte, la función hash que utilizaremos será crypt() que soporta de forma nativa varios algoritmos. Por defecto usa la codificación MD5 pero por razones de seguridad usaremos Blowfish, también puede utilizarse Verificando si mi versión de PHP soporta Blowfish El algoritmo Blowfish está disponible a partir de la versión 5.3 de PHP. Si quieres comprobar que tienes soporte para Blowfish puedes colocar este código en un archivo PHP:
<?php
  if(defined("CRYPT_BLOWFISH") && CRYPT_BLOWFISH) {
    echo "CRYPT_BLOWFISH esta disponible";
  }
?>
Si podemos usar Blowfish pasaremos a codificar la contraseña, en el caso de que no, tendremos que instalar la última versión de PHP. Para forzar que crypt() utilice el algoritmo Blowfish debemos colocar un salt especial, si la función no reconoce el salt que escribimos, el hash resultante estará codificado en MD5. La función queda asi:
<?php
crypt($password, '$2a$10$'.$unique_salt);
?>
El segundo parámetro es un poco raro, pero en realidad lo que hay ahí son instrucciones que deben seguir la salt para Blowfish $2y$ Indica que vamos a usar BlowFish. $10$ Indica el costo del cálculo. Puede ir de 04 a 31., con 10 como valor aceptable. $unique_salt Indica un salt para el cálculo del algoritmo. Una palabra/frase alfa-numérica de 22 caractéres (por lo menos así es para Blowfish) que pueden ser ./1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz. Teniendo en cuenta todo lo anterior, un script para registrar un usuario sería más o menos así:
<?php
$nombre = $_POST['nombre'];
$password = $_POST['pass'];

// Generamos un salt aleatoreo, de 22 caracteres para Bcrypt
$salt = substr(base64_encode(openssl_random_pseudo_bytes('30')), 0, 22);

// A Crypt no le gustan los '+' así que los vamos a reemplazar por puntos.
$salt = strtr($salt, array('+' => '.')); 

// Generamos el hash
$hash = crypt($password, '$2y$10$' . $salt);

// Guardamos los datos en la base de datos
$db = new PDO(.....);
$stmt = $db->prepare('INSERT INTO usuarios (nombre, pass) VALUES (?, ?)');
$stmt->execute(array($nombre, $hash)); 
?>
Y para validar la contraseña que esta almacenada en la base de datos contra un valor proporcionado por el usuario sería algo así:
<?php
$nombre = $_POST['nombre'];
$password = $_POST['pass'];

// Validamos $nombre, bla bla bla..

// Extraemos el hash de la base de datos
$db = new PDO(......);
$stmt = $db->prepare('SELECT pass
                      FROM usuarios
                      WHERE nombre = ?');
                      
$stmt->execute(array($nombre));
$dbHash = $stmt->fetchcolumn();

// Recalculamos a ver si el hash coincide.
if (crypt($password, $dbHash) == $dbHash)
    echo 'El usuario ha sido autenticado correctamente';
else
    die('Mal Password');
?>
Creando una función que haga el trabajo Para que nuestra contraseña sea más segura, vamos a crear una función que realice un salt aleatorio. El valor que se generará aleatoriamente para cada hash serán los últimos 22 caracteres.
<?php
function crypt_blowfish($password, $digito = 7) {
$set_salt = './1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
$salt = sprintf('$2a$%02d$', $digito);
for($i = 0; $i < 22; $i++)
{
 $salt .= $set_salt[mt_rand(0, 22)];
}
return crypt($password, $salt);
}
?>
Para crear el hash con la función que recién creamos solamente tenemos que escribirlo de la siguiente manera
<?php
$password = crypt_blowfish('stringdondeestaralacontraseña');
?>
Ahora para validar la contraseña que recién se ha creado y suponiendo que se guardo en la base de datos, vamos a recuperar ese valor en la variable $passwordenBD lo que se obtiene es:
<?php
$passwordenBD = '$2a$07$yMoJrJpwEPrmVnZx4KIyNuOAiOMQksjkV1EW0YRgVe33eYe/yT60y';

//Micontraseña representa el valor capturado desde el usuario

if( crypt('micontraseña', $passwordenBD) == $passwordenBD) {
 echo 'OK';
}
?>

Related Posts:

  • file_get_contents() y file_put_contents() en PHPfile_get_contents() se utiliza para obtener archivos desde PHP y es equivalente a usar fopen(), fgets() y fclose() por lo que es la manera abreviada y preferida de transmitir el contenido de un fichero a una cadena. Usa técn… Read More
  • Login PHP con crypt() y BlowfishEn esta entrada se utilizara la función crypt() y Blowfish, otra opción muy aceptable es utilizar password_hash(), dejo este link con una explicación del tema en Login PHP con password_hash(), pasando a la función crypt() co… Read More
  • Patrón Dependency InjectionRobert C. Martin afirma en el Principio de Inyección de Dependencias: A. Las clases de alto nivel no deberían depender de las clases de bajo nivel. Ambas deberían depender de las abstracciones. B. Las abstracciones no deber… Read More
  • ob_start PHPAl programar en PHP primero se realiza un procesamiento de la página que se muestra en el ordenador del usuario, luego se envía la petición al servidor y por último se envía al ordenador del usuario el resultado de procesar e… Read More
  • Login PHP con password_hash()Primero una aclaración…como no guardar contraseñas No guardar contraseñas en texto plano, esto debería ser obvio ya que si alguien tiene acceso a tu base de datos y a las contraseñas de tus usuarios, si un ataque externo…o in… Read More