Cifrado bidireccional: necesito almacenar contraseñas que se puedan recuperar

174

Estoy creando una aplicación que almacenará contraseñas, que el usuario puede recuperar y ver. Las contraseñas son para un dispositivo de hardware, por lo que la comprobación de los hashes está fuera de discusión.

Lo que necesito saber es:

  1. ¿Cómo cifro y descifro una contraseña en PHP?

  2. ¿Cuál es el algoritmo más seguro para cifrar las contraseñas?

  3. ¿Dónde guardo la clave privada?

  4. En lugar de almacenar la clave privada, ¿es una buena idea exigir a los usuarios que ingresen la clave privada cada vez que necesiten una contraseña descifrada? (Se puede confiar en los usuarios de esta aplicación)

  5. ¿De qué maneras se puede robar y descifrar la contraseña? ¿Qué necesito tener en cuenta?

HyderA
fuente
1
Nota: Libsodium ahora se compila en el núcleo de PHP para> = 7.2. Esta sería la solución "ir a" ahora, ya que está llena de métodos modernos a diferencia de mcrypt, que se considera obsoleto y se ha eliminado.
Expositor

Respuestas:

212

Personalmente, usaría mcryptcomo otros publicados. Pero hay mucho más para notar ...

  1. ¿Cómo cifro y descifro una contraseña en PHP?

    Vea a continuación una clase sólida que se encarga de todo por usted:

  2. ¿Cuál es el algoritmo más seguro para cifrar las contraseñas?

    más seguro ? cualquiera de ellos. El método más seguro si va a cifrar es proteger contra vulnerabilidades de divulgación de información (XSS, inclusión remota, etc.). Si sale, el atacante eventualmente puede descifrar el cifrado (ningún cifrado es 100% irreversible sin la clave - Como @NullUserException señala que esto no es del todo cierto. Hay algunos esquemas de cifrado que son imposibles de descifrar como OneTimePad ) .

  3. ¿Dónde guardo la clave privada?

    Lo que haría es usar 3 teclas. Uno es proporcionado por el usuario, uno es específico de la aplicación y el otro es específico del usuario (como una sal). La clave específica de la aplicación se puede almacenar en cualquier lugar (en un archivo de configuración fuera de la raíz web, en una variable de entorno, etc.). El usuario específico se almacenaría en una columna en la base de datos junto a la contraseña cifrada. El usuario suministrado uno no sería almacenado. Entonces, harías algo como esto:

    $key = $userKey . $serverKey . $userSuppliedKey;

    El beneficio allí es que cualquiera de las 2 claves puede verse comprometida sin que los datos se vean comprometidos. Si hay un ataque de inyección SQL, pueden obtener el $userKey, pero no el otro 2. Si hay un exploit de servidor local, pueden obtener $userKeyy $serverKey, pero no el tercero $userSuppliedKey. Si van a golpear al usuario con una llave inglesa, pueden obtener los $userSuppliedKeyotros 2, pero no los otros 2 (pero, de nuevo, si el usuario es golpeado con una llave inglesa, de todos modos es demasiado tarde).

  4. En lugar de almacenar la clave privada, ¿es una buena idea exigir a los usuarios que ingresen la clave privada cada vez que necesiten una contraseña descifrada? (Se puede confiar en los usuarios de esta aplicación)

    Absolutamente. De hecho, esa es la única forma en que lo haría. De lo contrario, necesitaría almacenar una versión sin cifrar en un formato de almacenamiento duradero (memoria compartida como APC o memcached, o en un archivo de sesión). Eso es exponerse a compromisos adicionales. Nunca almacene la versión sin cifrar de la contraseña en otra cosa que no sea una variable local.

  5. ¿De qué maneras se puede robar y descifrar la contraseña? ¿Qué necesito tener en cuenta?

    Cualquier forma de compromiso de sus sistemas les permitirá ver datos cifrados. Si pueden inyectar código o acceder a su sistema de archivos, pueden ver los datos descifrados (ya que pueden editar los archivos que descifran los datos). Cualquier forma de reproducción o ataque MITM también les dará acceso completo a las teclas involucradas. Oler el tráfico HTTP sin procesar también les dará las claves.

    Use SSL para todo el tráfico. Y asegúrese de que nada en el servidor tenga ningún tipo de vulnerabilidad (CSRF, XSS, inyección de SQL, escalada de privilegios, ejecución remota de código, etc.).

