Estoy tratando de entender más sobre la fijación de sesiones PHP y el secuestro y cómo prevenir estos problemas. He estado leyendo los siguientes dos artículos en el sitio web de Chris Shiflett:
Sin embargo, no estoy seguro de entender las cosas correctamente.
Para ayudar a prevenir la fijación de la sesión, es suficiente llamar a session_regenerate_id (true); después de iniciar sesión con éxito en alguien? Creo que lo entiendo correctamente.
También habla sobre el uso de tokens pasados en URL a través de $ _GET para evitar el secuestro de sesión. ¿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, ¿en cada página compararía esa variable de sesión con el valor de la variable $ _GET?
¿Debería cambiarse este token solo una vez por sesión o en cada carga de página?
¿También es una buena manera de prevenir el secuestro sin tener que pasar un valor en las URL? Esto sería mucho más fácil.
Respuestas:
Ok, 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. Por lo general, en PHP se realiza dándoles una URL como
http://www.example.com/index...?session_name=sessionid
. Una vez que el atacante le da 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 la sesión (hacer todas):
Establecer
session.use_trans_sid = 0
en suphp.ini
archivo. Esto le indicará a PHP que no incluya el identificador en la URL y que no lea la URL de los identificadores.Establecer
session.use_only_cookies = 1
en suphp.ini
archivo. Esto le indicará a PHP que nunca use URL con identificadores de sesión.Vuelva a generar la ID de sesión cada vez que cambie el estado de la sesión. Eso significa cualquiera de los siguientes:
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, no se puede distinguir del usuario válido con respecto al servidor.
No puede evitar directamente el secuestro de sesión. Sin embargo, puede poner pasos para que sea muy difícil y difícil de usar.
Use un identificador hash de sesión fuerte:
session.hash_function
enphp.ini
. Si PHP <5.3,session.hash_function = 1
configúrelo para SHA1. Si PHP> = 5.3, configúrelo ensession.hash_function = sha256
osession.hash_function = sha512
.Enviar un hash fuerte:
session.hash_bits_per_character
enphp.ini
. Establece esto ensession.hash_bits_per_character = 5
. Si bien esto no hace que sea más difícil de descifrar, sí hace una diferencia cuando el atacante intenta adivinar el identificador de sesión. La identificación será más corta, pero usa más caracteres.Establezca una entropía adicional con
session.entropy_file
ysession.entropy_length
en suphp.ini
archivo. Establezca el primero ensession.entropy_file = /dev/urandom
y el último en el número de bytes que se leerán del archivo de entropía, por ejemplosession.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 llamarsession_start
.Si eres realmente paranoico, también puedes rotar el nombre de la sesión, pero ten en cuenta que todas las sesiones se invalidarán automáticamente si cambias esto (por ejemplo, si lo haces dependerá del tiempo). Pero dependiendo de su caso de uso, puede ser una opción ...
Gire su identificador de sesión a menudo. No haría esto todas las solicitudes (a menos que realmente necesite ese nivel de seguridad), pero en un intervalo aleatorio. Desea cambiar esto a menudo, ya que si un atacante secuestra una sesión, no desea que pueda usarla durante demasiado tiempo.
Incluya el agente de usuario de
$_SERVER['HTTP_USER_AGENT']
en la sesión. Básicamente, cuando comienza la sesión, guárdela en algo así$_SESSION['user_agent']
. Luego, en cada solicitud posterior verifique que coincida. Tenga en cuenta que esto se puede falsificar, por lo que no es 100% confiable, pero es mejor que no.Incluya la dirección IP del usuario de
$_SERVER['REMOTE_ADDR']
en la sesión. Básicamente, cuando comienza la sesión, guárdela en algo así$_SESSION['remote_ip']
. Esto puede ser problemático para algunos ISP que usan múltiples direcciones IP para sus usuarios (como solía hacer AOL). Pero si lo usa, será mucho más seguro. La única forma en que un atacante puede falsificar la dirección IP es comprometer la red en algún momento entre el usuario real y usted. Y si comprometen la red, pueden hacer mucho peor 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 a menudo. Básicamente, para cada solicitud hacer
$_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 que transmiten el mismo conteo y puede decir 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 la fijación de sesión y el secuestro es solo sobre cómo se ve comprometido el identificador de sesión. En la fijación, el identificador se establece en un valor que el atacante conoce de antemano. En Hijacking es adivinado o robado por el usuario. De lo contrario, los efectos de los dos son los mismos una vez que se compromete el identificador.
Regeneración de ID de sesión
Siempre que regenere el identificador de sesión con
session_regenerate_id
la sesión anterior, debe eliminarse. Esto sucede de forma transparente con el controlador de sesión principal. Sin embargo, algunos controladores de sesión personalizados que usansession_set_save_handler()
no lo hacen y están abiertos a atacar identificadores de sesión antiguos. Asegúrese de que si está utilizando un controlador de sesión personalizado, que realiza un seguimiento del identificador que abre, y si no es el mismo que guarda, elimine (o cambie) explícitamente el identificador en el anterior.Usando el controlador de sesión predeterminado, está bien con solo llamar
session_regenerate_id(true)
. Eso eliminará la información de la sesión anterior para usted. La identificación anterior ya no es válida y hará que se cree una nueva sesión si el atacante (o cualquier otra persona) trata de usarla. Sin embargo, tenga cuidado con los controladores de sesión personalizados ...Destruyendo una sesión
Si va a destruir una sesión (por ejemplo, al cerrar sesión), asegúrese de destruirla completamente. Esto incluye desarmar la cookie. Utilizando
session_destroy
:fuente
session_regenerate_id
no invalida la sesión que todavía está asociada a la ID anterior; solo si el parámetro delete_old_session se establece en verdadero, la sesión se destruirá. ¿Pero qué pasa si un atacante inicia esta regeneración de ID?session.entropy_file = /dev/urandom
. Se ha demostrado que la generación de entropía interna de PHP es extremadamente débil y el conjunto de entropía proporcionado por / dev / random o / dev / uranom es lo mejor que puede obtener en un servidor web sin un hardware rng.session.cookie_httponly
ysession.cookie_secure
. El primero ayuda a frustrar xss (pero no es perfecto). La segunda es la mejor manera de detener OWASP A9 ...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 usar esta sesión en particular.
En un ataque de Secuestro de sesión , el atacante intenta obtener la identificación de la sesión de una víctima para usar su sesión.
En ambos ataques, la ID de la sesión son los datos sensibles en los que se centran estos ataques. Por lo tanto, es la ID de sesión la que debe protegerse tanto para un acceso de lectura (Secuestro de sesión) como para un acceso de escritura (Fijación de sesión).
La regla general de proteger datos confidenciales mediante HTTPS también se aplica en este caso. Además, debe hacer lo siguiente:
Para evitar ataques de fijación de sesión , asegúrese de que:
true
) y hágalo para HTTPS solo si es posible (configure session.cookie_secure entrue
); se puede hacer tanto consession_set_cookie_params
.Para evitar ataques de secuestro de sesión , asegúrese de que:
true
)Para evitar ambos ataques de sesión, asegúrese de que:
session_regenerate_id(true)
después de un intento de autenticación (true
solo en caso de éxito) o un cambio de privilegios y destruir la sesión anterior. (Asegúrese de almacenar cualquier cambio de$_SESSION
usosession_write_close
antes 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).fuente
Los tokens que mencionas son un "nonce" - número usado una vez. No necesariamente tienen que usarse solo una vez, pero cuanto más tiempo se usen, mayores serán las probabilidades de que el nonce se pueda capturar y usar para secuestrar la sesión.
Otro inconveniente de nonces es que es muy difícil construir un sistema que los use y permita múltiples ventanas paralelas en la misma forma. Por ejemplo, el usuario abre dos ventanas en un foro y comienza a trabajar en dos publicaciones:
Si no tiene forma de rastrear varias ventanas, solo habrá almacenado un nonce, el de la ventana B / Q. Cuando el usuario luego envía su publicación desde la ventana A y la pasa en una 'P', este sistema rechazará la publicación como
P != Q
.fuente
No leí el artículo de Shiflett, pero creo que has entendido mal algo.
Por defecto, PHP pasa el token de sesión en la URL cada vez que el cliente no acepta cookies. De lo contrario, en el caso más común, el token de sesión se almacena como una cookie.
Esto significa que si coloca un token de sesión en la URL, PHP lo reconocerá e intentará usarlo posteriormente. La fijación de la sesión ocurre cuando alguien crea una sesión y luego engaña a otro usuario para que comparta la misma sesión abriendo una URL que contiene el token de la sesión. Si el usuario se autentica de alguna manera, el usuario malintencionado conoce el token de sesión de uno autenticado, que podría tener diferentes privilegios.
Como estoy seguro de que Shiflett explica, lo habitual es regenerar un token diferente cada vez que cambian los privilegios de un usuario.
fuente
Sí, podría evitar la fijación de la sesión regenerando la identificación de la sesión una vez al iniciar sesión. De esta manera, si el atacante no sabrá el valor de la cookie de la sesión recién autenticada. Otro enfoque que detiene totalmente el problema se establece
session.use_only_cookies=True
en su configuración de tiempo de ejecución. Un atacante no puede establecer el valor de una cookie en el contexto de otro dominio. La fijación de la sesión se basa en enviar el valor de la cookie como GET o POST.fuente