Seguridad de sesión PHP


125

¿Cuáles son algunas pautas para mantener una seguridad de sesión responsable con PHP? ¡Hay información en toda la web y ya es hora de que todo aterrice en un solo lugar!

Respuestas:


88

Hay un par de cosas que hacer para mantener su sesión segura:

  1. Use SSL cuando autentique usuarios o realice operaciones confidenciales.
  2. Vuelva a generar la identificación de la sesión cada vez que cambie el nivel de seguridad (como iniciar sesión). Incluso puede regenerar la identificación de la sesión cada solicitud si lo desea.
  3. Tener sesiones de tiempo de espera
  4. No uses registros globales
  5. Almacenar detalles de autenticación en el servidor. Es decir, no envíe detalles como el nombre de usuario en la cookie.
  6. Comprueba el $_SERVER['HTTP_USER_AGENT']. Esto agrega una pequeña barrera al secuestro de sesión. También puede verificar la dirección IP. Pero esto causa problemas a los usuarios que tienen una dirección IP cambiante debido al equilibrio de carga en múltiples conexiones a Internet, etc. (que es el caso en nuestro entorno aquí).
  7. Bloquee el acceso a las sesiones en el sistema de archivos o use el manejo de sesión personalizado
  8. Para operaciones delicadas, considere solicitar a los usuarios registrados que proporcionen nuevamente sus detalles de autenticación

15
Usar SSL solo para algunas operaciones no es suficiente, a menos que tenga sesiones separadas para el tráfico cifrado y no cifrado. Si usa una sola sesión sobre HTTPS y HTTP, el atacante la robará en la primera solicitud que no sea HTTPS.
Kornel

66
-1 el agente de usuario es trivial para falsificar. Lo que está describiendo desperdicia código y no es un sistema de seguridad.
torre

24
@The Rook, puede ser una barrera trivial (el atacante puede capturar al agente de usuario de la víctima usando su propio sitio) y depende de la seguridad a través de la oscuridad, pero sigue siendo una barrera adicional. Si el HTTP del agente de usuario cambiara durante el uso de la sesión, sería extremadamente sospechoso y muy probablemente un ataque. Nunca dije que puedes usarlo solo. Si lo combina con las otras técnicas, tiene un sitio mucho más seguro.
Grom

55
@grom Creo que es como poner un trozo de cinta adhesiva en la puerta y decir que evitará que las personas entren.
Rook

8
Si está comprobando el agente de usuario, bloqueará todas las solicitudes de los usuarios de IE8 cuando cambien el modo de compatibilidad. Vea la diversión que tuve rastreando este problema en mi propio código: serverfault.com/questions/200018/http-302-problem-on-ie7 . Voy a retirar el agente de usuario, porque es una cosa tan trivial suplantar, como han dicho otros.
Bestattendance


11

Mis dos (o más) centavos:

  • No confíes en nadie
  • Filtrar entrada, salida de escape (cookie, datos de sesión son su entrada también)
  • Evite XSS (mantenga su HTML bien formado, eche un vistazo a PHPTAL o HTMLPurifier )
  • Defensa en profundidad
  • No exponer datos

Hay un libro pequeño pero bueno sobre este tema: Seguridad PHP esencial de Chris Shiflett .

Essential PHP Security http://shiflett.org/images/essential-php-security-small.png

En la página de inicio del libro encontrará algunos ejemplos de códigos interesantes y capítulos de muestra.

Puede usar la técnica mencionada anteriormente (IP y UserAgent), descrita aquí: Cómo evitar el robo de identidad


+1 para la prevención de XSS. Sin eso, es imposible protegerse contra CSRF y, por lo tanto, alguien puede "montar" la sesión sin siquiera obtener la ID de la sesión.
Kornel

11

Creo que uno de los principales problemas (que se está abordando en PHP 6) es register_globals. En este momento, uno de los métodos estándar que se usan para evitar register_globalses usar el $_REQUEST, $_GETo $_POSTmatrices.

La forma "correcta" de hacerlo (a partir de 5.2, aunque es un poco defectuoso allí, pero estable a partir de 6, que llegará pronto) es a través de filtros .

Entonces en lugar de:

$username = $_POST["username"];

tu harías:

$username = filter_input(INPUT_POST, 'username', FILTER_SANITIZE_STRING);

o incluso solo:

$username = filter_input(INPUT_POST, 'username');

2
Esto no tiene ninguna relación con la pregunta en absoluto.
The Pixel Developer

55
De Verdad? Entonces, ¿por qué en la respuesta aceptada mencionan no utilizar registros globales? En lo que respecta a la mayoría de los desarrolladores habituales, ¿el registro global y el manejo variable de variables no se incluirían en el marco de las "sesiones", incluso si técnicamente no forma parte del objeto "sesión"?
cmcculloh

9
Estoy de acuerdo, esto no responde completamente la pregunta, pero definitivamente es PARTE de la respuesta a la pregunta. Una vez más, esto desarrolla un punto en la respuesta aceptada, "No utilice registros globales". Esto le dice qué hacer en su lugar.
cmcculloh


5

Usar la dirección IP no es realmente la mejor idea en mi experiencia. Por ejemplo; mi oficina tiene dos direcciones IP que se usan según la carga y constantemente nos encontramos con problemas al usar direcciones IP.

