Fijación/secuestro de sesión PHP

Resuelto me2 asked hace 54 años • 0 respuestas

Estoy tratando de comprender más sobre la reparación y el secuestro de sesiones de PHP y cómo prevenir estos problemas. He estado leyendo los siguientes dos artículos en el sitio web de Chris Shiflett:

  • Fijación de sesión
  • Secuestro de sesión

Sin embargo, no estoy seguro de entender las cosas correctamente.

Para ayudar a evitar la fijación de sesiones, ¿es suficiente llamar session_regenerate_id(true);después de que alguien haya iniciado sesión correctamente? Creo que lo entiendo correctamente.

También habla sobre el uso de tokens transmitidos en URL $_GETpara evitar el secuestro de sesiones. ¿Cómo se haría esto exactamente? Supongo que cuando alguien inicia sesión, usted genera su token y lo almacena en una variable de sesión, luego en cada página compararía esa variable de sesión con el valor de la $_GETvariable.

¿Será necesario cambiar este token solo una vez por sesión o en cada carga de página?

¿También existe una buena manera de evitar el secuestro sin tener que pasar un valor en las URL? Esto sería mucho más fácil.

me2 avatar Jan 01 '70 08:01 me2
Aceptado

Bien, hay dos problemas separados pero relacionados, y cada uno se maneja de manera diferente.

Fijación de sesión

Aquí es donde un atacante establece explícitamente el identificador de sesión de una sesión para un usuario. Normalmente en PHP se hace dándoles una URL como http://www.example.com/index...?session_name=sessionid. Una vez que el atacante proporciona la URL al cliente, el ataque es lo mismo que un ataque de secuestro de sesión.

Hay algunas formas de evitar la fijación de sesiones (hágalas todas):

  • Establecer session.use_trans_sid = 0en su php.iniarchivo. Esto le indicará a PHP que no incluya el identificador en la URL y que no lea la URL en busca de identificadores.

  • Establecer session.use_only_cookies = 1en su php.iniarchivo. Esto le indicará a PHP que nunca use URL con identificadores de sesión.

  • Vuelva a generar el ID de la sesión cada vez que cambie el estado de la sesión. Eso significa cualquiera de los siguientes:

    • Autenticacion de usuario
    • Almacenamiento de información confidencial en la sesión
    • Cambiar algo sobre la sesión
    • etc...

Secuestro de sesión

Aquí es donde un atacante obtiene un identificador de sesión y puede enviar solicitudes como si fuera ese usuario. Eso significa que, dado que el atacante tiene el identificador, es prácticamente indistinguible del usuario válido con respecto al servidor.

No se puede evitar directamente el secuestro de sesión. Sin embargo, puedes introducir pasos para que sea muy difícil y más difícil de usar.

  • Utilice un identificador hash de sesión seguro: session.hash_functionen php.ini. Si PHP <5.3, configúrelo session.hash_function = 1para SHA1. Si PHP >= 5.3, configúrelo en session.hash_function = sha256o session.hash_function = sha512.

  • Envía un hash fuerte: session.hash_bits_per_characteren php.ini. Establezca esto en session.hash_bits_per_character = 5. Si bien esto no hace que sea más difícil de descifrar, sí marca la diferencia cuando el atacante intenta adivinar el identificador de sesión. El ID será más corto, pero utilizará más caracteres.

  • Establezca una entropía adicional con session.entropy_filey session.entropy_lengthen su php.iniarchivo. Establezca el primero en session.entropy_file = /dev/urandomy el segundo en el número de bytes que se leerán del archivo de entropía, por ejemplo session.entropy_length = 256.

  • Cambie el nombre de la sesión del PHPSESSID predeterminado. Esto se logra llamando session_name()con su propio nombre de identificador como primer parámetro antes de llamar session_start.

  • Si está realmente paranoico, también puede rotar el nombre de la sesión, pero tenga en cuenta que todas las sesiones se invalidarán automáticamente si cambia esto (por ejemplo, si lo hace dependiente de la hora). Pero dependiendo de su caso de uso, puede ser una opción...

  • Rote su identificador de sesión con frecuencia. No haría esto en cada solicitud (a menos que realmente necesite ese nivel de seguridad), sino en un intervalo aleatorio. Desea cambiar esto con frecuencia, ya que si un atacante secuestra una sesión, no querrá que pueda usarla por mucho tiempo.

  • Incluya el agente de usuario de$_SERVER['HTTP_USER_AGENT'] la sesión. Básicamente, cuando comience la sesión, guárdela en algo como $_SESSION['user_agent']. Luego, en cada solicitud posterior, verifique que coincida. Tenga en cuenta que esto puede ser falsificado, por lo que no es 100% confiable, pero es mejor que no.

  • Incluya la dirección IP del usuario$_SERVER['REMOTE_ADDR'] en la sesión. Básicamente, cuando comience la sesión, guárdela en algo como $_SESSION['remote_ip']. Esto puede ser problemático para algunos ISP que utilizan múltiples direcciones IP para sus usuarios (como solía hacer AOL). Pero si lo usas, será mucho más seguro. La única forma que tiene un atacante de falsificar la dirección IP es comprometer la red en algún punto entre el usuario real y usted. Y si comprometen la red, pueden ser mucho peores que un secuestro (como ataques MITM, etc.).

  • Incluya un token en la sesión y en el lado de los navegadores que incremente y compare con frecuencia. Básicamente, para cada solicitud, hágalo $_SESSION['counter']++en el lado del servidor. También haga algo en JS en el lado de los navegadores para hacer lo mismo (usando un almacenamiento local). Luego, cuando envíe una solicitud, simplemente tome un nonce de un token y verifique que el nonce sea el mismo en el servidor. Al hacer esto, debería poder detectar una sesión secuestrada, ya que el atacante no tendrá el contador exacto o, si lo tiene, tendrá 2 sistemas transmitiendo el mismo recuento y podrá darse cuenta de que uno está falsificado. Esto no funcionará para todas las aplicaciones, pero es una forma de combatir el problema.

