Necesidad de almacenar de manera efímera contraseñas de terceros

5

Un servicio web particular en el que estoy escribiendo interfaces con una API. Cada llamada a la API requiere que se envíen el nombre de usuario y la contraseña del usuario, no se mantiene ningún estado.

Idealmente, cuando use mi servicio web, el usuario ingresará su nombre de usuario y contraseña de API una vez, y mi servicio web almacenará esa información hasta que finalice la sesión. Entiendo que no debo almacenar la contraseña de la API utilizando sesiones de PHP ni en una base de datos debido a problemas de seguridad. Por lo tanto, ¿cómo puedo almacenar y acceder de forma segura a la contraseña durante la sesión?

¿Sería seguro cifrar la contraseña, almacenar la contraseña cifrada en una cookie y la clave de cifrado en una sesión?

Tenga en cuenta que originalmente hice la pregunta (sin la solución propuesta) en SO: enlace Si hubiera bebido café primero, habría sabido publicar aquí en lugar de allí. La publicación SO se puede eliminar, pero no yo.

La respuesta dada es la que ahora estoy usando en producción, por lo que si hay fallas en el enfoque (almacenar la contraseña encriptada en la sesión de PHP, la clave de encriptación en la cookie) me gustaría mucho saberlo.

$encryptionKey = sha1(microtime(true).mt_rand(PHP_INT_MAX / 10, PHP_INT_MAX));
$encryptedPassword = mcrypt_encrypt(MCRYPT_BLOWFISH, $encryptionKey, $password, MCRYPT_MODE_CFB);
setcookie('atwood', $encryptionKey, 0);
$_SESSION['encryptedPassword'] = $encryptedPassword;

$password = mcrypt_decrypt(MCRYPT_BLOWFISH, $_COOKIE['atwood'], $_SESSION['encryptedPassword'], MCRYPT_MODE_CFB);
    
pregunta dotancohen 26.02.2013 - 09:36
fuente

1 respuesta

5

La pregunta que debe hacerse es: ¿cuál es el modelo de seguridad aquí?

Aparentemente, necesita transmitir la contraseña del usuario (un dato sensible) del usuario a los servidores de servicios de fondo. Pero el momento importa: el usuario humano ingresa su contraseña una vez , al comienzo de lo que el usuario piensa como "la sesión", y la contraseña debe transmitirse más tarde al back-end (las "llamadas API"). Así que debe haber algo de almacenamiento en algún lugar.

Las sesiones de PHP son almacenamiento del lado del servidor, como una colección de archivos pequeños con vencimiento basado en el tiempo. Lo que escribes en una "variable de sesión" en última instancia va al disco duro. Por lo tanto, podría considerarse una forma incorrecta almacenar una contraseña simple en una variable de sesión, ya que los contenidos físicos del disco duro no se destruyen de manera confiable cuando se elimina el archivo (al eliminarlo, el área de almacenamiento dedicada al archivo se marca como reutilizable, pero los datos en sí no se sobrescribirán hasta que el área se reutilice para otro archivo). Pero hay detalles:

  • Si teme una fuga de datos a través del acceso post mortem a un disco antiguo (o una cinta de respaldo), evite enviar el archivo al medio físico. Algunas personas ponen los archivos de sesión de PHP en un disco RAM : el disco RAM está configurado con las instalaciones del sistema operativo para tales cosas, y la ruta de acceso se ajusta con session_save_path() . Los archivos en un disco RAM nunca llegan al almacenamiento físico, por lo que se advierte la fuga. Por otro lado, todas las sesiones se perderán si el servidor se reinicia (esto es probablemente tolerable, pero depende de la configuración). Compartir la sesión en varios front-end también sería más complejo.

    Nota: en los sistemas Linux, hay tres formas de crear discos RAM: los discos RAM "verdaderos" (tamaño de hasta 16 MB cada uno, ajustado al momento del arranque) ), "ramfs" y "tmpfs". Este último utilizará RAM, pero también espacio de intercambio, por lo que el contenido puede todavía puede golpear el disco. Consulte esta página para obtener más información.

  • Si teme que se filtren datos de la sesión a través de un hack en vivo de su servidor, entonces considere que alguien que pueda obtener acceso de lectura a algún archivo protegido por el sistema operativo probablemente no esté lejos de tomar el control de la máquina completa, en ese momento simplemente se conectará al motor de PHP y tomará las contraseñas de usuario a medida que vayan llegando. No tiene mucho sentido ir a ese nivel de protección.

    Lo que sugiere es cifrar la contraseña del usuario y almacenar la clave en el navegador del cliente (como una cookie) y la contraseña cifrada en los archivos de la sesión; o puede hacer lo contrario (clave en la sesión de PHP, contraseña cifrada en la cookie). En ambos casos, la idea es que el atacante debe tomar los datos de la sesión y la cookie para desentrañar la contraseña. Esto solo tiene sentido si su modelo de seguridad asume que un atacante podría leer los archivos de la sesión (incluso cuando están solo en un disco RAM) pero no la RAM asignada al motor PHP (a través del cual las contraseñas necesariamente viajan en algún momento) . Esto no me parece un modelo muy realista.

Si do desea utilizar el cifrado, independientemente de su inutilidad aparente en esa situación específica, también puede hacerlo correctamente:

  • Genere la clave (específica del usuario) con un PRNG criptográficamente seguro ( openssl_random_pseudo_bytes() ).
  • Use el cifrado adecuado. Esto significa el surtido habitual de modo de encriptación, IV aleatorio (para ser almacenado a lo largo del archivo encriptado), relleno ... que es fácil equivocarse completamente. Es posible realizar el cifrado correcto con PHP, pero debe comprender lo que está haciendo hasta los detalles. En ese caso específico donde se genera una nueva clave para cada instancia de cifrado, debería ser suficiente usar un cifrado de bloque fuerte en el modo CFB y un IV convencional fijo, aunque perdería la longitud del ; y PHP tiene la costumbre de hacer cosas raras (por ejemplo, su modo "CFB" es en realidad CFB con retroalimentación de 8 bits , que es lento y de seguridad cuestionable para entradas largas).

pero aún así recomiendo no hacerlo, y en su lugar use el almacenamiento basado en RAM de las sesiones de PHP en el servidor.

    
respondido por el Thomas Pornin 26.02.2013 - 13:29
fuente

Lea otras preguntas en las etiquetas