robo desesionesfinal

12

Upload: miguel-angel-lopez-torralba

Post on 13-Jun-2015

299 views

Category:

Documents


5 download

TRANSCRIPT

Page 1: Robo desesionesfinal
Page 2: Robo desesionesfinal

Robo de sesiones en PHP Miguel Angel Lopez Torralba

INtroduccion

Definicion

Session Hijacking (secuestro o robo de sesión) se refiere a que un individuo (atacante) consigue el identificador de sesión entre una página web y un usuario, de forma que puede hacerse pasar por este y acceder a su cuenta en esa página.

A continuación veremos algunas de las formas en las que un atacante puede robar este identificador y técnicas para intentar prevenirlo en esta introducción y que elaboro un poco más detenidamente en la Seguridad en PHP

Ataque por fuerza bruta

El ataque por fuerza bruta significa probar identificadores aleatoriamente hasta encontrar uno que esté siendo usado. Es como intentar abrir una caja fuerte sin saber la combinación, poniendo números al azar.

Como en el caso de la caja fuerte, cuantos más números tenga la combinación (en este caso el identificador de sesión), más difícil será de adivinar. También ayuda el hecho de que el número o identificador sea aleatorio, y no algo que se pueda predecir. El sistema de identificadores de sesión de PHP es aceptable en este sentido.

Robo por sniffing

Este tipo de ataque se da cuando el atacante tiene un programa de sniffing1 en la red del usuario y puede interceptar el tráfico destinado al mismo, incluido su identificador de sesión. Es algo que ha dado mucho de que hablar a causa de Firesheep, una extensión para Firefox que permite robar las sesiones de Facebook, Twitter y otras páginas web muy conocidas en redes inalámbricas públicas. La única forma de prevenir estos ataques es utilizando cifrado HTTPS en toda la página web.

Propagacion en URL

Si el identificador de sesión se propaga utilizando la URL en lugar de las cookies, cualquier atacante puede robarlo desde muchos sitios:

• Un enlace que el propio usuario ponga en un lugar público. Los usuarios típicos no saben para que sirve ese identificador y no le dan importancia.

• El historial del navegador. • El referrer, que es un encabezado que envían muchos navegadores a las páginas

web en el que les indican la URL de la que vienen.

La forma de prevenir esto es no utilizar la URL para el identificador de sesión; utilizar únicamente las cookies. En PHP esto se consigue con la instrucción:

ini_set('session.use_only_cookies', 1);

1 un analizador de paquetes, un programa de captura de las tramas de una red informática

Page 3: Robo desesionesfinal

Robo de sesiones en PHP Miguel Angel Lopez Torralba

Robo en servidor compartido

Si tenemos nuestra página web alojada en un servidor compartido, los archivos físicos de las sesiones se guardan, por defecto, en un directorio común para todas las páginas web del servidor. Esto quiere decir que todas las personas que tengan su página web en ese mismo servidor, tienen acceso a todos los archivos de sesiones. Dado que el nombre de los archivos es "sess_" más el identificador de sesión, cualquier atacante tendrá una lista de identificadores de sesión válidos con sólo leer la lista de archivos del directorio común.

Esta vulnerabilidad se puede combatir de dos formas:

• Usando la función session_save_path para guardar los archivos de sesión de la página web en un directorio dentro de su cuenta al que sólo pueda acceder PHP

(ya sea por estar fuera del directorio web o con un .htaccess con la instrucción deny from all). Este método no es demasiado fiable, ya que el resto de usuarios seguirá pudiendo leer en ese directorio, sólo tienen que averiguar su localización.

Page 4: Robo desesionesfinal

Robo de sesiones en PHP Miguel Angel Lopez Torralba

• Guardando las sesiones en base de datos en lugar de en archivos. Esto se consigue fácilmente usando la función session_set_save_handler. Esta solución es la más segura ya que la página web será la única que tendrá acceso a la base de datos y, por tanto, a las sesiones.

Robo por Cross-Site Scripting

Si la página web es vulnerable a XSS el atacante puede insertar un código javascript que envíe las cookies de un usuario a su cuenta.