Editar: Aquí hay una implementación de clase PHP de un método de cifrado fuerte:

/**
 * A class to handle secure encryption and decryption of arbitrary data
 *
 * Note that this is not just straight encryption.  It also has a few other
 *  features in it to make the encrypted data far more secure.  Note that any
 *  other implementations used to decrypt data will have to do the same exact
 *  operations.  
 *
 * Security Benefits:
 *
 * - Uses Key stretching
 * - Hides the Initialization Vector
 * - Does HMAC verification of source data
 *
 */
class Encryption {

    /**
     * @var string $cipher The mcrypt cipher to use for this instance
     */
    protected $cipher = '';

    /**
     * @var int $mode The mcrypt cipher mode to use
     */
    protected $mode = '';

    /**
     * @var int $rounds The number of rounds to feed into PBKDF2 for key generation
     */
    protected $rounds = 100;

    /**
     * Constructor!
     *
     * @param string $cipher The MCRYPT_* cypher to use for this instance
     * @param int    $mode   The MCRYPT_MODE_* mode to use for this instance
     * @param int    $rounds The number of PBKDF2 rounds to do on the key
     */
    public function __construct($cipher, $mode, $rounds = 100) {
        $this->cipher = $cipher;
        $this->mode = $mode;
        $this->rounds = (int) $rounds;
    }

    /**
     * Decrypt the data with the provided key
     *
     * @param string $data The encrypted datat to decrypt
     * @param string $key  The key to use for decryption
     * 
     * @returns string|false The returned string if decryption is successful
     *                           false if it is not
     */
    public function decrypt($data, $key) {
        $salt = substr($data, 0, 128);
        $enc = substr($data, 128, -64);
        $mac = substr($data, -64);

        list ($cipherKey, $macKey, $iv) = $this->getKeys($salt, $key);

        if (!hash_equals(hash_hmac('sha512', $enc, $macKey, true), $mac)) {
             return false;
        }

        $dec = mcrypt_decrypt($this->cipher, $cipherKey, $enc, $this->mode, $iv);

        $data = $this->unpad($dec);

        return $data;
    }

    /**
     * Encrypt the supplied data using the supplied key
     * 
     * @param string $data The data to encrypt
     * @param string $key  The key to encrypt with
     *
     * @returns string The encrypted data
     */
    public function encrypt($data, $key) {
        $salt = mcrypt_create_iv(128, MCRYPT_DEV_URANDOM);
        list ($cipherKey, $macKey, $iv) = $this->getKeys($salt, $key);

        $data = $this->pad($data);

        $enc = mcrypt_encrypt($this->cipher, $cipherKey, $data, $this->mode, $iv);

        $mac = hash_hmac('sha512', $enc, $macKey, true);
        return $salt . $enc . $mac;
    }

    /**
     * Generates a set of keys given a random salt and a master key
     *
     * @param string $salt A random string to change the keys each encryption
     * @param string $key  The supplied key to encrypt with
     *
     * @returns array An array of keys (a cipher key, a mac key, and a IV)
     */
    protected function getKeys($salt, $key) {
        $ivSize = mcrypt_get_iv_size($this->cipher, $this->mode);
        $keySize = mcrypt_get_key_size($this->cipher, $this->mode);
        $length = 2 * $keySize + $ivSize;

        $key = $this->pbkdf2('sha512', $key, $salt, $this->rounds, $length);

        $cipherKey = substr($key, 0, $keySize);
        $macKey = substr($key, $keySize, $keySize);
        $iv = substr($key, 2 * $keySize);
        return array($cipherKey, $macKey, $iv);
    }