Una nota sobre los dos

La diferencia entre fijación de sesión y secuestro se refiere únicamente a cómo se compromete el identificador de sesión. En la fijación, el identificador se establece en un valor que el atacante conoce de antemano. En Hijacking, el usuario lo adivina o se lo roba. De lo contrario, los efectos de ambos son los mismos una vez que el identificador se ve comprometido.

Regeneración de ID de sesión

Siempre que se vuelva a generar el identificador de sesión utilizando session_regenerate_idla sesión anterior se debe eliminar. Esto sucede de forma transparente con el controlador de sesión principal. Sin embargo, algunos controladores de sesión personalizados que utilizansession_set_save_handler() no hacen esto y están abiertos a ataques a identificadores de sesión antiguos. Asegúrese de que, si está utilizando un controlador de sesión personalizado, realice un seguimiento del identificador que abre y, si no es el mismo que guarda, elimine (o cambie) explícitamente el identificador del anterior.

Usando el controlador de sesión predeterminado, está bien simplemente llamar a session_regenerate_id(true). Eso eliminará la información de la sesión anterior. La ID anterior ya no es válida y provocará que se cree una nueva sesión si el atacante (o cualquier otra persona) intenta utilizarla. Sin embargo, tenga cuidado con los controladores de sesiones personalizados...

Destruir una sesión

Si va a destruir una sesión (al cerrar sesión, por ejemplo), asegúrese de destruirla completamente. Esto incluye desarmar la cookie. Usando session_destroy:

function destroySession() {
    $params = session_get_cookie_params();
    setcookie(session_name(), '', time() - 42000,
        $params["path"], $params["domain"],
        $params["secure"], $params["httponly"]
    );
    session_destroy();
}
ircmaxell avatar Feb 22 '2011 17:02 ircmaxell

Ambos ataques de sesión tienen el mismo objetivo: obtener acceso a una sesión legítima de otro usuario. Pero los vectores de ataque son diferentes:

  • En un ataque de fijación de sesión , el atacante ya tiene acceso a una sesión válida e intenta obligar a la víctima a utilizar esta sesión en particular.

  • En un ataque de secuestro de sesión , el atacante intenta obtener el ID de la sesión de la víctima para utilizar su sesión.

En ambos ataques, el ID de sesión son los datos confidenciales en los que se centran estos ataques. Por lo tanto, es el ID de sesión el que debe protegerse tanto para el acceso de lectura (secuestro de sesión) como para el acceso de escritura (fijación de sesión).

En este caso también se aplica la regla general de proteger los datos confidenciales mediante HTTPS. Además, debes hacer lo siguiente:

Para evitar ataques de fijación de sesión , asegúrese de que:

  • el ID de sesión solo se acepta desde una cookie (establezca session.use_only_cookies en true) y hágalo para HTTPS solo si es posible (establezca session.cookie_secure en true); puedes hacer ambas cosas con session_set_cookie_params.

Para evitar ataques de secuestro de sesión , asegúrese de que:

  • el ID de sesión en la cookie solo es legible por su servidor (establezca session.cookie_httponly en true)
  • se utiliza una fuente adicional de entropía (ver session.entropy_file ) ya que el generador de números aleatorios de PHP tiene una debilidad conocida ; Muchos avisos de seguridad sugieren al menos 128 bits de longitud de entropía (consulte session.entropy_length ).
  • se utiliza una función hash criptográfica sólida (consulte session.hash_function ); en el mejor de los casos, se trata de una función hash computacionalmente costosa como Whirlpool , que por ejemplo es cinco veces más lenta que MD5 y, por tanto, sólo permite una quinta parte del número de operaciones hash que MD5.

Para evitar ambos ataques de sesión, asegúrese de que:

  • para aceptar solo sesiones que su aplicación haya iniciado. Puede hacer esto tomando las huellas digitales de una sesión al inicio con información específica del cliente. Puede utilizar el ID del agente de usuario , pero no utilice la dirección IP remota ni ninguna otra información que pueda cambiar entre solicitudes.
  • para cambiar el ID de sesión session_regenerate_id(true)después de un intento de autenticación ( truesolo en caso de éxito) o un cambio de privilegios y destruir la sesión anterior. (Asegúrese de almacenar cualquier cambio de $_SESSIONuso session_write_close antes de volver a generar la ID si desea conservar la sesión asociada a la ID anterior; de lo contrario, solo la sesión con la nueva ID se verá afectada por esos cambios).
  • para utilizar una implementación adecuada de caducidad de sesión (consulte ¿Cómo caduco una sesión de PHP después de 30 minutos? ).
Gumbo avatar Feb 22 '2011 18:02 Gumbo

Los tokens que mencionas son un número "nonce" que se usa una vez. No necesariamente tienen que usarse solo una vez, pero cuanto más tiempo se usan, mayores serán las probabilidades de que el nonce pueda capturarse y usarse para secuestrar la sesión.

Otro inconveniente de los nonces es que es muy difícil construir un sistema que los utilice y permita múltiples ventanas paralelas en el mismo formulario. Por ejemplo, el usuario abre dos ventanas en un foro y comienza a trabajar en dos publicaciones:

window 'A' loads first and gets nonce 'P'
window 'B' loads second and gets nonce 'Q'

If you have no way of tracking multiple windows, you'll only have stored one nonce - that of window B/Q. When the user then submits their post from window A and passes in nonce 'P', ths system will reject the post as P != Q.

Marc B avatar Feb 22 '2011 16:02 Marc B