PHP Velho Oeste 2024

Sesiones y seguridad

Enlaces externos: » Fijación de sesiones

El administrador de sesiones de HTTP es el núcleo de la seguridad web. Se deberían adoptar todos los atenuantes para garantizar la seguridad de sesiones. Los desarrolladores deberían habilitar/emplear configuraciones relevantes de forma apropiada.

  • session.cookie_lifetime=0. El valor 0 tiene un significado especial. Indica a los navegadores no almacenar permanentemente cookies. Por tanto, cuando un navegador finaliza, la cookie de ID de sesión se elimina inmediatamente. Si el desarrollador establece un valor distinto de 0, podría permitir que otros usuarios empleen ese ID de sesión. La mayoría de las aplicacioines deberían utilizar "0". Si se requiere la autoidentificación, se ha de implementar una característca de autoidentificación segura. No se han de utilizar ID de sesiones para ello.
  • session.use_cookies=On y session.use_only_cookies=On. Aunque las cookies de HTTP tienen algunos problemas, son la manera preferida de administrar ID de sesiones. Use solamente cookies para administrar ID de sesiones cuando sea posible. La mayoría de las aplicaciones deberían utilizar cookies para ID de sesiones.
  • session.use_strict_mode=On. Previene que el módulo de sesiones utilice ID de sesiones no inicializados. En otras palabras, el módulo de sesiones solamente acepta ID de sesiones válidos generados por él mismo. Rechaza ID de sesions proporcionados por los usuarios. Se podría realizar una inyección de ID de sesiones a través de inyecciones de cookies mediante JavaScript de forma permanente o temporal. Cuando están habilitadas las sesiones transparentes, se podría inyectar una ID de sesión mediante un string de consulta o un parámetro de formulario. No hay ninguna razón para aceptar ID de sesiones proporcionados por el usuario, la mayoría de las aplicaciones no deben aceptar ID de sesiones no inicializados proporcionados por el usuario.
  • session.cookie_httponly=On. Denegar el acceso a cookies de sesión a JavaScript. Este ajuste previene del robo de cookies por inyecciones de JavaScript. Es posible utilizar ID de sesiones como claves de protección CSRF, aunque no se recomienda. Por ejemplo, se podría guardar y enviar código fuente HTML a otros usuarios. Para mayor seguridad, los desarrolladores no deberían escribir ID de sesiones en páginas web. Casi todas las aplicaciones deben emplear el atributo httponly para cookies de ID de sesión.
  • session.cookie_secure=On. Permite el acceso a cookies de ID de sesión solamente al protocolo HTTPS. Si un sitio web es un sitio solamente HTTPS, se debe habilitar este ajuste. No debería considerarse el empleo de HSTS para sitios web que sean solamente HTTPS.
  • session.gc_maxlifetime=[elegir el más pequeño posible]. La recolección de basura (GC) se realiza por probabilidades. Este ajuste no garantiza la eliminación de sesiones antiguas. Algunos modulos de gestores de almacenamiento de sesiones no emplean este ajuste. Consulte la documentación de gestores almacenamiento de sesiones para más detalles. Aunque los desarrolladores no pueden depender de este ajuste, se recomienda establecerlo al valor más pequeño posible. Se ha de ajustar session.gc_probability y session.gc_divisor para que las sesiones obsoleta sean eliminadas con la frecuencia apropiada. Si se requiere la autoidentificación, se ha de implementar una característca de autoidentificación segura. No utilice ID de sesiones de vida larga para ello.
  • session.use_trans_sid=Off. El empleo de administradores de ID de sesiones transparentes no está prohibido. Se podría utilizar cuando fuera necesario. Sin embargo, la deshabilitación de la administración de ID de sesiones transparentes mejoraría la seguridad general de ID de sesiones eliminando la posibilidad de inyecciones y filtracioines de ID de sesiones.
  • session.referer_check=[el URL original] Cuando session.use_trans_sid está habilitado, se recomienda el empleo de este ajuste si es posible. Reduce el riesgo de inyecciones de ID de sesión. Si un sitio fuera http://example.com/, se ha de establecer http://example.com/ para ello. Obaservar que al utilizar HTTPS, los navegadores no enviarán la cabecera recomendante. Los navegadores podrían no enviar dicha cabecera debido a su configuración. Por tanto, este ajuste no es una medida de seguridad de confianza.
  • session.cache_limiter=nocache. Garantiza que los contenidos HTTP no se almacenan en caché para sesiones autenticadas. Permite el almacenamiento en caché solamente cuando el contenido no es privado. De lo contrario, el contenido podría quedar expuesto. Se podría emplear "private" si el contenido HTTP no incluye datos sensibles a la seguridad. Observar que "private" podría dejar datos privados en caché por clientes compartidos. Se podría utilizar "public" solamente cuando el contenido HTTP no contenga ningún dato privado en absoluto.
  • session.hash_function="sha256". Las funciones de hash más fuertes generarán ID de sesiones más fuertes. Aunque son improbables las colisiones hash incluso con MD5, los desarrolladores deberían utilizar funciones de hash SHA-2 o posterior para esta tarea. Los desarrolladores podrían emplear hash más fuertes, como sha384 y sha512.