Este tipo de ataque se puede prevenir (además de evitando los ataques XSS)

haciendo que las cookies de sesión tengan el atributo HttpOnly, que evita que puedan ser manejadas por javascript en la mayoría de navegadores. En PHP esto se consigue con la instrucción:

ini_set('session.cookie_httponly', 1);

Metodos de prevenci0n generales

Además de los métodos de prevención concretos vistos para cada tipo de ataque, vamos a ver algunas técnicas de prevención que ayudan a evitar el robo de las sesiones:

• Limitar tiempo de inactividad: eliminar la sesión si está cierto tiempo sin ser usada (de 5 a 30 minutos, según el nivel de seguridad de la página web).

• Cambiar el identificador de sesión: cada cierto tiempo o después de cada acción, cambiar el identificador de la sesión por otro distinto y eliminar la sesión antigua.

• Sistema de logout: dar a los usuarios una forma de salir de su cuenta y destruir la sesión.

• Verificación doble: usar un segundo método para intentar reconocer al usuario

de la sesión. Esto puede hacerse guardando cabeceras como HTTP_USER_AGENT (navegador del usuario) o REMOTE_ADDR (IP del usuario) cuando se crea la sesión, de esta forma:

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

La IP del usuario es más significativa que su navegador, pero es más problemática ya que hay usuarios a los que les cambia la IP habitualmente (IP dinámica, proxies, ...).

Con este sistema, un atacante tendría que robar la sesión a un usuario y, además, enviar la misma cabecera de navegador para poder usarla.

Page 5: Robo desesionesfinal

Robo de sesiones en PHP Miguel Angel Lopez Torralba

Seguridad PHP Seguridad PHP Seguridad PHP Seguridad PHP

PHP tiene soporte nativo para trabajar con sesiones. Cada sesión viene identificada un id aleatorio (32 caracters hexadecimales), que se crea la inicializar dicha sesión con la función session_start(), y que se almacena en una variable llamada PHPSESSID. Este id es esencial ya que cuando creamos una sesión, se crea un array superglobal que almacenará la información de la sesión. Y éste se almacena en el servidor, en un archivo temporal cuyo nombre está formado por 'sess' + dicho ID de sesión (depende de la configuración de php.ini). Ahora necesitamos que el cliente tenga una forma de hacer peticiones al servidor y que este sepa que se está comunicando en un contexto de sesión determinado. O dicho de otra forma el servidor tiene que saber que las peticiones del cliente pertenecen a la sesión.

En una comunicación bidireccional hay dos posibilidades para la comunicación de identificador de sesión: 1- Si el cliente tiene las cookies activadas. En él se crea una cookie con nombre PHPSESSID (modificable en php.ini) y cuyo valor es el identificador de 32 caracteres hexadecimales. Recordemos que cada una de las cookies de un sitio web es una cadena: una lista de parejas "nombre, valor" separadas por punto y coma. La cookie se crea en el cliente gracias a que el servidor, tras haber creado la sesión, envía la primera respuesta con la cookie en su cabecera:

Page 6: Robo desesionesfinal

Robo de sesiones en PHP Miguel Angel Lopez Torralba

HTTP/1.1 200 OK

Date: Sun, 12 Sep 2010 22:46:25 GMT

Server: Apache/2.2.15 (Win32) PHP/5.2.13

X-Powered-By: PHP/5.2.13

Set-Cookie: PHPSESSID=q75n4oq6turdv67uohqkbl7lv5; path=/

Expires: Thu, 5 Sep 2013 08:52:00 GMT

Cache-Control: no-store, no-cache, must-revalidate, post-check=0,

pre-check=0

Pragma: no-cache

Content-Length: 2031

Content-Type: text/html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es">

<head>

<title>Página 1</title>

...

A partir de aquí y siempre dentro de la duración de la sesión, el navegador acompañará esta cookie con las solicitudes de páginas que se hagan a ese mismo servidor. Y este último comprobará que el identificador existe y es válido recuperando la sesión de entre sus ficheros donde se almacenan las sesiones. 2- Si el cliente (navegador) tiene las cookies desactivadas. PHP dispone de una opción alternativa que permite la propagación a través de la URL como hemos visto antes. Para garantizar la propagación de las sesiones aún cuando el navegador esté configurado para no aceptar cookies. Por lo tanto se tendrá que pasar el PHPSESSID junto con las llamadas a las páginas siguientes. Y para ello tenemos 2 opciones: - Añadir el PHPSESSID manualmente cada vez que creamos un enlace:

<a href="page.php?PHPSESSID=<?php

echo htmlspecialchars(session_id()); ?>">haga click</a>

- Dejar que PHP lo añada automáticamente. Si modificamos en el php.ini la variable session.use_trans_sid a True, PHP añadirá automáticamente el PHPSESSID a las URI's de tu sitio web de manera transparente al desarrollador. Siempre que la sesión no haya expirado y que las cookies del cliente estén desactivadas. Y así, cuando el cliente envíe nuevamente la petición al servidor a través de una URI con PHPSESSID, se podrá coger mediante el array $_GET para comprobar que no ha habido cambio. Esta opción viene desactivada por seguridad ya que estamos mostrando dicho id en la

url.

También se puede activar en tiempo de ejecución, en el script evidentemente, mediante

Page 7: Robo desesionesfinal

Robo de sesiones en PHP Miguel Angel Lopez Torralba

ini_set('session.use_trans_sid', true);

Tal y como hemos visto en la introducción.

Problemas de seguridad con PHPSESSID

El mayor problema con el envío del id de la sesión de un lado a otro, ya sea en las cabeceras o en la url, es que es susceptible a ser interceptado y con ello aumenta la posibilidad de acceder a un servidor de forma ilegítima.

Podría ser interceptado si alguien escanea o monitoriza el tráfico de la red. Y debido al fuerte crecimiento de las redes WIFI con débiles protocolos de encriptación, hacen que el apropiarse de los datos de sesión sea más sencillo. Además, la posibilidad anteriormente comentada de incluir el PHPSESSID en la url hace que incluso los usuarios despistados revelen ellos mismos el id. Ya que es posible que al copiar y compartir un enlace, estén enviando información de su sesión. Y esto sucede más de lo que uno puede pensar.

Pero no solo es posible interceptar el PHPSESSID mediante un escaneo o monitorización. También es posible a través de un proxy que actué entre el cliente y el servidor y capturar la información de la sesión. Y esto podría ocurrir mediante un mensaje cuyo enlace no lleva al sitio de confianza que se presupone. Si no que lleva a un servidor (hace de proxy) que se encarga de redirigir al sitio legítimo y capturar la información de las cabeceras donde puede haber alguna cookie de sesión.

Ataque por fijacion de sesion

Como hemos visto, cuando un usuario se autentica en una aplicación, el valor de la sesión que se creará no cambiará en toda la sesión (si no lo cambiamos nosotros). Por tanto, se puede atacar intentando que la víctima se autentique en la aplicación usando un ID de sesión previamente creada por el atacante. De tal forma que una vez el usuario se autentique, el atacante pueda acceder a la aplicación con el mismo rol que la víctima gracias a que conoce la sesión de ésta. Este ataque es posible gracias a uso de PHPSESSID en las las urls y a programar el comportamiento de las sesiones de una forma equivocada.

Page 8: Robo desesionesfinal

Robo de sesiones en PHP Miguel Angel Lopez Torralba

Ejemplo

Vamos a ver un ejemplo donde un mal uso de una función puede provocar un fallo de seguridad. Con la función PHP session_id() hay que tener cuidado ya que ofrece la posibilidad de cambiar el identificador actual de la sesión si se le pasa como parámetro dicho identificador. Pero para que funcione este cambio tiene que ir antes de iniciar la sesión con la llamada a session_start().Y esto puede ser aprovechado por los atacantes para intentar que un usuario registrado se identifique y sin saberlo cree un PHPSESSID conocido por ellos. Y así poder suplantarlo. Imaginanemos que un atacante, conociendo el uso de id de sesión en la url por parte del servidor, proporciona este enlace para ver si lo usa algún usuario registrado en dicho servidor y que tenga desactivado el uso de cookies (recuerda que el servidor que haga uso de PHPSESSID en url primero comprueba que las cookies están desactivadas en el cliente):