    /**
     * Stretch the key using the PBKDF2 algorithm
     *
     * @see http://en.wikipedia.org/wiki/PBKDF2
     *
     * @param string $algo   The algorithm to use
     * @param string $key    The key to stretch
     * @param string $salt   A random salt
     * @param int    $rounds The number of rounds to derive
     * @param int    $length The length of the output key
     *
     * @returns string The derived key.
     */
    protected function pbkdf2($algo, $key, $salt, $rounds, $length) {
        $size   = strlen(hash($algo, '', true));
        $len    = ceil($length / $size);
        $result = '';
        for ($i = 1; $i <= $len; $i++) {
            $tmp = hash_hmac($algo, $salt . pack('N', $i), $key, true);
            $res = $tmp;
            for ($j = 1; $j < $rounds; $j++) {
                 $tmp  = hash_hmac($algo, $tmp, $key, true);
                 $res ^= $tmp;
            }
            $result .= $res;
        }
        return substr($result, 0, $length);
    }

    protected function pad($data) {
        $length = mcrypt_get_block_size($this->cipher, $this->mode);
        $padAmount = $length - strlen($data) % $length;
        if ($padAmount == 0) {
            $padAmount = $length;
        }
        return $data . str_repeat(chr($padAmount), $padAmount);
    }

    protected function unpad($data) {
        $length = mcrypt_get_block_size($this->cipher, $this->mode);
        $last = ord($data[strlen($data) - 1]);
        if ($last > $length) return false;
        if (substr($data, -1 * $last) !== str_repeat(chr($last), $last)) {
            return false;
        }
        return substr($data, 0, -1 * $last);
    }
}

Tenga en cuenta que estoy usando una función añadida en PHP 5.6: hash_equals. Si está en un nivel inferior a 5.6, puede usar esta función de sustitución que implementa una función de comparación segura de tiempo usando la verificación HMAC doble :

function hash_equals($a, $b) {
    $key = mcrypt_create_iv(128, MCRYPT_DEV_URANDOM);
    return hash_hmac('sha512', $a, $key) === hash_hmac('sha512', $b, $key);
}

Uso:

$e = new Encryption(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC);
$encryptedData = $e->encrypt($data, $key);

Luego, para descifrar:

$e2 = new Encryption(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC);
$data = $e2->decrypt($encryptedData, $key);

Tenga en cuenta que usé $e2la segunda vez para mostrarle que diferentes instancias aún descifrarán los datos correctamente.

Ahora, cómo funciona / por qué usarlo sobre otra solución:

  1. Llaves

    • Las teclas no se usan directamente. En cambio, la clave se estira mediante una derivación PBKDF2 estándar.

    • La clave utilizada para el cifrado es única para cada bloque de texto cifrado. Por lo tanto, la clave suministrada se convierte en una "clave maestra". Por lo tanto, esta clase proporciona rotación de claves para claves de cifrado y autenticación.

    • NOTA IMPORTANTE , el $roundsparámetro está configurado para claves aleatorias verdaderas de potencia suficiente (128 bits de aleatorización criptográfica segura como mínimo). Si va a utilizar una contraseña o una clave no aleatoria (o menos aleatoria que 128 bits de CS aleatoria), debe aumentar este parámetro. Sugeriría un mínimo de 10000 para las contraseñas (cuanto más pueda pagar, mejor, pero se agregará al tiempo de ejecución) ...

  2. Integridad de los datos

    • La versión actualizada utiliza ENCRYPT-THEN-MAC, que es un método mucho mejor para garantizar la autenticidad de los datos cifrados.
  3. Cifrado:

    • Utiliza mcrypt para realizar el cifrado. Sugeriría usar cualquiera MCRYPT_BLOWFISHo las MCRYPT_RIJNDAEL_128cifras y MCRYPT_MODE_CBCpara el modo. Es lo suficientemente fuerte y sigue siendo bastante rápido (un ciclo de cifrado y descifrado tarda aproximadamente 1/2 segundo en mi máquina).