El módulo de sesión no puede garantizar que la información que se almacena en una sesión sea vista sólo por el usuario que creó la sesión. Se necesita tomar medidas adicionales para proteger activamente la confidencialidad de la sesión, dependiendo del valor asociado con ella.

Evalúe la importancia de la información que portan las sesiones y utilice protecciones adicionales; esto normalmente conlleva un precio, reduciendo la comodidad del usuario. Por ejemplo, si se quiere proteger a los usuarios de tácticas de ingeniería social simples, es necesario habilitar session.use_only_cookies. En este caso, las cookies deben estar activas incondicionalmente en el lado del usuario, o las sesiones no funcionarán.

Hay varias maneras de filtrar un ID de sesión existente a terceros. Un ID de sesión filtrado habilita al tercero a acceder a todos los recursos que están asociados con un ID específico. Primero, los URL portan ID de sesiones. Si se enlaza con un sitio externo, el URL que incluye el ID de sesión podría estar almacenado en el registro de consultas del sitio externo. Segundo, un atacante más activo podría escuchar el tráfico de red. Si no están encriptados, los ID de sesión fluirán en texto plano por la red. La solución aquí es implementar SSL en el servidor y hacerlo obligatorio para los usuarios. Se debería emplear HSTS para esto.

Desde PHP 5.5.2, está disponible session.use_strict_mode. Cuando está habilitada y el módulo gestor de almacenamiento lo admite, un ID de sesión no inicializado es rechazado, creando así un nuevo ID de sesión. Es protege contra ataques que fuerzan a los usuarios que empleen ID de sesiones conocidos. El atacante podría pegar enlaces o enviar correos que contengan ID de sesiones, p.ej., http://example.com/page.php?PHPSESSID=123456789. Si session.use_trans_sid está habilitada, las víctimas iniciarán sesión utilizando el ID de sesión provisto por el atacante. session.use_strict_mode mitiga este riesgo.

Incluso si session.use_strict_mode mitiga el riesgo de gestores de sesiones adoptivos, el atacante puede forzar a los usuarios a que empleen ID de sesiones inicializados creados por él mismo. Todo lo que tiene que hacer el atacante es inicializar el ID de sesión antes de atacar y mantanerlo vivo.

Se podría establecer una cookie de ID de sesión con los atributos de dominio, ruta, httponly y seguro. Los navegadores definen su propia precedencia. Al emplear la precedencia, el atacante puede establecer un ID de sesión que podría utlizarse permanentemente. El empleo de session.use_only_cookies no resolverá este problema. session.use_strict_mode mitiga este riesgo. Con session.use_strict_mode=On, los ID de sesiones no inicializados no serán aceptados. El módulo de sesiones crea un nuevo ID de sesión siempre que dicho ID no esté inicializado por él midmo. Esto podría resultar en una denegación del servicio, aunque esto es mejor que comprometer la cuenta.

