php - que - ¿Qué algoritmo de encriptación es mejor para encriptar cookies?
que es encriptacion de datos (12)
Advertencia de seguridad : estas dos funciones no son seguras. Están usando el modo ECB y no autentican el texto cifrado . Vea esta respuesta para una mejor manera de avanzar.
Para aquellos que quieran leer usando este método en scripts PHP. Aquí hay un ejemplo de trabajo que usa Rijndael de 256 bits (no AES).
function encrypt($text, $salt)
{
return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $salt, $text, MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND))));
}
function decrypt($text, $salt)
{
return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $salt, base64_decode($text), MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND)));
}
Luego, para guardar la cookie
setcookie("PHPSESSION", encrypt(''thecookiedata'', ''longsecretsalt''));
y leer en la página siguiente:
$data = decrypt($_COOKIE[''PHPSESSION''], ''longsecretsalt'');
Como esta pregunta es bastante popular, pensé que sería útil actualizarla.
Permítanme enfatizar la respuesta correcta dada por AviD a esta pregunta:
No debe almacenar ningún dato que necesite cifrado en su cookie. En su lugar, almacene una clave aleatoria de buen tamaño (128 bits / 16 bytes) en la cookie y almacene la información que desea mantener segura en el servidor, identificada por la clave de la cookie.
Estoy buscando información sobre el mejor algoritmo de cifrado para cifrar las cookies.
Tengo los siguientes requisitos:
Debe ser rápido
encriptar y descifrar los datos se hará para (casi) cada solicitudFuncionará en pequeños conjuntos de datos, generalmente cadenas de alrededor de 100 caracteres o menos
Debe ser seguro, pero no es como si estuviéramos asegurando transacciones bancarias
Necesitamos poder descifrar la información para que SHA1 y similares estén fuera.
Ahora he leído que Blowfish es rápido y seguro, y he leído que AES es rápido y seguro. Con Blowfish teniendo un tamaño de bloque más pequeño.
Creo que ambos algoritmos brindan una seguridad más que adecuada. entonces la velocidad se convertiría en el factor decisivo. Pero realmente no tengo idea si esos algoritmos son adecuados para la cadena de caracteres pequeños y si hay un algoritmo quizás mejor adaptado para cifrar las cookies.
Entonces mi pregunta es:
¿Qué algoritmo de cifrado es el mejor para cifrar datos de cookies?
Actualizar
Para ser más precisos, queremos encriptar 2 cookies: una con información de sesión y la otra con información ''recordarme''.
La plataforma es PHP como módulo apache en Linux en un VPS.
Actualización 2
Estoy de acuerdo con cletus que almacenar cualquier información en una cookie es inseguro.
Sin embargo, tenemos un requisito para implementar una función ''recordarme''. La forma aceptada de hacerlo es establecer una cookie. Si el cliente presenta esta cookie, puede acceder al sistema con derechos (casi) iguales que si presentara la combinación válida de contraseña de usuario.
Por lo tanto, al menos queremos encriptar todos los datos en la cookie para que:
a) los usuarios maliciosos no pueden leer sus contenidos,
b) los usuarios maliciosos no pueden fabricar sus propias cookies o alterarlas.
(Todos los datos de las cookies se desinfectan y se verifica su validez antes de hacer algo con ellos, pero esa es otra historia)
La cookie de sesión contiene una sessionId / timestamp nada más. Probablemente podría ser utilizado sin encriptación, pero no veo ningún daño en encriptarlo? (que no sea el tiempo de cálculo).
Entonces, dado que tenemos que almacenar algunos datos en una cookie, ¿cuál es la mejor manera de encriptarlo?
Actualización 3
Las respuestas a esta pregunta me hicieron reconsiderar el enfoque elegido. De hecho, puedo hacer lo mismo sin la necesidad de cifrado. En lugar de cifrar los datos, solo debería enviar datos que no tienen sentido sin su contexto y no pueden adivinarse .
Sin embargo, también estoy en una pérdida:
Pensé que el cifrado nos permitía enviar datos al BigBadWorld ™, y aún así (bastante) estar seguros de que nadie podía leer ni manipular el ...
¿No era ese el objetivo de la encriptación?
Pero las reacciones a continuación apuntan hacia: No confíe en el cifrado para lograr la seguridad.
¿¿Qué me estoy perdiendo??
Cookies rápidas y cifradas con Libsodium
Si necesita cookies cifradas rápidas y seguras en PHP, consulte cómo Halite implementa. Halite se basa en la extensión libsodium PECL para proporcionar criptografía segura.
<?php
use /ParagonIE/Halite/Cookie;
use /ParagonIE/Halite/Symmetric/Key;
use /ParagonIE/Halite/Symmetric/SecretKey;
// You can also use Key::deriveFromPassword($password, $salt, Key::CRYPTO_SECRETBOX);
$encryption_key = new SecretKey($some_constant_32byte_string_here);
$cookie = new Cookie($encryption_key);
$cookie->store(''index'', $any_value);
$some_value = $cookie->fetch(''other_index'');
Si no puede instalar las extensiones PECL, solicite a su administrador de sistemas o servidor de hosting que lo haga por usted. Si se niegan, todavía tienes opciones.
Secure Encrypted Cookies en PHP, mantenga el Salt Please
Las otras respuestas le indican que cifre sus datos con openssl o mcrypt, pero les falta un paso crucial. Si desea cifrar datos de manera segura en PHP , debe autenticar sus mensajes.
Al usar la extensión OpenSSL, el proceso que necesitaría seguir se ve así:
Preámbulo
(Antes de siquiera pensar en el cifrado) Genere una cadena aleatoria de 128 bits, 192 bits o 256 bits. Esta será tu llave maestra .
No use una contraseña legible por humanos. Si usted, por algún motivo, debe usar una contraseña legible por el ser humano, solicite a Cryptography SE una guía.
Si necesita atención especial, mi empleador ofrece servicios de consultoría tecnológica , incluido el desarrollo de funciones de criptografía.
Cifrado
- Genere un Vector de Inicialización aleatorio (IV) o nonce. eg
random_bytes(openssl_cipher_iv_length(''aes-256-cbc''))
- Use HKDF o un algoritmo similar para dividir su clave maestra en dos claves:
- Una clave de cifrado (
$eKey
) - Una clave de autenticación (
$aKey
)
- Una clave de cifrado (
- Encripte su cadena con
openssl_encrypt()
con su IV y un modo apropiado (por ejemplo,aes-256-ctr
) usando su clave de cifrado ($eKey
) desde el paso 2. - Calcule una etiqueta de autenticación de su texto cifrado desde el paso 3, usando una función hash con clave como HMAC-SHA256. por ejemplo,
hash_hmac(''sha256'', $iv.$ciphertext, $aKey)
. Es muy importante autenticarse después del cifrado y encapsular el IV / nonce también. - Empaquete la etiqueta de autenticación, IV o nonce, y el texto cifrado juntos y
bin2hex()
opcionalmente conbin2hex()
obase64_encode()
. (Advertencia: este enfoque puede filtrar la información de sincronización del caché).
Descifrado
- Divida su clave, como en el paso 2 en el cifrado. ¡Necesitamos las mismas dos claves durante el descifrado!
- (Opcionalmente, descodifique y descomprima el MAC, el IV y el texto cifrado del mensaje empaquetado).
- Verifique la etiqueta de autenticación volviendo a calcular el HMAC de IV / nonce y texto cifrado con el HMAC proporcionado por el usuario utilizando
hash_equals()
. - Si, y solo si pasa el paso 3, descifre el texto cifrado usando
$eKey
.
Si desea ver cómo se ve todo esto junto, vea esta respuesta que tiene código de muestra .
Si esto parece demasiado trabajo, use defuse/php-encryption o zend-crypt y zend-crypt un día.
Recordarme cookies
Sin embargo, tenemos un requisito para implementar una función ''recordarme''. La forma aceptada de hacerlo es establecer una cookie. Si el cliente presenta esta cookie, puede acceder al sistema con derechos (casi) iguales que si presentara la combinación válida de contraseña de usuario.
En realidad, el cifrado no es la herramienta correcta para este trabajo. Desea seguir este proceso para recordar cookies seguras en PHP :
Generando un Token de Remember Me
- Genera dos cadenas aleatorias:
- Un
selector
que se usará para búsquedas en la base de datos. (El propósito de un selector aleatorio en lugar de solo un ID secuencial es no filtrar cuántos usuarios activos hay en su sitio web. Si se siente cómodo filtrando esta información, puede usar una ID secuencial). - Un
validator
que se usará para autenticar al usuario automáticamente.
- Un
- Calcule un hash de
validator
(un hash SHA-256 simple será suficiente). - Almacene el
selector
y el hash delvalidator
en una tabla de base de datos reservada para inicios de sesión automáticos. - Almacene el
selector
y elvalidator
en una cookie en el cliente.
Canjear un token de Remember Me
- Divida la cookie entrante en el
selector
y elvalidator
. - Realice una búsqueda en la base de datos (¡use declaraciones preparadas !) Según el
selector
. - Si se encuentra una fila, calcule un hash del
validator
. - Compare el hash calculado en el paso 3 con el hash almacenado en la base de datos, una vez más usando
hash_equals()
. - Si el paso 4 devuelve verdadero, inicie sesión en la cuenta correspondiente.
Esta es la estrategia que adoptó Gatekeeper para la autenticación de usuarios a largo plazo y es la estrategia más segura propuesta hasta la fecha para satisfacer este requisito.
¿Por qué quieres encriptar la cookie?
Según lo veo, hay dos casos: o le das la llave al cliente, o no.
Si no le da la clave al cliente, ¿por qué les está dando los datos? A menos que esté jugando un juego extraño con el cifrado débil (que no lo es explícitamente), también podría almacenar los datos en el servidor.
Si le entrega la clave al cliente, ¿por qué lo encripta en primer lugar? Si no encriptas la comunicación de la clave, entonces la encriptación de la cookie es irrelevante: un MITM puede mirar la cookie y enviarte cualquier cookie que quiera. Si usa un canal encriptado para el cliente, ¿por qué la sobrecarga adicional de encriptar los datos almacenados?
Si le preocupa que otros usuarios en el equipo del cliente lean la cookie, abandone y suponga que el navegador establece buenos bits de permiso :)
AES (también conocido como Rijndael) es el más popular. El tamaño del bloque es de 128 bits, eso es solo 16 bytes, y estás hablando de "alrededor de 100 caracteres".
Además, probé mcrypt_encrypt
y una cosa, por favor, tenga en cuenta. Si haces base64_encode(mcrypt_encrypt(...))
.
y luego, haces base64_decode
y base64_decode
los datos encriptados ( echo
). Probablemente estarás jodido y no verás nada. Sin embargo, si lo hace mcrypt_decrypt( ... base64_decode($value) )
. Verás los datos originales.
Como se señaló algunas veces en comentarios anteriores, debe aplicar protección de integridad a cualquier texto cifrado que envíe al usuario y lo acepte nuevamente. De lo contrario, los datos protegidos se pueden modificar o la clave de cifrado se puede recuperar.
Especialmente el mundo PHP está lleno de malos ejemplos que ignoran esto (ver ipsec.pl/node/1085 ) pero esto se aplica a cualquier idioma.
Uno de los pocos buenos ejemplos que he visto es PHP-CryptLib que usa el modo de autenticación de cifrado combinado para hacer el trabajo. Para Python, pyOCB ofrece una funcionalidad similar.
Creo que "regalar" cualquier información incluso encriptada cuando se trata de nombre de usuario y contraseña no es buena ... Hay muchas JS que pueden olfatearla ... Sugiero que crees en los usuarios una tabla DB un campo cookie_auth o lo que sea ... .
después del primer inicio de sesión recopilar: actual: navegador, IP, y algunas propias clave de sal, además de su nombre de host var ...
crea un hash y almacena en ese campo ... establece una cookie ... cuando la cookie "responde" compara todos estos con el hash almacenado y listo ...
incluso si alguien "roba" una cookie no podrá usarla :-)
Espero que esto ayude :-)
feha vision.to
Esto está tocando dos cuestiones separadas.
En primer lugar, secuestro de sesión . Aquí es donde un tercero descubre, por ejemplo, una cookie autenticada y obtiene acceso a los detalles de otra persona.
En segundo lugar, hay seguridad de datos de sesión . Con esto quiero decir que almacenas datos en la cookie (como el nombre de usuario). Esta no es una buena idea Cualquiera de estos datos es fundamentalmente indigno de confianza, al igual que los datos de formularios HTML no son confiables (independientemente de la validación de JavaScript y / o las restricciones de longitud de HTML que utilice, si corresponde) porque un cliente puede enviar lo que quiera.
A menudo encontrará personas (con razón) que abogan por desinfectar los datos del formulario HTML, pero los datos de las cookies se aceptarán ciegamente por su valor nominal. Gran error. De hecho, nunca almaceno ninguna información en la cookie. Lo veo como una clave de sesión y eso es todo.
Si tiene la intención de almacenar datos en una cookie, le recomiendo que reconsidere.
El cifrado de estos datos no hace que la información sea más confiable porque el cifrado simétrico es susceptible al ataque de fuerza bruta. Obviamente, AES-256 es mejor que, por ejemplo, DES (heh), pero 256 bits de seguridad no significa necesariamente tanto como crees.
Por un lado, los SALT generalmente se generan según un algoritmo o son susceptibles de ataque.
Por otro lado, los datos de cookies son un candidato principal para los ataques de crib . Si se sabe o se sospecha que un nombre de usuario está en los datos cifrados, oirá, ahí está su cuna.
Esto nos lleva de vuelta al primer punto: secuestro.
Cabe señalar que en los entornos de alojamiento compartido en PHP (como un ejemplo) los datos de la sesión simplemente se almacenan en el sistema de archivos y pueden ser leídos por cualquier otra persona en ese mismo host, aunque no necesariamente saben para qué sitio es. Por lo tanto, nunca almacene contraseñas de texto plano, números de tarjetas de crédito, detalles personales extensos ni nada que pueda considerarse como confidencial en los datos de sesión en dichos entornos sin algún tipo de encriptación o, mejor aún, solo almacene una clave en la sesión y almacene la información confidencial real. datos en una base de datos.
Nota: lo anterior no es exclusivo de PHP.
Pero eso es el cifrado del lado del servidor.
Ahora podría argumentar que el cifrado de una sesión con algunos datos adicionales lo hará más seguro contra el secuestro. Un ejemplo común es la dirección IP del usuario. El problema es que muchas personas usan la misma PC / computadora portátil en muchos lugares diferentes (por ejemplo, zonas Wi-Fi, trabajo, hogar). Además, muchos entornos utilizarán una variedad de direcciones IP como dirección de origen, particularmente en entornos corporativos.
También puede usar el agente de usuario, pero eso es adivinable.
Entonces, en realidad, hasta donde puedo decir, no hay una razón real para usar en absoluto el cifrado de cookies. Nunca pensé que lo había, pero a la luz de esta pregunta busqué que se probara que era correcto o incorrecto. Encontré algunas conversaciones sobre personas que sugerían formas de encriptar datos de cookies, hacerlo de forma transparente con módulos de Apache, etc., pero todo parecía motivado por la protección de los datos almacenados en una cookie (lo que no debería hacer).
Todavía tengo que ver un argumento de seguridad para cifrar una cookie que no representa más que una clave de sesión.
Estaré felizmente demostrado que estoy equivocado si alguien puede señalar algo en contra.
No hay razón real para no ir con AES con 256 bits. Asegúrese de usar esto en modo CBC , y PKCS # 7 relleno. Como dijiste, rápido y seguro.
He leído (no probado) que Blowfish puede ser un poco más rápido ... Sin embargo, Blowfish tiene un inconveniente importante de un tiempo de configuración largo, lo que lo haría malo para su situación. Además, AES es más "probado".
Esto supone que realmente es necesario encriptar simétricamente sus datos de cookies. Como otros han notado, realmente no debería ser necesario, y hay solo unos pocos casos extremos en los que no hay otra opción más que hacerlo. Normalmente, le conviene más cambiar el diseño y volver a identificadores de sesión aleatorios o, si es necesario, hashes unidireccionales (utilizando SHA-256).
En su caso, además del identificador de sesión aleatorio "regular", su problema es la función "recordarme"; esto también debe implementarse como:
- un número aleatorio largo, almacenado en la base de datos y correlacionado con una cuenta de usuario;
- o un hash con clave (por ejemplo, HMAC) que contiene, por ejemplo, el nombre de usuario, la marca de tiempo, mebbe a salt, Y una clave secreta del servidor. Por supuesto, esto puede verificarse desde el servidor ...
Parece que nos hemos alejado un poco del tema de tu pregunta original específica, y cambiamos la base de tu pregunta cambiando el diseño ...
Así que mientras lo hagamos, también recomendaría EN CONTRA de esta característica de "recordarme" persistente, por varias razones, la más grande de ellas:
- Hace que sea mucho más probable que alguien robe la clave de recuerdo de ese usuario, lo que le permite falsificar la identidad del usuario (y luego probablemente cambie su contraseña);
- CSRF : falsificación de solicitudes entre sitios . Su característica permitirá efectivamente que un atacante anónimo haga que los usuarios desconocidos envíen solicitudes "autenticadas" a su aplicación, incluso sin estar realmente conectado.
Puede lograr lo que quiere de forma segura mediante el uso de AES en modo EAX. El texto cifrado será más grande que el texto sin formato; eso es normal para una encriptación segura.
El atacante, por supuesto, sabrá la longitud de su texto plano del texto cifrado, pero no debería poder determinar nada más.
Genera claves AES al azar.
Asegúrate de utilizar una nueva versión para cada encriptación y utiliza el campo "datos asociados" para asegurarte de que algo que encriptaste para un propósito no se presente como para otro (por lo que cosas como el nombre de usuario y el nombre de la cookie podrían entrar). ahí)
las reacciones a continuación presionan hacia: No confíe en el cifrado para lograr la seguridad.
Más "si no eres un experto en cifrado, subestimarás lo fácil que es equivocarte". Por ejemplo, AFAICT nadie más en este hilo ha discutido modos de encadenamiento o integridad de mensaje, que cubre dos errores comunes de principiantes.
Si bien ambos son muy fuertes, AES es un estándar.
En cuanto a la seguridad de pequeños fragmentos de datos: cuanto más pequeños, mejor. Mientras menos datos encriptados estén expuestos, más tiempo podrá usar la clave. Siempre hay un límite teórico de la cantidad de datos que se pueden cifrar dentro de una clave de algoritmo determinado sin exponer el sistema a riesgos.
Si encriptas la cookie, el servidor aún tiene que decodificarla para leerla (para buscar la misma clave), por lo tanto, cualquier cookie encriptada es inútil, porque si se la roban (y no se edita), eso llevará al intruso a tu cuenta . Es tan inseguro como no cifrado en absoluto.
Creo que el problema real de alguien robando su cookie es la conexión entre el servidor y el cliente. Use la conexión SSL proporcionada por su anfitrión.
En cuanto a su cookie, debe crear una larga identificación aleatoria por usuario en la base de datos (haga que cambie cada inicio de sesión) y simplemente configure esa cookie o sesión. La cookie que contiene la clave se puede verificar a través de php y si es igual a una cuenta o tabla en su base de datos, vacíe los datos en la página web como siempre.