Ahora, en cuanto al punto 3 de la primera lista, lo que eso le daría es una función como esta:

function makeKey($userKey, $serverKey, $userSuppliedKey) {
    $key = hash_hmac('sha512', $userKey, $serverKey);
    $key = hash_hmac('sha512', $key, $userSuppliedKey);
    return $key;
}

Podrías estirarlo en la makeKey()función, pero como se estirará más tarde, no hay realmente un gran punto para hacerlo.

En cuanto al tamaño de almacenamiento, depende del texto sin formato. Blowfish utiliza un tamaño de bloque de 8 bytes, por lo que tendrá:

  • 16 bytes para la sal
  • 64 bytes para el hmac
  • longitud de datos
  • Relleno para que la longitud de datos% 8 == 0

Entonces, para una fuente de datos de 16 caracteres, habrá 16 caracteres de datos para encriptar. Eso significa que el tamaño real de los datos cifrados es de 16 bytes debido al relleno. Luego agregue los 16 bytes para el salt y los 64 bytes para el hmac y el tamaño total almacenado es de 96 bytes. Entonces, en el mejor de los casos, una sobrecarga de 80 caracteres, y en el peor, una sobrecarga de 87 caracteres ...

Espero que eso ayude...

Nota: 12/12/12: Acabo de actualizar esta clase con un método de cifrado MUCHO mejor, usando mejores claves derivadas y arreglando la generación MAC ...