session.use_strict_mode es un buen atenuante, pero no lo suficiente para sesiones autenticadas. Los desarrolladores deben emplear session_regenerate_id() para la autenticación. session_regenerate_id() debe invocarse antes de establecer la información de autentición para $_SESSION. session_regenerate_id() garantiza que las nuevas sesiones contengan información de autenticación almacenada solamente en nuevas sesiones. Es decir, los errores durante el proceso de identificación podrían guardar indicadores autenticados en sesiones antiguas.

Llamar a la función session_regenerate_id() podría resultar en una denegación del servicio personal como con use_strict_mode=On. Sin embargo, esto es mejor que comprometer la cuenta. Un ID de sesión debería ser regenerado cuando el usuario, al menos, sea autenticado. La regeneración de ID de sesiones reduce el riesgo del robo de los mismos, por lo que debería invocarse periódicamente. Los desarrolladores no deberían depender de la expiración de los ID de sesiones. Los atacantes podrían acceder a los ID de sesión de las víctimas periódicamente para evitar la expiración. Los desarrolladores deben implementar su propia utilidad de expiración para sesiones antiguas.

Observar que session_regenerate_id() no elimina sesiones antiguas de forma predeterminada. Podrían estar disponibles las sesiones autenticadas antiguas. Si los desarrolladores quiesieran prevenir que las sesiones autenticadas antiguas sen utilizadas por cualquiera, debe destruir las sesiones estableciendo delete_old_session a true. Sin embargo, la inmediata eliminación de sesiones antigas tiene efectos secundarios no deseados. Las sesiones podrían desaparecer cuando hayan conexiones concurrentes a la aplicación web y/o cuando la red esté inestable. En lugar de eliminar las sesiones antiguas inmediatamente, podría establecerse un tiempo de expiración a corto plazo en $_SESSION por uno mismo. Si el usuario accede a una sesión obsoleta (expirada), se ha de denegar el acceso a ella.

session.use_only_cookies y el uso apropiado de session_regenerate_id() podría ocasionar una denegación del servicio personal. Cuando sea este el caso, se podría preguntar a los usuarios para que eliminen las cookies y advertirles de que podría haber problemas de seguridad. Los atacantes podrían establecer cookies maliciosas mediante una aplicación web vulnerable (es decir, inyección de JavaScript), complementos vulnerables/maliciosos de navegadores, etc.

Los desarrolladores no deben utilizar ID de sesiones de vida larga para la autoidentifiación, ya que aumenta el riego del robo de sesiones. La autoidentificación debería ser implementada por el desarrolador. Emplee la clave de hash de seguridad de una sola vez como clave de autoidentificación utilizando cookies. Emplee un hash de seguridad más fuerte que SHA-2, p.ej., SHA-256 o superior con datos aleatorios de /dev/urandom o similar. Si el usuario no se autentica, compruebe que la clave de autoidentificación de una sola vez es válida. Si la clave es válida, autentique al usuario y establezca una nueva clave de hash de seguridad de una sola vez. La clave de autoidentificación es una clave de vida larga; debería estar lo más protegida posible. Emplee los atributos ruta/httponly/seguridad de las cookies para la protección. Los desarrolladores deben implementar la característca que deshbilite la autoidentificación y elmine las claves de autoidentificación de los usuarios innecesarias.

add a note add a note

User Contributed Notes 5 notes

up
64
Anurag Jain
15 years ago
Websites which have sensitive information need to be patched to ensure its not exploited because of session issues.

In earlier versions of apache cookie reliability was not assumed and hence the default method was always using url-rewrite which meant every url link, every form submission etc would have a PHPSESSID=<sessionid> passed along to inform the server about the active session. New versions have turned this off using

session.use_trans_sid = 0

in the /etc/php5/apache2/php.ini file.

Reasons?
Well one might safe the offline page as a bookmark or pass the link across to others not realizing that the session id information is also sent. So someone who quickly accesses these pages could possible get logged on, this was also true wrt search engines, and I guess in some cases it being seen as duplicate content as the same page will have a different session id every time the robots scan the website.

