Pregunta

  

Como esta pregunta es bastante popular, pensé que sería útil darle una actualización.

     

Permítanme enfatizar la respuesta correcta dada por AviD a esta pregunta:   

     

No debe almacenar ningún dato que necesite cifrar 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, identificado por la clave de la cookie.



Estoy buscando información sobre el "mejor" algoritmo de cifrado para cifrar cookies.

Tengo los siguientes requisitos:

  • Debe ser rápido
    el cifrado y descifrado de los datos se realizará para (casi) cada solicitud

  • Funcionará en pequeños conjuntos de datos, generalmente cadenas de alrededor de 100 caracteres o menos

  • Debe ser seguro, pero no es que estemos 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 que tiene un tamaño de bloque más pequeño.

¿Creo que ambos algoritmos proporcionan 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 cadenas de caracteres pequeños y si tal vez hay un algoritmo más adecuado para cifrar cookies.

Entonces mi pregunta es:
¿Qué algoritmo de cifrado es 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 de '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 no es seguro.

Sin embargo, tenemos el requisito de implementar una función 'recordarme'. La forma aceptada de hacerlo es mediante la configuración de una cookie. Si el cliente presenta esta cookie, se le permite acceder al sistema con (casi) los mismos derechos que si presentara la combinación de contraseña de nombre de usuario válida.

Por lo tanto, al menos queremos cifrar todos los datos en la cookie para que:
a) los usuarios malintencionados no pueden leer su contenido,
b) los usuarios malintencionados no pueden fabricar su propia cookie o manipularla.