ircmaxell
fuente
3
Alguien no entiende lo que significa "descanso". @IRC buen trabajo en la clase, es un muy buen código.
jcolebrand
1
Lo siguiente devuelve falso. ¿Alguna idea de por qué? $ x = nuevo cifrado (MCRYPT_BlOWFISH, MCRYPT_MODE_CBC); $ prueba = $ x-> cifrar ("prueba", "a"); echo var_dump ($ x-> descifrar ($ prueba, "a"));
The Wavelength
2
Ah, y de nuevo en la función de descifrado, cambiar los dos -64s para -128ayudar (así que obtienes $enc = substr($data, 128, -128)y$mac = substr($data, -128);
cosmorogers
44
@ircmaxell Ha pasado bastante tiempo desde la última revisión del código, así que me pregunto si está actualizado. Necesito usar algo similar para una solicitud financiera y sería bueno que
aceptaras
2
¡Advertencia! La extensión mcrypt ha sido abandonada durante casi una década, y también fue bastante compleja de usar. Por lo tanto, ha quedado en desuso a favor de OpenSSL, donde se eliminará del núcleo y pasará a PECL en PHP 7.2. th1.php.net/manual/en/migration71.deprecated.php
vee
15

¿Cómo cifro y descifro una contraseña en PHP? Mediante la implementación de uno de los muchos algoritmos de cifrado. (o usando una de muchas bibliotecas)

¿Cuál es el algoritmo más seguro para cifrar las contraseñas? Hay toneladas de algoritmos diferentes, ninguno de los cuales es 100% seguro. Pero muchos de ellos son lo suficientemente seguros para el comercio e incluso para fines militares.

¿Dónde guardo la clave privada? Si ha decidido implementar la clave pública - algoritmo de criptografía (por ejemplo, RSA), no almacena la clave privada. El usuario tiene clave privada. su sistema tiene clave pública que puede almacenarse en cualquier lugar que desee.

En lugar de almacenar la clave privada, ¿es una buena idea exigir a los usuarios que ingresen la clave privada cada vez que necesiten una contraseña descifrada? (Se puede confiar en los usuarios de esta aplicación) Bueno, si su usuario puede recordar números primos ridículamente largos, entonces, sí, por qué no. Pero, en general, necesitaría crear un sistema que permita al usuario almacenar su clave en algún lugar.

¿De qué maneras se puede robar y descifrar la contraseña? ¿Qué necesito tener en cuenta? Esto depende del algoritmo utilizado. Sin embargo, siempre asegúrese de no enviar la contraseña sin cifrar hacia o desde el usuario. Cifre / descifre en el lado del cliente, o use https (u otro medio criptográfico del usuario para asegurar la conexión entre el servidor y el cliente).

Sin embargo, si todo lo que necesita es almacenar las contraseñas de forma cifrada, le sugiero que utilice un cifrado XOR simple. El principal problema con este algoritmo es que podría romperse fácilmente mediante análisis de frecuencia. Sin embargo, como generalmente las contraseñas no están hechas de largos párrafos de texto en inglés, no creo que deba preocuparse por eso. El segundo problema con XOR Cipher es que si tiene un mensaje en forma cifrada y descifrada, puede encontrar fácilmente la contraseña con la que se cifró. Nuevamente, no es un gran problema en su caso, ya que solo afecta al usuario que ya se vio comprometido por otros medios.

Ivan
fuente
En la respuesta 3, cuando dices que los usuarios tienen clave privada, no entiendo lo que eso significa. No recomienda que el usuario pase claves privadas a la aplicación manualmente, entonces, ¿de qué otra manera se pasan las claves privadas a la aplicación?
HyderA
Bueno, eso es un pequeño problema. La clave privada se puede almacenar en el archivo de texto y luego copiar y pegar en la aplicación. La clave también podría almacenarse en el servidor, pero en este caso aún debería cifrarse con algún otro algoritmo de cifrado como XOR. El uso de XOR aquí en este caso es lo suficientemente seguro, ya que solo hay un par de mensaje de contraseña y el mensaje es bastante aleatorio, por lo que no se puede utilizar el análisis de frecuencia en frío.
Ivan
44
Ciertamente, no recomendaría implementar un algoritmo de cifrado usted mismo, hay demasiadas trampas potenciales y las bibliotecas existentes han sido probadas y analizadas por muchas personas.
Long Ears
El principal problema con XOR es que si alguien roba los datos de su aplicación y conoce solo una de las contraseñas de un usuario, puede descifrar todas las demás contraseñas para ese usuario.
Long Ears
1
@Ivan: sí, pero este es uno de los casos en los que creo que el bricolaje es realmente malo a menos que REALMENTE entiendas la criptografía. Existen cifrados fuertes, ¿por qué no usarlos?
ircmaxell
13
  1. La función PHP que busca es Mcrypt ( http://www.php.net/manual/en/intro.mcrypt.php ).

El ejemplo del manual está ligeramente editado para este ejemplo):

<?php
$iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$key = "This is a very secret key";
$pass = "PasswordHere";
echo strlen($pass) . "\n";

$crypttext = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $pass, MCRYPT_MODE_ECB, $iv);
echo strlen($crypttext) . "\n";
?>

Se podría utilizar MCRYPT_DECRYPT para descifrar la contraseña.

  1. El mejor algoritmo es bastante subjetivo: pregunte a 5 personas y obtenga 5 respuestas. Personalmente, si el valor predeterminado (Blowfish) no es lo suficientemente bueno para usted, ¡probablemente tenga mayores problemas!

  2. Dado que PHP lo necesita para encriptar, no estoy seguro de que pueda ocultarlo en cualquier lugar, agradecemos sus comentarios al respecto. ¡Las mejores prácticas de codificación PHP estándar se aplican, por supuesto!

  3. Dado que la clave de cifrado estará en su código de todos modos, no estoy seguro de lo que obtendrá, siempre que el resto de su aplicación sea segura.

  4. Obviamente, si se roban la contraseña encriptada y la clave de encriptación, entonces el juego ha terminado.

Pondría un jinete en mi respuesta: no soy un experto en cifrado de PHP, pero creo que lo que he respondido es una práctica estándar. Agradezco los comentarios que otros puedan tener.

