¿Cómo almaceno los datos de sesión en un servidor de forma segura?

1

Estoy creando un sistema donde la seguridad es importante y me gustaría almacenar los detalles de la sesión en el servidor en una tabla de sesión. Sin embargo, me preocupa que si un atacado se apoderara de la base de datos, tendrían acceso a todos los detalles de la sesión para todos los usuarios registrados.

¿Cómo puedo resolver esto? ¿Es solo para mantener los detalles de la sesión cifrados y enviar un secreto al usuario como una cookie, lo que significa que en cada solicitud hay descifrado? Esto obviamente ralentizará al usuario.

No puedo almacenar los detalles de la sesión en una cookie en la máquina del usuario ya que esta cookie puede crecer mucho y puede exceder los 4kb (tamaño máximo del encabezado de la solicitud).

    
pregunta Yule 09.01.2017 - 16:53
fuente

3 respuestas

3

En general, la información de la sesión no suele estar cifrada en el lado del servidor. En general, se supone que, como parte del modelo de amenaza, si un atacante obtiene acceso al servidor, entonces ya tiene todo lo que necesita. Los datos de la sesión en sí no suelen ser más sensibles que el resto del contenido de la base de datos.

Hay algunas opciones:

  • Almacénelos en el sistema de archivos en texto plano. Si su modelo de amenaza sugiere que SQLi es más probable que el acceso al sistema de archivos, este es un movimiento fácil.
  • Cifre los ID de sesión y los datos utilizando las rutinas de cifrado incorporadas en la base de datos. Esto lo protege contra casos en los que se compromete una copia de seguridad de la base de datos, pero no lo protegerá contra el robo de disco o contra un atacante con acceso a SQL.
  • Cifre sus ID de sesión y los datos de sesión en la base de datos, usando una clave establecida en un archivo de configuración en el servidor en algún lugar. El beneficio de esto es que el atacante necesitaría acceso tanto a la base de datos (por ejemplo, a través de una inyección SQL) como al sistema de archivos al mismo tiempo para descifrar los ID de sesión y los datos de sesión.
  • Cifre los ID de sesión y los datos utilizando una clave elegida al azar que se almacena en caché dentro del proceso del demonio del servidor (por ejemplo, APC o memcached para PHP). Esto sería extremadamente difícil para un atacante obtener acceso sin la ejecución completa del código en el sistema, pero tiene el inconveniente de que todos los datos de la sesión se invalidarán si reinicia el proceso del servidor.

Recomiendo el uso de cifrado autenticado, con cifrado y autenticidad separados. El pseudocódigo para el cifrado es el siguiente:

iv = secure_random(16)
encrypted = iv || AES-CBC-128(session_id || session_data, enc_key, iv)
auth_encrypted = HMAC-SHA256(encrypted, auth_key) || encrypted

El pseudocódigo para el descifrado es el siguiente:

mac = auth_encrypted[0:31]
encrypted = auth_encrypted[32:]
expected_mac = HMAS-SHA256(encrypted, auth_key)
if mac != encrypted_mac:
    session was tampered with
else:
    iv = encrypted[0:15]
    encrypted = encrypted[16:]
    decrypted = AES-CBC-128_Decrypt(encrypted, enc_key, iv)

Esto proporciona cifrado autenticado para evitar la manipulación de los datos de sesión en el lado del servidor.

    
respondido por el Polynomial 09.01.2017 - 17:16
fuente
0

El enfoque estándar para esto es hacer que las sesiones tengan un tiempo de vida relativamente corto: la forma más común para que un atacante obtenga acceso a la base de datos es obtener copias de seguridad y esas sesiones caducarán en esa copia de seguridad.

Si un atacante tiene acceso en vivo a la base de datos en vivo, es probable que no necesiten sesiones, por lo que puede no ser una preocupación.

Alternativamente, si no necesita compartir sesiones entre servidores, simplemente podría mantener las sesiones en la memoria. (La mayoría de las implementaciones de sesión predeterminadas hacen esto en la mayoría de los marcos que conozco)

Una alternativa a las sesiones podría ser los tokens web de JSON, que también tienen una vida útil, pero son autocontenidos, contienen reclamos (es decir, soy usuario X) y se validan mediante firma o cifrado. Eso requiere que usted tenga un servidor central de autenticación que firme todos los tokens (que otros servidores pueden leer y verificar) en una configuración de clave pública / privada o que todos los servidores tengan acceso a una clave de cifrado común (que obviamente debe estar muy bien protegida) HSM o equivalente se utiliza a menudo para esto). Dado que el cliente los transfiere de un lado a otro, no es necesario que los almacene, ya que puede verificarlos cada vez que el cliente realice una acción.

    
respondido por el crovers 09.01.2017 - 17:03
fuente
0
  

Esto obviamente ralentizará al usuario.

No, no lo hará.

Sí, será más lento que almacenar texto sin formato, y reducirá la capacidad pero la diferencia será insignificante (a menos que sea muy malo en esto).

Mi capa de sesión de cifrado cuesta alrededor de 0,002 segundos por solicitud (tamaño de sesión de 4k) en hardware bastante corriente con AES de 256 bits. Los seres humanos no pueden percibir diferencias en la duración por debajo de alrededor de 0.030 segundos.

Si estamos hablando específicamente de PHP, tenga en cuenta que también hay un costo de aproximadamente 0,0005 segundos por solicitud para usar un serializador personalizado, requerido para mi controlador. OTOH, hay otras cosas que puede hacer con un controlador personalizado para mejorar la capacidad.

  

tamaño máximo de encabezado de solicitud

Esto no está limitado por HTTP, puede ser una restricción de configuración local. Ciertamente, algunos navegadores limitan el tamaño de los cocineros.

  

No puedo almacenar los detalles de la sesión en una cookie

No, pero puede almacenar más datos en varias cookies y almacenamiento estructurado en el cliente (hay bibliotecas para manejar esto). Pero añade mucha complejidad. Y como se explicó anteriormente, no hay beneficio neto.

    
respondido por el symcbean 10.01.2017 - 01:18
fuente

Lea otras preguntas en las etiquetas