son - Fijación de sesión PHP/secuestro
son seguras las sesiones php (5)
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 ID de la sesión de una víctima para usar su sesión.
En ambos ataques, la ID de sesión es la información confidencial en la que se centran estos ataques. Por lo tanto, es la ID de sesión lo 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 el uso de 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:
- la ID de la sesión solo se acepta desde una cookie (establece session.use_only_cookies en
true
) y la convierte en HTTPS solo si es posible (establece session.cookie_secure entrue
); puedes hacer ambas cosas consession_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 tu servidor (establece session.cookie_httponly en
true
) - se usa 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 bit de longitud de entropía (ver session.entropy_length )
- se usa una fuerte función hash criptográfica (ver session.hash_function ); en el mejor de los casos, es una función hash computacionalmente costosa como Whirlpool que, por ejemplo, es cinco veces más lenta que MD5 y, por lo tanto, solo permite un quinto del número de operaciones hash en oposición a MD5.
Para evitar ambos ataques de sesión, asegúrese de que:
- para aceptar solo sesiones que su aplicación haya iniciado. Puede hacerlo tomando las huellas dactilares de una sesión al inicio con información específica del cliente. Puede usar el ID del usuario-agente pero no use la dirección IP remota o cualquier otra información que pueda cambiar entre las solicitudes.
- para cambiar la ID de sesión usando
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 guardar cualquier cambio de$_SESSION
utilizandosession_write_close
antes de regenerar el ID si desea conservar la sesión asociada al ID anterior, de lo contrario, solo la sesión con el nuevo ID se verá afectada por esos cambios). - utilizar una implementación de vencimiento de sesión adecuada (consulte ¿Cómo expirar una sesión PHP después de 30 minutos? ).
Estoy tratando de comprender más sobre la fijación de sesión 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 sesión, es suficiente llamar a session_regenerate_id (true); después de iniciar sesión exitosamente con alguien? Creo que entiendo eso correctamente
También habla sobre el uso de tokens pasados en urls a través de $ _GET para evitar el secuestro de la sesión. ¿Cómo se haría esto exactamente? Supongo que cuando alguien inicia sesión, genera su token y lo almacena en una variable de sesión, entonces en cada página compara 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 evitar el secuestro sin tener que pasar un valor en las direcciones URL? esto sería mucho más fácil.
Los tokens que mencionas son un "nonce": número utilizado una vez. No necesariamente tienen que usarse solo una vez, pero cuanto más tiempo se usen, mayores serán las probabilidades de que se capture y se use para secuestrar la sesión.
Otro inconveniente de nonces es que es muy difícil construir un sistema que los use y permite 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:
window ''A'' loads first and gets nonce ''P''
window ''B'' loads second and gets nonce ''Q''
Si no tiene forma de rastrear múltiples 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 pasa en nonce ''P'', este sistema rechazará la publicación como P != Q
No leí el artículo de Shiflett, pero creo que has malentendido algo.
Por defecto PHP pasa el token de sesión en la URL siempre que el cliente no acepte 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 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 sesión. Si el usuario se autentica de alguna manera, el usuario malintencionado conoce el token de sesión de un autenticado, que puede tener diferentes privilegios.
Como estoy seguro de que Shiflett explica, lo más habitual es regenerar un token diferente cada vez que cambian los privilegios de un usuario.
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. Normalmente en PHP se hace 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 el mismo que el de un ataque de secuestro de sesión.
Hay algunas maneras de evitar la fijación de la sesión (hacer todas):
Establezca
session.use_trans_sid = 0
en su archivophp.ini
. Esto le indicará a PHP que no incluya el identificador en la URL y que no lea la URL para los identificadores.Establezca
session.use_only_cookies = 1
en su archivophp.ini
. Esto le dirá a PHP que nunca use URLs 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:
- Autenticacion de usuario
- Almacenar información confidencial en la sesión
- Cambiando algo de 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 fueran ese usuario. Esto significa que, dado que el atacante tiene el identificador, todos son indistinguibles del usuario válido con respecto al servidor.
No puede evitar directamente el secuestro de la sesión. Sin embargo, puede poner los pasos para que sea muy difícil y más difícil de usar.
Use un fuerte identificador hash de sesión:
session.hash_function
enphp.ini
. Si PHP <5.3,session.hash_function = 1
ensession.hash_function = 1
para SHA1. Si PHP> = 5.3,session.hash_function = sha256
osession.hash_function = sha512
.Envía un hash fuerte:
session.hash_bits_per_character
enphp.ini
. Establezca esto ensession.hash_bits_per_character = 5
. Si bien esto no hace que sea más difícil de descifrar, hace una diferencia cuando el atacante intenta adivinar el identificador de sesión. La ID será más corta, pero usa más caracteres.Establezca una entropía adicional con
session.entropy_file
ysession.entropy_length
en su archivophp.ini
. Establezca el primero ensession.entropy_file = /dev/urandom
y el último en la cantidad 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 a
session_name()
con su propio nombre de identificador como primer parámetro antes de llamar asession_start
.Si eres realmente paranoico, también puedes rotar el nombre de la sesión, pero ten cuidado de que todas las sesiones se invaliden automáticamente si cambias esto (por ejemplo, si dependes de la hora). Pero dependiendo de su caso de uso, puede ser una opción ...
Gire el identificador de su sesión a menudo. No haría esto en todas las solicitudes (a menos que realmente necesite ese nivel de seguridad), sino en un intervalo aleatorio. Desea cambiar esto a menudo, ya que si un atacante secuestra una sesión no quiere que la pueda usar 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 como$_SESSION[''user_agent'']
. Luego, en cada solicitud posterior, verifique que coincida. Tenga en cuenta que esto puede ser falso, por lo que no es 100% confiable, pero es mejor que no hacerlo.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 como$_SESSION[''remote_ip'']
. Esto puede ser problemático para algunos ISP que usan múltiples direcciones IP para sus usuarios (como lo hacía AOL). Pero si lo usa, será mucho más seguro. La única forma de que un atacante falsifique la dirección IP es poner en peligro la red en algún momento entre el usuario real y usted. Y si ponen en peligro la red, pueden hacer mucho peor que un secuestro (como ataques MITM, etc.).Incluya un token en la sesión y en el lado del navegador que incremente y compare a menudo. Básicamente, para cada solicitud, haga
$_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ías poder detectar una sesión secuestrada ya que el atacante no tendrá el contador exacto, o si lo hacen tendrás 2 sistemas que transmiten el mismo conteo y pueden 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 Secuestro solo se refiere 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, es adivinado o robado del usuario. De lo contrario, los efectos de los dos son los mismos una vez que el identificador está comprometido.
Regeneración de ID de sesión
Siempre que regenere el identificador de sesión usando session_regenerate_id
la sesión anterior debe ser eliminada. Esto ocurre de forma transparente con el controlador de la sesión principal. Sin embargo, algunos manejadores de sesión personalizados que usan session_set_save_handler()
no hacen esto y están abiertos para atacar los 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 que elimina explícitamente (o cambia) el identificador en el anterior.
Usando el manejador de sesión predeterminado, puede simplemente llamar a session_regenerate_id(true)
. Eso eliminará la información de sesión anterior para usted. La ID anterior ya no es válida y hará que se cree una nueva sesión si el atacante (o cualquier otra persona para el caso) intenta usarla. Tenga cuidado con los controladores de sesión personalizados, aunque ....
Destruyendo una sesión
Si vas a destruir una sesión (al cerrar la sesión, por ejemplo), asegúrate 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();
}
Sí, podría evitar la fijación de la sesión regenerando la identificación de la sesión una vez que inicie sesión. De esta forma si el atacante no sabrá el valor de la cookie de la nueva sesión autenticada. Otro enfoque que detiene por completo el problema es set 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 depende de enviar el valor de la cookie como GET o POST.