(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 un sessionId / timestamp nada más. Probablemente podría usarse sin cifrado, pero no veo ningún daño en cifrarlo. (aparte del tiempo de cálculo).

Entonces, dado que tenemos que almacenar algunos datos en una cookie, ¿cuál es la mejor manera de encriptarlos?

Actualización 3
Las respuestas a esta pregunta me hicieron reconsiderar el enfoque elegido. De hecho, puedo hacer lo mismo sin necesidad de cifrado. En lugar de encriptar los datos, solo debería enviar datos que no tengan sentido sin su contexto y no se puedan adivinar .

Sin embargo, también estoy perdido:
Pensé que el cifrado nos permitía enviar datos al BigBadWorld ™, y aún así estar (bastante) seguro de que nadie podría leerlo ni alterarlo ...
¿No era ese el punto de encriptación?

Pero las siguientes reacciones se dirigen hacia: No confíe en el cifrado para lograr la seguridad.

¿Qué me estoy perdiendo?

¿Fue útil?

Solución

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 marginalmente más rápido ... Sin embargo, Blowfish tiene un gran inconveniente de un largo tiempo de configuración, lo que lo haría malo para su situación. Además, AES está más "probado".

Esto supone que realmente es necesario encriptar simétricamente sus datos de cookies. Como otros han señalado, realmente no debería ser necesario, y solo hay unos pocos casos extremos en los que no hay otra opción que hacerlo. Por lo general, le conviene cambiar el diseño y volver a los identificadores de sesión aleatorios o, si es necesario, hashes unidireccionales (utilizando SHA-256).
En su caso, además del " regular " identificador de sesión aleatorio, su problema es el "recordarme" característica: esto también debe implementarse como:

  • un número aleatorio largo, almacenado en la base de datos y asignado a 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 una sal, Y una clave secreta del servidor. Por supuesto, todo esto se puede verificar en el lado del servidor ...

Parece que nos hemos alejado un poco del tema de su pregunta original y específica, y hemos cambiado la base de su pregunta cambiando el diseño ...
Por lo tanto, mientras lo hagamos, también recomendaría FUERTEMENTE CONTRA esta característica de persistente "recordarme", por varias razones, la más importante de ellas:

  • Hace que sea mucho más probable que alguien pueda robar la clave para recordar de ese usuario, permitiéndole falsificar la identidad del usuario (y luego probablemente cambiar su contraseña);
  • CSRF - Falsificación de solicitudes de sitios cruzados . Su función permitirá efectivamente que un atacante anónimo provoque que usuarios desconocidos envíen '' autenticado '' solicitudes a su aplicación, incluso sin estar realmente conectado.

Otros consejos

Esto toca dos temas separados.

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 almacena datos en la cookie (como el nombre de usuario). Esta no es una buena idea. Cualquiera de estos datos es fundamentalmente no confiable al igual que los datos de formulario HTML no son confiables (independientemente de la validación de Javascript y / o las restricciones de longitud de HTML que use, si corresponde) porque un cliente es libre de enviar lo que quiera.

A menudo encontrará personas (con razón) que defienden la desinfección de los datos de formulario HTML, pero los datos de 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 lo 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, digamos, DES (heh), pero 256 bits de seguridad no significa necesariamente tanto como crees que es.

Por un lado, las SALT generalmente se generan de acuerdo con un algoritmo o son susceptibles de ataque.

Por otro lado, los datos de cookies son los principales candidatos para crib . Si se sabe o se sospecha que un nombre de usuario está en los datos cifrados, bueno, ahí está su cuna.

Esto nos lleva de vuelta al primer punto: secuestro.

Cabe señalar que en entornos de alojamiento compartido en PHP (como un ejemplo), los datos de su sesión simplemente se almacenan en el sistema de archivos y cualquier otra persona en ese mismo host puede leerlos, aunque no necesariamente saben en qué sitio se encuentra. es para. Por lo tanto, nunca almacene contraseñas de texto sin formato, números de tarjetas de crédito, detalles personales extensos o cualquier cosa que de otra manera se podría considerar confidencial en los datos de la sesión en dichos entornos sin algún tipo de cifrado o, mejor aún, simplemente almacenando una clave en la sesión y almacenando la información confidencial real datos en una base de datos.

Nota: lo anterior no es exclusivo de PHP.

Pero eso es encriptación del lado del servidor.

Ahora podría argumentar que cifrar una sesión con algunos datos adicionales hará que sea 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 / laptop en muchos lugares diferentes (por ejemplo, puntos de acceso Wifi, 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 se puede adivinar.

Entonces, hasta donde puedo decir, no hay ninguna razón real para usar el cifrado de cookies. Nunca pensé que existiera, pero a la luz de esta pregunta, busqué que se probara que estaba bien o mal. Encontré algunos hilos sobre personas que sugerían formas de encriptar datos de cookies, hacerlo de forma transparente con los módulos de Apache, etc., pero todos parecían motivados por la protección de los datos almacenados en una cookie (que no debería hacer).

Todavía no he visto un argumento de seguridad para cifrar una cookie que no representa más que una clave de sesión.

Felizmente se me demostrará que estoy equivocado si alguien puede señalar algo en contrario.

  

Advertencia de seguridad : estas dos funciones no son seguras. Están utilizando modo ECB y no pueden autenticar el texto cifrado . Vea esta respuesta para una mejor manera de avanzar.

Para aquellos que están leyendo y desean usar este método en scripts PHP. Aquí hay un ejemplo de trabajo usando 256 bits Rijndael (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 para leer en la página siguiente:

$data = decrypt(
  

Advertencia de seguridad : estas dos funciones no son seguras. Están utilizando modo ECB y no pueden autenticar el texto cifrado . Vea esta respuesta para una mejor manera de avanzar.

Para aquellos que están leyendo y desean usar este método en scripts PHP. Aquí hay un ejemplo de trabajo usando 256 bits Rijndael (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 para leer en la página siguiente:

<*>COOKIE['PHPSESSION'], 'longsecretsalt');

Puede lograr lo que desea de forma segura utilizando AES en modo EAX. El texto cifrado será más grande que el texto sin formato; eso es normal para el cifrado seguro.

El atacante, por supuesto, sabrá la longitud de su texto sin formato a partir del texto cifrado, pero no debería poder determinar nada más.

Generar claves AES al azar.

Asegúrese de usar un nonce nuevo para cada encriptación, y use los "datos asociados". campo para asegurarse de que una cosa que cifró para un propósito no se presente como otra (por lo que cosas como el nombre de usuario y el nombre de la cookie podrían ir allí)

  

las siguientes reacciones empujan hacia: Do   no confiar en el cifrado para lograr   seguridad.

Más " si no eres un experto en cifrado, subestimarás lo fácil que es equivocarse " ;. Por ejemplo, AFAICT nadie más en este hilo ha discutido los modos de encadenamiento o la integridad del mensaje, que cubre dos errores comunes de principiantes.

Fast, Encrypted Cookies with Libsodium

If you need fast, secure encrypted cookies in PHP, check out how Halite implements them. Halite relies on the libsodium PECL extension to provide secure cryptography.

<?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');

If you cannot install PECL extensions, ask your sysadmin or hosting provider to do it for you. If they refuse, you still have options.


Secure Encrypted Cookies in PHP, Hold the Salt Please

The other answers instruct you to encrypt your data with openssl or mcrypt, but they're missing a crucial step. If you want to safely encrypt data in PHP, you must authenticate your messages.

Using the OpenSSL extension, the process you would need to follow looks like this:


Preamble

  • (Before you even think about encryption) Generate a 128-bit, 192-bit, or 256-bit random string. This will be your master key.

    Do not use a human-readable password. If you, for some reason, must use a human-readable password, ask Cryptography SE for guidance.

    If you need special attention, my employer offers technology consulting services, including development of cryptography features.

Encryption

  1. Generate a random Initialization Vector (IV) or nonce. e.g. random_bytes(openssl_cipher_iv_length('aes-256-cbc'))
  2. Use HKDF or a similar algorithm for splitting your master key into two keys:
    1. An encryption key ($eKey)
    2. An authentication key ($aKey)
  3. Encrypt your string with openssl_encrypt() with your IV and an appropriate modate (e.g. aes-256-ctr) using your encryption key ($eKey) from step 2.
  4. Compute an authentication tag of your ciphertext from step 3, using a keyed hash function such as HMAC-SHA256. e.g. hash_hmac('sha256', $iv.$ciphertext, $aKey). It's very important to authenticate after encryption, and to encapsulate the IV/nonce as well.
  5. Package the authentication tag, IV or nonce, and ciphertext together and optionally encode it with bin2hex() or base64_encode(). (Warning: This approach might leak cache-timing information.)

Decryption

  1. Split your key, as per step 2 in encryption. We need the same two keys during decryption!
  2. (Optionally, decode and) unpack the MAC, IV, and ciphertext from the packed message.
  3. Verify the authentication tag by recalculating the HMAC of the IV/nonce and ciphertext with the user-provided HMAC by using hash_equals().
  4. If and only if step 3 passes, decrypt the ciphertext using $eKey.

If you want to see how this all looks together, see this answer which has sample code.

If this sounds like too much work, use defuse/php-encryption or zend-crypt and call it a day.


Remember Me Cookies

However, we have a requirement to implement a 'remeber me' feature. The accepted way to go about this is by setting a cookie. If the client presents this cookie, he or she is allowed access the system with (almost) equal rights as if he/she presented the valid username password combination.

Encryption is actually not the correct tool for this job. You want to follow this process for secure remember me cookies in PHP:

Generating a Remember Me Token

  1. Generate two random strings:
    1. A selector which will be used for database lookups. (The purpose of a random selector instead of just a sequential ID is to not leak how many active users are on your website. If you're comfortable leaking this information, feel free to just use a sequential ID.)
    2. A validator which will be used to authenticate the user automatically.
  2. Calculate a hash of validator (a simple SHA-256 hash will suffice).
  3. Store the selector and the hash of the validator in a database table reserved for automatic logins.
  4. Store the selector and validator in a cookie on the client.

Redeeming a Remember Me Token

  1. Split the incoming cookie into the selector and validator.
  2. Perform a database lookup (use prepared statements!) based on selector.
  3. If a row is found, calculate a hash of the validator.
  4. Compare the hash calculated in step 3 with the hash stored in the database, once again using hash_equals().
  5. If step 4 returns true, log the user in to the appropriate account.

This is the strategy that Gatekeeper adopted for long-term user authentication and it is the most secure strategy proposed to date for satisfying this requirement.

While both a very strong ones, AES is a standard.

As for security of small chunks of data: the smaller - the better. The less encrypted data is exposed, the longer you can use the key. There is always a theoretical limit of how much data can be encrypted within one key of given algorithm without exposing system to risks.

If you encrypt the cookie, the server still has to decode it to read it (to check for same key), therefore any encrypted cookie is pointless, because if stolen (and un-edited) it will still lead the hacker right to your account. Its just as unsafe as no encrypted at all.

I believe the real issue of someone stealing your cookie is the connection between the server and client. Use SSL connection provided by your host.

As for your cookie, you need to make a long random id per user in the database, (have it change every log on) and just set that as the cookie or session. The cookie that contains the key can be checked via php and if it is equal to an account or table in your database, dump the data on the web page like normal.

As pointed out a few times in previous comments, you must apply integrity protection to any ciphertext that you send out to the user and accept back. Otherwise the protected data can be modified, or the encryption key recovered.

Especially the PHP world is full of bad examples that ignore this (see PHP cryptography - proceed with care) but this does apply to any language.

One of few good examples I've seen is PHP-CryptLib which uses combined encryption-authentication mode to do the job. For Python pyOCB offers similar functionality.

Why do you want to encrypt the cookie?

As I see it, there are two cases: either you give the client the key, or you don't.

If you don't give the key to the client, then why are you giving them the data? Unless you're playing some weird game with breaking weak encryption (which you're explicitly not), you might as well store the data on the server.

If you do hand the client the key, then why do you encrypt it in the first place? If you don't encrypt the communication of the key, then encrypting the cookie is moot: a MITM can look at the cookie and send you any cookie he wants. If you use an encrypted channel to the client, why the extra overhead of encrypting the stored data?

If you're worried about other users on the client's machine reading the cookie, give up and assume the browser sets good permission bits :)

AES (also known as Rijndael) is the most popular. The block size is 128-bits, that's only 16-bytes, and you're talking "around 100 characters".

I think that "giving away" any data even encrypted when it is about username and password is not good ... There are many JS that can sniff it ... I suggest you create in users DB table a field cookie_auth or whatever ...

after first login gather : current: browser, IP,ans some own salt key, plus your hostname var ...

create a hash and store in that field ... set a cookie ... when cookie "responds" compare all of these with the stored hash and done ...

even if someone "steal" a cookie they won't be able to use it :-)

Hope this helps :-)

feha vision.to

In addition, I have tried the mcrypt_encrypt and one thing please keep in mind. If you do base64_encode(mcrypt_encrypt(...)).

and then later, you do base64_decode and output the encrypted data (echo). You probably will be screwed and not seeing anything. However, if you do mcrypt_decrypt( ... base64_decode($value) ). You will see the original data.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top