En cambio, opté por almacenar las sesiones en una base de datos separada para los dominios en mis servidores. De esta manera, nadie en el sistema de archivos tiene acceso a esa información de sesión. Esto fue realmente útil con phpBB antes de 3.0 (desde entonces lo han solucionado), pero creo que sigue siendo una buena idea.


3

Esto es bastante trivial y obvio, pero asegúrese de session_destroy después de cada uso. Esto puede ser difícil de implementar si el usuario no cierra sesión explícitamente, por lo que se puede configurar un temporizador para hacerlo.

Aquí hay un buen tutorial sobre setTimer () y clearTimer ().


3

El principal problema con las sesiones y la seguridad de PHP (además del secuestro de sesión) viene con el entorno en el que se encuentra. De manera predeterminada, PHP almacena los datos de la sesión en un archivo en el directorio temporal del sistema operativo. Sin ningún pensamiento o planificación especial, este es un directorio legible a nivel mundial, por lo que toda la información de su sesión es pública para cualquier persona con acceso al servidor.

En cuanto a mantener sesiones en múltiples servidores. En ese punto, sería mejor cambiar PHP a sesiones manejadas por el usuario donde llama a sus funciones proporcionadas a CRUD (crear, leer, actualizar, eliminar) los datos de la sesión. En ese momento, podría almacenar la información de la sesión en una base de datos o una solución similar a Memcache para que todos los servidores de aplicaciones tengan acceso a los datos.

El almacenamiento de sus propias sesiones también puede ser ventajoso si está en un servidor compartido porque le permitirá almacenarlo en la base de datos, que a menudo tiene más control sobre el sistema de archivos.


3

Configuré mis sesiones así:

en la página de inicio de sesión:

$_SESSION['fingerprint'] = md5($_SERVER['HTTP_USER_AGENT'] . PHRASE . $_SERVER['REMOTE_ADDR']);

(frase definida en una página de configuración)

luego en el encabezado que se encuentra en el resto del sitio:

session_start();
if ($_SESSION['fingerprint'] != md5($_SERVER['HTTP_USER_AGENT'] . PHRASE . $_SERVER['REMOTE_ADDR'])) {       
    session_destroy();
    header('Location: http://website login page/');
    exit();     
}

3

php.ini

session.cookie_httponly = 1
change session name from default PHPSESSID

eq Apache agregar encabezado:

X-XSS-Protection    1

httpd.conf -> <FilesMatch "\. (php | phtml | aspx | htm | html) $"> Conjunto de encabezado X-XSS-Protection "1" </FilesMatch>
user956584

Tenga en cuenta que X-XSS-Protectionno es realmente útil en absoluto. De hecho, el algoritmo de protección en sí podría ser explotado, lo que lo hace peor que antes.
Pacerier

2

Verificaría tanto IP como User Agent para ver si cambian

if ($_SESSION['user_agent'] != $_SERVER['HTTP_USER_AGENT']
    || $_SESSION['user_ip'] != $_SERVER['REMOTE_ADDR'])
{
    //Something fishy is going on here?
}

55
La IP puede cambiar legítimamente si el usuario está detrás de una granja de servidores con equilibrio de carga.
Kornel

2
Y user_agent puede cambiar cada vez que un usuario actualiza su navegador.
scotts

3
@scotts Estoy de acuerdo con la parte de IP, pero para la actualización del navegador, establecería la sesión cuando inicien sesión, así que no veo cómo actualizarían su navegador sin crear una nueva sesión una vez que inicien sesión nuevamente.
JasonDavis

Creo que user_agent también puede cambiar al alternar entre el modo compatible en IE8. También es muy fácil fingir.

Sí, pero ¿qué pasa con los usuarios que tenían IP estática eq GSM y se cambia cada media hora? Entonces, IP almacenada en la sesión + nombre de host, WHEN IP! = REMOTE_ADDR comprueba host y compara hostanmes eq. 12.12.12.holand.nl-> cuando es holand.nl == verdadero. Pero algunos anfitriones tenían un nombre de host basado en IP. Luego necesitan comparar la máscara 88.99.XX.XX
user956584

2

Si usa session_set_save_handler () , puede configurar su propio controlador de sesión. Por ejemplo, podría almacenar sus sesiones en la base de datos. Consulte los comentarios de php.net para ver ejemplos de un controlador de sesión de base de datos.

Las sesiones de base de datos también son buenas si tiene varios servidores; de lo contrario, si usa sesiones basadas en archivos, deberá asegurarse de que cada servidor web tenga acceso al mismo sistema de archivos para leer / escribir las sesiones.


2

Debe asegurarse de que los datos de la sesión estén seguros. Mirando tu php.ini o usando phpinfo () puedes encontrar la configuración de tu sesión. _session.save_path_ te dice dónde se guardan.

Verifique el permiso de la carpeta y de sus padres. No debe ser público (/ tmp) ni accesible desde otros sitios web en su servidor compartido.

Suponiendo que aún desea usar la sesión de php, puede configurar php para usar otra carpeta cambiando _session.save_path_ o guardar los datos en la base de datos cambiando _session.save_handler_.

Usted puede ser capaz de establecer _session.save_path_ en su php.ini (algunos proveedores permiten) o para Apache + mod_php, en un archivo .htaccess en la carpeta raíz del sitio: php_value session.save_path "/home/example.com/html/session". También puede configurarlo en tiempo de ejecución con _session_save_path () _.

Consulte el tutorial de Chris Shiflett o Zend_Session_SaveHandler_DbTable para establecer un controlador de sesión alternativo.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.