But having this set does not mean you are protected. Let me explain.
What prevents me from presetting the session id! Assume there is a banking site www.example.com which has a login screen at www.example.com/login.php
I can send you can email with a link to the bank site as http://www.example.com/login.php?PHPSESSID=12345
When you click on the link it presents the session id as 12345 rather then asking the server to generate a new one. This is called session fixation. Keep in mind even with session.use_trans_sid = 0 this will work as this sets it only not to use url-rewrite. To prevent this altogether set session.use_only_cookies = 1 which ensures that only cookies will be used, but this could cause problems when dealing with transaction which involve switch sites, i.e. siteA forwards to site B for payment which forwards to siteA for thank you, in which case a phpsessid inform might be used to revive the old session.

A good approach would always be to at the login screen and immediately post login to force a new session id generated using random numbers

session_start();
$newsessid = somerandomnumberfunction();
session_id($newsessid);

you can also use session_regenerate_id() function to generate a new id

session_start();
session_regenerate_id();

Also its always good to ensure every valid session is checked against an ip. One good method is to store the session id and remote ip information in a table, or better store the ip as a session variable itself, once the user logs in and ensure that this is continued for remaining pages for security. This ofcourse wont work when users use the same office or shared network as the ip to the outside world is the same.

https is always a good idea for sensitive sites, but keeping it persistent for all pages which use session is important if you really want a foolproof system else anyone can always sniff your packets.

So to quickly go through the bits

- set session.use_trans_sid = 0 in /etc/php5/apache2/php.ini file.
- Ensure you always use a new self generated session id on successful login attempt.
- Try setting session.use_only_cookies = 1 and check if all works fine.
- Use https throughout to ensure no one can sniff your session id.
- Store session id, remote IP information and compare for successive pages
up
13
bmearns at ieee dot org
15 years ago
In addition to ip-address binding not always being effective, it can also prevent users connecting through a proxy-pool from even being able to use your site. In such a scenario, a person's IP address may very well change with every access.

If you're handling anything remotely secure, the only safe option is HTTPS. If the data doesn't need to be that secure, than you should not allow a high-jacked session to do too much damage. Basically, don't assume that a person really is who they pretend to be just because the session says a person authenticated with a username and password: it may have been that person who logged in, but that doesn't mean it's still that person. So if you're going to do something like change passwords or something, require them to authenticate again on the same form.

Of course this needs to be done in some secure way, as well, so that the password is not just floating over the network. A good way to do this is sending a nonce (number-used-once) along with the form and some javascript to concatenate the nonce to the password, then perform a cryptographic hash of the combined string. The resulting valid-once "password" should then be sent instead of the plain text password. To be effective, you also need to prevent people from using the form if they don't have JavaScript enabled. You can do this by disabling the form fields in HTML, then re-enabling them in JavaScript.
up
-1
justin at fatbird dot ca
15 years ago
IP checking is a sometimes useful feature with two limitations that are important to be aware of:

1. Anyone surfing behind a proxy (e.g., someone at work) will provide the proxy's IP, not his own.  Session ID replay attacks will not be prevented by IP checking for an attacker on the user's side of the proxy.

2. If the PHP application is behind a reverse proxy, the reverse proxy's IP address will be the only request IP seen by PHP, so IP checking is useless.
up
-4
Olle Bergkvist
15 years ago
It is also quite important to (somehow) make sure that the cookies you're setting (including the session cookie) is only visible to the site that created it (or to other trusted sites only).

If the cookie's path is set to '/' (the whole domain), then any website on the same domain (might be lots of websites) _will_ get the cookie through HTTP headers and could possibly hijack your session.

One slightly acceptable protection would be to lock a session to one IP adress.
up
-44
JonathanFeller at NOSPAMgmx dot ch
15 years ago
Perhaps, you would also like to timeout a session after some idle time. I noticed that session.gc_maxlifetime is not suitable for this. So I used this code to do the job:

<?php
if (!isset($_SESSION['timeout_idle'])) {
   
$_SESSION['timeout_idle'] = time() + MAX_IDLE_TIME;
} else {
    if (
$_SESSION['timeout_idle'] < time()) {   
       
//destroy session
   
} else {
       
$_SESSION['timeout_idle'] = time() + MAX_IDLE_TIME;
    }
}
?>
To Top