www.ejemplo.com/index.php?action=login&PHPSESSID=1234

Pues si ese usuario se identifica en el servidor y resulta que el servidor ejecuta algo parecido a session_id($_GET['PHPSESSID']) antes de una llamada a session_start(), se acaba de crear una sesión con el id 1234. Y como ese ID lo conoce el atacante, se puede apropiar de la sesión. Y utilizarla para identificarse en el servidor y suplantar al usuario legítimo. La utilización de $_GET['PHPSESSID'] solo tiene sentido si se transportan PHPSESSID por la url. Si el servidor solo utilizará cookies no tendría sentido que en algún momento se capturase de variable anterior. Por lo tanto este ataque (el del ejemplo) no podría llevarse a cabo si solo se transmite el PHPSESSID por cookies. Pero aún está el problema de la interceptación de la comunicaciones (proxy o escaneo) y utilizar la cookie de sesión para identificarse.

Opciones para prevenir ataques Aunque hemos visto anteriormente algunas formas de evitar ataques, en este caso vamos a hacerlo de forma más tecnica y enfocada a PHP SSL

Muchos sitios web usan SSL únicamente para encriptar contenido de formularios, como podría ser el de login. Sin embargo también sería muy aconsejable usar SSL para encriptar toda la información que se transmite entre las partes de la comunicación (cliente-servidor). Ya que encriptando la PHPSESSID podríamos protegernos de dos de los tipos de ataques comentados en el apartado anterior:

Page 9: Robo desesionesfinal

Robo de sesiones en PHP Miguel Angel Lopez Torralba

-Por un lado nos protegeríamos gracias a la encriptación de posible atacantes que escaneando o monitorizando el tráfico de la red buscan datos de sesión. -Y por otro lado nos protegeríamos de posibles redirecciones a proxys inesperados. Ya que al establecerse la comunicación entre el cliente y el servidor fraudulento (autofirmado con su certificado fraudulento), el navegador (cliente) nos avisaría que el certificado de dicho servidor es desconocido.

Evidentemente el problema de este mecanismo de seguridad es su coste económico (certificados de clave pública firmados por entidad certificadora). Por lo que se van a presentar otros mecanismos para proporcionar una seguridad decente sin coste adicional. Pero que no es completa al cien por cien. Ya que el la seguridad completa ante proxies y escaneos solo la proporciona el uso correcto de SSL.

Tiempo de expiracion en la sesion

Esto tiene poca historia. Si definimos un tiempo de expiración de sesión muy alto estamos dando más tiempo al usuario 'malicioso' a que pruebe y desarrolle sus ataques. El tiempo de vida de la 'cookie de sesión' lo podemos especificar mediante la siguiente función:

ini_set("session.cookie_lifetime",120); //El tiempo viene dado en

segundos

Es posible que intentéis modificar el tiempo de vida de una cookie y no funcione. Hay que tener en cuenta que es posible que vuestro equipo siga teniendo una cookie activa, por lo que hasta que no caduque la anterior no se guardará la nueva con el tiempo de vida modificado. Pero este cambio sólo afecta la vida de la cookie y la sesión puede ser todavía válida. Es tarea del servidor invalidar una sesión, no del cliente. Así que como lo que queremos es que expire la sesión en el servidor tenemos que buscar una alternativa mejor. Una buena solución sería utilizar marcas de tiempo. En el siguiente ejemplo destruiremos las sesión si han pasado mas de 30 minutos desde la identificación del usuario. Tras hacer login y al crear la sesión nos guardariamos la tiempo Unix del último acceso:

$_SESSION['LAST_LOGIN'] = time(); // última identificación

Y podríamos introducir la siguiente función para saber si tenemos que cancelar la sesión o no por haber pasado el tiempo límite.

Page 10: Robo desesionesfinal

Robo de sesiones en PHP Miguel Angel Lopez Torralba

