php - texto - mcrypt está en desuso, ¿cuál es la alternativa?
string strip_tags (10)
Como se detalla en otras respuestas aquí, la mejor solución que encontré es usar OpenSSL. Está integrado en PHP y no necesita ninguna biblioteca externa. Aquí hay ejemplos simples:
Para encriptar:
function encrypt($key, $payload) {
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length(''aes-256-cbc''));
$encrypted = openssl_encrypt($payload, ''aes-256-cbc'', $key, 0, $iv);
return base64_encode($encrypted . ''::'' . $iv);
}
Para descifrar:
function decrypt($key, $garble) {
list($encrypted_data, $iv) = explode(''::'', base64_decode($garble), 2);
return openssl_decrypt($encrypted_data, ''aes-256-cbc'', $key, 0, $iv);
}
Enlace de referencia: https://www.shift8web.ca/2017/04/how-to-encrypt-and-execute-your-php-code-with-mcrypt/
La extensión mcrypt está en deprecated se eliminará en PHP 7.2 de acuerdo con el comentario publicado here . Por lo tanto, estoy buscando una forma alternativa de cifrar las contraseñas.
En este momento estoy usando algo como
mcrypt_encrypt(MCRYPT_RIJNDAEL_128, md5($key, true), $string, MCRYPT_MODE_CBC, $iv)
Necesito su opinión sobre la mejor / mejor forma de encriptar las contraseñas, la contraseña encriptada, por supuesto, debe ser compatible con PHP 7.xx y también debe ser descifrable porque mis clientes quieren tener una opción para ''recuperar'' sus contraseñas sin generar una nueva uno.
Como se señaló, no debe almacenar las contraseñas de sus usuarios en un formato descifrable. El cifrado reversible proporciona una ruta fácil para que los piratas informáticos descubran las contraseñas de sus usuarios, lo que se extiende a poner las cuentas de sus usuarios en otros sitios en riesgo si usan la misma contraseña allí.
PHP proporciona un par de potentes funciones para el cifrado hash unidireccional con sal aleatoria:
password_hash()
y
password_verify()
.
Debido a que el hash se sala automáticamente al azar, no hay forma de que los piratas informáticos utilicen tablas precompiladas de hashes de contraseñas para realizar ingeniería inversa de la contraseña.
Establezca la opción
PASSWORD_DEFAULT
y las futuras versiones de PHP usarán automáticamente algoritmos más fuertes para generar hashes de contraseñas sin tener que actualizar su código.
Debe usar OpenSSL sobre
mcrypt
ya que se desarrolla y mantiene activamente.
Proporciona mejor seguridad, mantenibilidad y portabilidad.
En segundo lugar, realiza el cifrado / descifrado AES mucho más rápido.
Utiliza el relleno PKCS7 de forma predeterminada, pero puede especificar
OPENSSL_ZERO_PADDING
si lo necesita.
Para usar con una clave binaria de 32 bytes, puede especificar
aes-256-cbc
que es mucho más obvio que
MCRYPT_RIJNDAEL_128
.
Aquí está el ejemplo de código usando Mcrypt:
Biblioteca de cifrado AES-256-CBC no autenticada escrita en Mcrypt con relleno PKCS7.
/**
* This library is unsafe because it does not MAC after encrypting
*/
class UnsafeMcryptAES
{
const CIPHER = MCRYPT_RIJNDAEL_128;
public static function encrypt($message, $key)
{
if (mb_strlen($key, ''8bit'') !== 32) {
throw new Exception("Needs a 256-bit key!");
}
$ivsize = mcrypt_get_iv_size(self::CIPHER);
$iv = mcrypt_create_iv($ivsize, MCRYPT_DEV_URANDOM);
// Add PKCS7 Padding
$block = mcrypt_get_block_size(self::CIPHER);
$pad = $block - (mb_strlen($message, ''8bit'') % $block, ''8bit'');
$message .= str_repeat(chr($pad), $pad);
$ciphertext = mcrypt_encrypt(
MCRYPT_RIJNDAEL_128,
$key,
$message,
MCRYPT_MODE_CBC,
$iv
);
return $iv . $ciphertext;
}
public static function decrypt($message, $key)
{
if (mb_strlen($key, ''8bit'') !== 32) {
throw new Exception("Needs a 256-bit key!");
}
$ivsize = mcrypt_get_iv_size(self::CIPHER);
$iv = mb_substr($message, 0, $ivsize, ''8bit'');
$ciphertext = mb_substr($message, $ivsize, null, ''8bit'');
$plaintext = mcrypt_decrypt(
MCRYPT_RIJNDAEL_128,
$key,
$ciphertext,
MCRYPT_MODE_CBC,
$iv
);
$len = mb_strlen($plaintext, ''8bit'');
$pad = ord($plaintext[$len - 1]);
if ($pad <= 0 || $pad > $block) {
// Padding error!
return false;
}
return mb_substr($plaintext, 0, $len - $pad, ''8bit'');
}
}
Y aquí está la versión escrita con OpenSSL:
/**
* This library is unsafe because it does not MAC after encrypting
*/
class UnsafeOpensslAES
{
const METHOD = ''aes-256-cbc'';
public static function encrypt($message, $key)
{
if (mb_strlen($key, ''8bit'') !== 32) {
throw new Exception("Needs a 256-bit key!");
}
$ivsize = openssl_cipher_iv_length(self::METHOD);
$iv = openssl_random_pseudo_bytes($ivsize);
$ciphertext = openssl_encrypt(
$message,
self::METHOD,
$key,
OPENSSL_RAW_DATA,
$iv
);
return $iv . $ciphertext;
}
public static function decrypt($message, $key)
{
if (mb_strlen($key, ''8bit'') !== 32) {
throw new Exception("Needs a 256-bit key!");
}
$ivsize = openssl_cipher_iv_length(self::METHOD);
$iv = mb_substr($message, 0, $ivsize, ''8bit'');
$ciphertext = mb_substr($message, $ivsize, null, ''8bit'');
return openssl_decrypt(
$ciphertext,
self::METHOD,
$key,
OPENSSL_RAW_DATA,
$iv
);
}
}
Fuente: si está escribiendo la palabra MCRYPT en su código PHP, lo está haciendo mal .
Debe usar la función openssl_encrypt .
Es una buena práctica hacer hash de contraseñas para que no se puedan descifrar. Esto hace las cosas un poco más difíciles para los atacantes que pueden haber obtenido acceso a su base de datos o archivos.
Si debe cifrar sus datos y descifrarlos, encontrará una guía para el cifrado / descifrado seguro en https://paragonie.com/white-paper/2015-secure-php-data-encryption . Para resumir ese enlace:
- Use Libsodium - Una extensión PHP
- Si no puede usar Libsodium, use defuse defuse/php-encryption - Código PHP directo
- Si no puede usar Libsodium o desactivar / cifrado php, use OpenSSL : muchos servidores ya lo tendrán instalado. Si no, se puede compilar con --with-openssl [= DIR]
La implementación de PHP puro de Rijndael existe con phpseclib disponible como paquete compositor y funciona en PHP 7.3 (probado por mí).
Hay una página en los documentos phpseclib, que genera un código de muestra después de ingresar las variables básicas (cifrado, modo, tamaño de clave, tamaño de bit). Produce lo siguiente para Rijndael, BCE, 256, 256:
un código con mycrypt
$decoded = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, ENCRYPT_KEY, $term, MCRYPT_MODE_ECB);
funciona así con la biblioteca
$rijndael = new /phpseclib/Crypt/Rijndael(/phpseclib/Crypt/Rijndael::MODE_ECB);
$rijndael->setKey(ENCRYPT_KEY);
$rijndael->setKeyLength(256);
$rijndael->disablePadding();
$rijndael->setBlockLength(256);
$decoded = $rijndael->decrypt($term);
*
$term
fue
base64_decoded
Pude traducir mi objeto Crypto
-
Obtenga una copia de php con mcrypt para descifrar los datos antiguos. Fui a http://php.net/get/php-7.1.12.tar.gz/from/a/mirror , lo compilé, luego agregué la extensión ext / mcrypt (configure; make; make install). Creo que también tuve que agregar la línea extenstion = mcrypt.so al php.ini. Una serie de scripts para construir versiones intermedias de los datos con todos los datos sin cifrar.
-
Cree una clave pública y privada para openssl
openssl genrsa -des3 -out pkey.pem 2048 (set a password) openssl rsa -in pkey.pem -out pkey-pub.pem -outform PEM -pubout
-
Para cifrar (usando clave pública) use openssl_seal. Por lo que he leído, openssl_encrypt usando una clave RSA está limitado a 11 bytes menos que la longitud de la clave (Ver http://php.net/manual/en/function.openssl-public-encrypt.php comentario de Thomas Horsten)
$pubKey = openssl_get_publickey(file_get_contents(''./pkey-pub.pem'')); openssl_seal($pwd, $sealed, $ekeys, [ $pubKey ]); $encryptedPassword = base64_encode($sealed); $key = base64_encode($ekeys[0]);
Probablemente podría almacenar el binario en bruto.
-
Para descifrar (usando clave privada)
$passphrase="passphrase here"; $privKey = openssl_get_privatekey(file_get_contents(''./pkey.pem''), $passphrase); // I base64_decode() from my db columns openssl_open($encryptedPassword, $plain, $key, $privKey); echo "<h3>Password=$plain</h3>";
PD: no puede cifrar la cadena vacía ("")
PPS Esto es para una base de datos de contraseñas, no para la validación del usuario.
Puede usar el paquete phpseclib pollyfill. No puede usar open ssl o libsodium para cifrar / descifrar con rijndael 256. Otro problema, no necesita reemplazar ningún código.
Según lo sugerido por
@rqLizard
, puede utilizar en su lugar las funciones PHP
openssl_encrypt
/
openssl_decrypt
, que proporcionan una alternativa mucho mejor para implementar
AES
(el Estándar de cifrado avanzado) también conocido como cifrado Rijndael.
Según el siguiente comentario de Scott en php.net :
Si está escribiendo código para cifrar / cifrar datos en 2015, debe usar
openssl_encrypt()
yopenssl_decrypt()
. La biblioteca subyacente (libmcrypt
) ha sido abandonada desde 2007, y tiene unlibmcrypt
mucho peor que OpenSSL (que aprovechaAES-NI
en los procesadores modernos y es seguro para el tiempo de caché).Además,
MCRYPT_RIJNDAEL_256
no esAES-256
, es una variante diferente del cifrado de bloque Rijndael. Si deseaAES-256
enmcrypt
, debe usarMCRYPT_RIJNDAEL_128
con una clave de 32 bytes. OpenSSL hace que sea más obvio qué modo está utilizando (es decir,aes-128-cbc
frente aaes-256-ctr
).OpenSSL también utiliza relleno PKCS7 con modo CBC en lugar del relleno de bytes NULL de mcrypt. Por lo tanto, es más probable que mcrypt haga que su código sea vulnerable a los ataques de relleno de Oracle que OpenSSL.
Finalmente, si no está autenticando sus textos cifrados (Cifrar y luego MAC), lo está haciendo mal.
Otras lecturas:
- Uso de cifrado y autenticación correctamente (para desarrolladores de PHP) .
- Si está escribiendo la palabra MCRYPT en su código PHP, lo está haciendo mal .
Ejemplos de código
Ejemplo 1
Ejemplo de cifrado autenticado AES en modo GCM para PHP 7.1+
<?php
//$key should have been previously generated in a cryptographically safe way, like openssl_random_pseudo_bytes
$plaintext = "message to be encrypted";
$cipher = "aes-128-gcm";
if (in_array($cipher, openssl_get_cipher_methods()))
{
$ivlen = openssl_cipher_iv_length($cipher);
$iv = openssl_random_pseudo_bytes($ivlen);
$ciphertext = openssl_encrypt($plaintext, $cipher, $key, $options=0, $iv, $tag);
//store $cipher, $iv, and $tag for decryption later
$original_plaintext = openssl_decrypt($ciphertext, $cipher, $key, $options=0, $iv, $tag);
echo $original_plaintext."/n";
}
?>
Ejemplo # 2
Ejemplo de cifrado autenticado AES para PHP 5.6+
<?php
//$key previously generated safely, ie: openssl_random_pseudo_bytes
$plaintext = "message to be encrypted";
$ivlen = openssl_cipher_iv_length($cipher="AES-128-CBC");
$iv = openssl_random_pseudo_bytes($ivlen);
$ciphertext_raw = openssl_encrypt($plaintext, $cipher, $key, $options=OPENSSL_RAW_DATA, $iv);
$hmac = hash_hmac(''sha256'', $ciphertext_raw, $key, $as_binary=true);
$ciphertext = base64_encode( $iv.$hmac.$ciphertext_raw );
//decrypt later....
$c = base64_decode($ciphertext);
$ivlen = openssl_cipher_iv_length($cipher="AES-128-CBC");
$iv = substr($c, 0, $ivlen);
$hmac = substr($c, $ivlen, $sha2len=32);
$ciphertext_raw = substr($c, $ivlen+$sha2len);
$original_plaintext = openssl_decrypt($ciphertext_raw, $cipher, $key, $options=OPENSSL_RAW_DATA, $iv);
$calcmac = hash_hmac(''sha256'', $ciphertext_raw, $key, $as_binary=true);
if (hash_equals($hmac, $calcmac))//PHP 5.6+ timing attack safe comparison
{
echo $original_plaintext."/n";
}
?>
Ejemplo # 3
Según los ejemplos anteriores, he cambiado el siguiente código que tiene como objetivo cifrar el ID de sesión del usuario:
class Session {
/**
* Encrypts the session ID and returns it as a base 64 encoded string.
*
* @param $session_id
* @return string
*/
public function encrypt($session_id) {
// Get the MD5 hash salt as a key.
$key = $this->_getSalt();
// For an easy iv, MD5 the salt again.
$iv = $this->_getIv();
// Encrypt the session ID.
$encrypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $session_id, MCRYPT_MODE_CBC, $iv);
// Base 64 encode the encrypted session ID.
$encryptedSessionId = base64_encode($encrypt);
// Return it.
return $encryptedSessionId;
}
/**
* Decrypts a base 64 encoded encrypted session ID back to its original form.
*
* @param $encryptedSessionId
* @return string
*/
public function decrypt($encryptedSessionId) {
// Get the MD5 hash salt as a key.
$key = $this->_getSalt();
// For an easy iv, MD5 the salt again.
$iv = $this->_getIv();
// Decode the encrypted session ID from base 64.
$decoded = base64_decode($encryptedSessionId);
// Decrypt the string.
$decryptedSessionId = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $decoded, MCRYPT_MODE_CBC, $iv);
// Trim the whitespace from the end.
$session_id = rtrim($decryptedSessionId, "/0");
// Return it.
return $session_id;
}
public function _getIv() {
return md5($this->_getSalt());
}
public function _getSalt() {
return md5($this->drupal->drupalGetHashSalt());
}
}
dentro:
class Session {
const SESS_CIPHER = ''aes-128-cbc'';
/**
* Encrypts the session ID and returns it as a base 64 encoded string.
*
* @param $session_id
* @return string
*/
public function encrypt($session_id) {
// Get the MD5 hash salt as a key.
$key = $this->_getSalt();
// For an easy iv, MD5 the salt again.
$iv = $this->_getIv();
// Encrypt the session ID.
$ciphertext = openssl_encrypt($session_id, self::SESS_CIPHER, $key, $options=OPENSSL_RAW_DATA, $iv);
// Base 64 encode the encrypted session ID.
$encryptedSessionId = base64_encode($ciphertext);
// Return it.
return $encryptedSessionId;
}
/**
* Decrypts a base 64 encoded encrypted session ID back to its original form.
*
* @param $encryptedSessionId
* @return string
*/
public function decrypt($encryptedSessionId) {
// Get the Drupal hash salt as a key.
$key = $this->_getSalt();
// Get the iv.
$iv = $this->_getIv();
// Decode the encrypted session ID from base 64.
$decoded = base64_decode($encryptedSessionId, TRUE);
// Decrypt the string.
$decryptedSessionId = openssl_decrypt($decoded, self::SESS_CIPHER, $key, $options=OPENSSL_RAW_DATA, $iv);
// Trim the whitespace from the end.
$session_id = rtrim($decryptedSessionId, ''/0'');
// Return it.
return $session_id;
}
public function _getIv() {
$ivlen = openssl_cipher_iv_length(self::SESS_CIPHER);
return substr(md5($this->_getSalt()), 0, $ivlen);
}
public function _getSalt() {
return $this->drupal->drupalGetHashSalt();
}
}
Para aclarar, el cambio anterior no es una conversión verdadera ya que los dos cifrados usan un tamaño de bloque diferente y datos cifrados diferentes.
Además, el relleno predeterminado es diferente,
MCRYPT_RIJNDAEL
solo admite relleno nulo no estándar.
@zaph
Notas adicionales (de los comentarios de @ zaph):
-
Rijndael 128
(
MCRYPT_RIJNDAEL_128
) es equivalente a AES , sin embargo, Rijndael 256 (MCRYPT_RIJNDAEL_256
) no es AES-256 ya que el 256 especifica un tamaño de bloque de 256 bits, mientras que AES solo tiene un tamaño de bloque: 128 bits. Entonces, básicamente, Rijndael con un tamaño de bloque de 256 bits (MCRYPT_RIJNDAEL_256
) ha sido nombrado erróneamente debido a las elecciones de los desarrolladores de mcrypt . @zaph - Rijndael con un tamaño de bloque de 256 puede ser menos seguro que con un tamaño de bloque de 128 bits porque este último ha tenido muchas más revisiones y usos. En segundo lugar, la interoperabilidad se ve obstaculizada porque AES está generalmente disponible, mientras que Rijndael con un tamaño de bloque de 256 bits no lo está.
-
El cifrado con diferentes tamaños de bloque para Rijndael produce diferentes datos cifrados.
Por ejemplo,
MCRYPT_RIJNDAEL_256
(no equivalente aAES-256
) define una variante diferente del cifrado de bloque Rijndael con un tamaño de 256 bits y un tamaño de clave basado en la clave pasada, dondeaes-256-cbc
es Rijndael con un tamaño de bloque de 128 bits con un tamaño de clave de 256 bits. Por lo tanto, están utilizando diferentes tamaños de bloque que producen datos cifrados completamente diferentes, ya que mcrypt usa el número para especificar el tamaño del bloque, donde OpenSSL utilizó el número para especificar el tamaño de la clave (AES solo tiene un tamaño de bloque de 128 bits). Básicamente, AES es Rijndael con un tamaño de bloque de 128 bits y tamaños de clave de 128, 192 y 256 bits. Por lo tanto, es mejor usar AES, que se llama Rijndael 128 en OpenSSL.
Simplemente use
@
antes de cada
mcrypt
por ejemplo:
@mcrypt_module_open,
@mcrypt_get_block_size,
@mcrypt_generic_init
@mcrypt_generic
@mcrypt_generic_deinit
Eliminará la función mcrypt_module_open error privado y funcionará.