Jon Rhoades
fuente
$pass = $text. Creo que cambió eso para atender la pregunta, y no notó la segunda ocurrencia.
HyderA
3
Dos cosas a tener en cuenta. Primero, MCRYPT_MODE_ECBno usa un IV. En segundo lugar, si lo hiciera, necesitaría almacenar el IV ya que no puede descifrar los datos sin él ...
ircmaxell 03 de
"El mejor algoritmo es bastante subjetivo: pregunte a 5 personas y obtenga 5 respuestas. Personalmente, si el valor predeterminado (Blowfish) no es lo suficientemente bueno para usted, ¡probablemente tenga mayores problemas!" Esto está totalmente mal. Cualquier experto en criptografía estará más o menos de acuerdo con gist.github.com/tqbf/be58d2d39690c3b366ad que excluye específicamente el pez globo
Scott Arciszewski
6

Muchos usuarios han sugerido usar mcrypt ... lo cual es correcto, pero me gusta ir un paso más allá para que sea fácilmente almacenado y transferido (ya que a veces los valores cifrados pueden dificultar el envío utilizando otras tecnologías como curl o json) .

Después de haber encriptado con éxito usando mcrypt, ejecútelo a través de base64_encode y luego conviértalo a código hexadecimal. Una vez en el código hexadecimal, es fácil de transferir de varias maneras.

$td = mcrypt_module_open('tripledes', '', 'ecb', '');
$iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
$key = substr("SUPERSECRETKEY",0,mcrypt_enc_get_key_size($td));
mcrypt_generic_init($td, $key, $iv);
$encrypted = mcrypt_generic($td, $unencrypted);
$encrypted = $ua."||||".$iv;
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
$encrypted = base64_encode($encrypted);
$encrypted = array_shift(unpack('H*', $encrypted));

Y por otro lado:

$encrypted = pack('H*', $encrypted);
$encrypted = base64_decode($encrypted);
list($encrypted,$iv) = explode("||||",$encrypted,2);
$td = mcrypt_module_open('tripledes', '', 'ecb', '');
$key = substr("SUPERSECRETKEY",0,mcrypt_enc_get_key_size($td));
mcrypt_generic_init($td, $key, $iv);
$unencrypted = mdecrypt_generic($td, $encrypted);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
Bradley
fuente
Mcrypt no es una gran opción
Scott Arciszewski
2
Bueno, fue en 2011: P
Bradley
5

Solo sugeriría el cifrado de clave pública si desea la capacidad de establecer la contraseña de un usuario sin su interacción (esto puede ser útil para restablecimientos y contraseñas compartidas).

Llave pública

  1. La extensión OpenSSL , específicamente openssl_public_encryptyopenssl_private_decrypt
  2. Esto sería RSA directo, suponiendo que sus contraseñas encajen en el tamaño de la clave: relleno, de lo contrario, necesitará una capa simétrica
  3. Almacene ambas claves para cada usuario, la frase de contraseña de la clave privada es la contraseña de su aplicación

Simétrico

  1. La extensión de Mcrypt
  2. AES-256 es probablemente una apuesta segura, pero esta podría ser una pregunta SO en sí misma
  3. No, esta sería la contraseña de su aplicación

Ambos

4. Sí, los usuarios tendrían que ingresar la contraseña de su aplicación cada vez, pero almacenarla en la sesión generaría otros problemas

5.

  • Si alguien roba los datos de la aplicación, es tan seguro como el cifrado simétrico (para el esquema de clave pública, se usa para proteger la clave privada con la frase de contraseña).
  • Definitivamente, solo debe poder acceder a su aplicación a través de SSL, preferiblemente utilizando certificados de cliente.
  • Considere agregar un segundo factor para la autenticación que solo se usaría una vez por sesión, como un token enviado por SMS.
Orejas largas
fuente
Evite mcrypt, tenga cuidado con openssl_private_decrypt().
Scott Arciszewski
2