function tiempo() {

if (isset($_SESSION['LAST_LOGIN']) && (time() -

$_SESSION['LAST_LOGIN'] > 1800)) {

if (isset($_COOKIE[session_name()])) {

setcookie(session_name(), "", time() - 3600, "/");

//limpiamos completamente el array superglobal

session_unset();

//Eliminamos la sesión (archivo) del servidor

session_destroy();

}

header(...) //redirigir al punto de partida para identificarse

exit;

}

//...

}

Afortunadamente dependiendo de la versión de PHP que estemos utilizando, así como de la configuración de nuestro php.ini, las sesiones desaparecen por si solas en periodos que van desde los 30 a 180 minutos, claro que este puede ser tiempo más que necesario para que nos suplanten la sesión. Cookies vs PHPSESSID en la URL

A partir de PHP 4.2, la variable session.use_trans_sid en el php.ini esta a false por lo que por defecto el uso de PHPSESSID automático en las urls, por parte de php, esta desactivado. Y únicamente se usarán cookies para la comunicación del PHPSSID. Tambien podemos usar este código en entornos donde session.use_trans_sid este activo y queramos desactivarlo.

ini_set('session.use_only_cookies', true);

ini_set('session.use_trans_sid', false);

Hay que recordar que usar cookies no evita ataque mediante proxies o escaneos. Regenerar ID de sesion

Una manera facíl de proteger contra ataques provocados por el posible robo del identificador de sesión es mediante una simple regeneración de dicho id. De está forma un atacante no podría utilizar el id apropiado ya que no sería el mismo que el generado por el servidor. Hay que pensar que el robo de id de sesión solo es útil para el atacante después de que el usuario se haya logeado y se haya creado la sesión. Por lo tanto es un buen momento para regenerar dicho id. en tiempo de ejecución:

Page 11: Robo desesionesfinal

Robo de sesiones en PHP Miguel Angel Lopez Torralba

Por ejemplo:

<?php

session_start();

if (!isset($_SESSION['inicializada']))

{

session_regenerate_id();

$_SESSION['inicializada'] = true;

}

?>

Esto nos protegería ante la fijación de la sesión ya que el id que pretendía usar el atacante, forzando al usuario a crear una sesión con él, habrá cambiado. Aunque evidentemente, no solucionará nada si intercepta todas las comunicaciónes. Ya que todos los cambios de cookies de sesión viajan por las cabeceras de la peticiones y respuestas. User-Agent

Una forma de incrementar la seguridad es mediante el uso del user-agent. En las cabeceras de cada mensaje entre cliente y servidor, además de la cookie con el PHPSESSID también se especifica el user-agent. Que incluye información como la versión del navegador del cliente que está haciendo las peticiones. Pues podemos utilizar esta información para que aunque se apropien del PHPSESSID, los atacantes necesiten las mismas condiciones que indica el user-agent. Por lo que podríamos guardarlo tras identificar al usuario y posteriormente hacer comprobaciones para cada para cada script.

<?php

/*login.php*/

...

if($existeUsuario){

session_start( );

$_SESSION['user_id'] = $data['user_id'];

$_SESSION['first_name'] = $data['first_name'];

$_SESSION['agent'] = sha1($_SERV['HTTP_USER_AGENT']);

header("location:home.php");

}

...

Page 12: Robo desesionesfinal

Robo de sesiones en PHP Miguel Angel Lopez Torralba

<?php

/*home.php*/

session_start();

if (isset($_SESSION['agent']))

{

if ($_SESSION['agent'] != sha1($_SERVER['HTTP_USER_AGENT']))

{

exit;

}

}

...

?>

Sin embargo hay que tener cuidado ya que por ejemplo Internet Explorer, al usar el modo compatibilidad, puede cambiar su usar-agent.

ConclusionConclusionConclusionConclusion La forma eficaz de combatir el robo de sesiones es mediante la combinación de las técnicas explicadas. - Usar SSL para evitar que les sirva de algo la información interceptada por lo atacantes. - Tener el servidor configurado correctamente (no permitir PHPSESSID en url, expirar sesiones ....). - Regenerar sesiones para que si alguien ha obtenido en algún momento un identificador de sesión no pueda utilizarlo. Ya que el identificador habrá cambiado con la regeneración y el que tiene el atacante no es válido.