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:
¿Cómo cifro y descifro una contraseña en PHP?
¿Cuál es el algoritmo más seguro para cifrar las contraseñas?
¿Dónde guardo la clave privada?
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)
¿De qué maneras se puede robar y descifrar la contraseña? ¿Qué necesito tener en cuenta?
php
security
encryption
passwords
HyderA
fuente
fuente
Respuestas:
Personalmente, usaría
mcrypt
como otros publicados. Pero hay mucho más para notar ...¿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:
¿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 ) .
¿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:
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$userKey
y$serverKey
, pero no el tercero$userSuppliedKey
. Si van a golpear al usuario con una llave inglesa, pueden obtener los$userSuppliedKey
otros 2, pero no los otros 2 (pero, de nuevo, si el usuario es golpeado con una llave inglesa, de todos modos es demasiado tarde).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.
¿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:
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 :Uso:
Luego, para descifrar:
Tenga en cuenta que usé
$e2
la 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:
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
$rounds
pará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) ...Integridad de los datos
Cifrado:
MCRYPT_BLOWFISH
o lasMCRYPT_RIJNDAEL_128
cifras yMCRYPT_MODE_CBC
para 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:
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á:
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 ...
fuente
-64
s para-128
ayudar (así que obtienes$enc = substr($data, 128, -128)
y$mac = substr($data, -128);
¿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.
fuente
El ejemplo del manual está ligeramente editado para este ejemplo):
Se podría utilizar MCRYPT_DECRYPT para descifrar la contraseña.
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!
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!
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.
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.
fuente
$pass = $text
. Creo que cambió eso para atender la pregunta, y no notó la segunda ocurrencia.MCRYPT_MODE_ECB
no usa un IV. En segundo lugar, si lo hiciera, necesitaría almacenar el IV ya que no puede descifrar los datos sin él ...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.
Y por otro lado:
fuente
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
openssl_public_encrypt
yopenssl_private_decrypt
Simétrico
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 problemas5
.fuente
openssl_private_decrypt()
.Intenté algo como esto, pero tenga en cuenta que no soy criptógrafo ni tengo un conocimiento profundo de
php
ningún lenguaje de programación. Es solo una idea. Mi idea es almacenarkey
en algún archivo odatabase
(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.Tenga en cuenta que es solo un concepto. Cualquier mejora en este código sería muy apreciable.
fuente
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.
fuente
Use password_hash y password_verify
Y para descifrar:
fuente