Intenté algo como esto, pero tenga en cuenta que no soy criptógrafo ni tengo un conocimiento profundo de phpningún lenguaje de programación. Es solo una idea. Mi idea es almacenar keyen algún archivo o database(o ingresar manualmente) qué (ubicación) no se puede predecir fácilmente (y, por supuesto, cualquier cosa se descifrará algún día, el concepto es alargar el tiempo de descifrado) y cifrar información confidencial.

$iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH , MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$key = "evenifyouaccessmydatabaseyouwillneverfindmyemail";
$text = "[email protected]";
echo "Key : ".$key."<br/>";
echo "Text : ".$text . "<br/>";
echo "Md5 : ".md5($text). "<br/>";
echo "Sha1 : ".sha1($text). "<br/>";



$crypttext = mcrypt_encrypt(MCRYPT_BLOWFISH , $key, $text, MCRYPT_MODE_ECB, $iv);
echo "Crypted Data : ".$crypttext."<br>";

$base64 = base64_encode($crypttext);
echo "Encoded Data : ".$base64."<br/>";
$decode =  base64_decode($base64);


$decryptdata = mcrypt_decrypt(MCRYPT_BLOWFISH , $key, $crypttext, MCRYPT_MODE_ECB, $iv);

echo "Decoded Data : ".ereg_replace("?", null ,  $decryptdata); 
//event if i add '?' to the sting to the text it works, I don't know why.

Tenga en cuenta que es solo un concepto. Cualquier mejora en este código sería muy apreciable.

Santosh Linkha
fuente
2

Las contraseñas son para un dispositivo de hardware, por lo que no se pueden verificar los hashes

Eh? No entiendo. ¿Simplemente quiere decir que la contraseña debe ser recuperable?

Como otros han dicho, la extensión mcrypt proporciona acceso a muchas funciones criptográficas; sin embargo, está invitando a sus usuarios a poner todos sus huevos en una canasta, una que potencialmente será un objetivo para los atacantes, y si ni siquiera sabe cómo comenzar a resolver el problema, entonces está perjudicando a sus usuarios. No está en condiciones de comprender cómo proteger los datos.

La mayoría de las vulnerabilidades de seguridad se producen no porque el algoritmo subyacente sea defectuoso o inseguro, sino por problemas con la forma en que se utiliza el algoritmo dentro del código de la aplicación.

Dicho esto, es posible construir un sistema razonablemente seguro.

Solo debe considerar el cifrado asimétrico si tiene un requisito para que un usuario cree un mensaje seguro que pueda ser leído por otro usuario (específico). La razón es que es computacionalmente costoso. Si solo desea proporcionar un repositorio para que los usuarios ingresen y recuperen sus propios datos, el cifrado simétrico es adecuado.

Sin embargo, si almacena la clave para descifrar el mensaje en el mismo lugar que el mensaje cifrado (o donde se almacena el mensaje cifrado), entonces el sistema no es seguro. Use el mismo token para autenticar al usuario que para la clave de descifrado (o en el caso del cifrado asimétrico, use el token como la contraseña de la clave privada). Dado que necesitará almacenar el token en el servidor donde se realiza el descifrado al menos temporalmente, es posible que desee considerar usar un sustrato de almacenamiento de sesión que no se pueda buscar o pasar el token directamente a un daemon asociado con la sesión que almacenaría el token en memoria y realizar el descifrado de mensajes bajo demanda.

symcbean
fuente
1

Use password_hash y password_verify

<?php
/**
 * In this case, we want to increase the default cost for BCRYPT to 12.
 * Note that we also switched to BCRYPT, which will always be 60 characters.
 */
$options = [
    'cost' => 12,
];
echo password_hash("rasmuslerdorf", PASSWORD_BCRYPT, $options)."\n";
?>

Y para descifrar:

<?php
// See the password_hash() example to see where this came from.
$hash = '$2y$07$BCryptRequires22Chrcte/VlQH0piJtjXl.0t1XkA8pw9dMXTpOq';

if (password_verify('rasmuslerdorf', $hash)) {
    echo 'Password is valid!';
} else {
    echo 'Invalid password.';
}
?>
jvitoroc
fuente