¿Cuál es la mejor manera de evitar el secuestro de sesión?

124

Específicamente, esto se refiere al uso de una cookie de sesión de cliente para identificar una sesión en el servidor.

¿Es la mejor respuesta para usar el cifrado SSL / HTTPS para todo el sitio web, y tiene la mejor garantía de que ningún hombre en el medio de ataques podrá rastrear una cookie de sesión de cliente existente?

¿Y quizás la segunda mejor opción para usar algún tipo de cifrado en el valor de la sesión en sí que se almacena en la cookie de la sesión?

Si un usuario malintencionado tiene acceso físico a una máquina, ¿aún puede mirar el sistema de archivos para recuperar una cookie de sesión válida y usarla para secuestrar una sesión?

Adán
fuente

Respuestas:

140

Cifrar el valor de la sesión tendrá cero efecto. La cookie de sesión ya es un valor arbitrario, encriptarla solo generará otro valor arbitrario que puede ser rastreado.

La única solución real es HTTPS. Si no desea hacer SSL en todo su sitio (quizás tenga problemas de rendimiento), es posible que solo pueda escapar con SSL para proteger las áreas sensibles. Para hacer eso, primero asegúrese de que su página de inicio de sesión sea HTTPS. Cuando un usuario inicia sesión, configure una cookie segura (lo que significa que el navegador solo la transmitirá a través de un enlace SSL) además de la cookie de sesión normal. Luego, cuando un usuario visita una de sus áreas "sensibles", rediríjalas a HTTPS y verifique la presencia de esa cookie segura. Un usuario real lo tendrá, un secuestrador de sesión no.

EDITAR : Esta respuesta se escribió originalmente en 2008. Ahora es 2016, y no hay razón para no tener SSL en todo su sitio. ¡No más texto plano HTTP!

Josh Hinman
fuente
28
HTTPS solo evitará el olfateo. Pero si tiene un XSS, o las ID de sesión se pueden adivinar fácilmente, o es vulnerable a la fijación de la sesión, o el almacenamiento de su ID de sesión es débil (¿inyección SQL?), SSL no será una mejora en absoluto.
Calimo
55
@ Josh Si un usuario malintencionado tiene acceso físico a una máquina, ¿aún puede ver el sistema de archivos para recuperar una cookie de sesión válida y usarla para secuestrar una sesión?
Pacerier
72
Si un usuario malintencionado tiene acceso físico a un sistema de archivos, no necesita secuestrar una sesión.
Josh Hinman
25
@Josh. No es cierto, a veces un usuario tiene acceso físico por tiempo limitado a un sistema de archivos. Imagine una computadora portátil que un colega deja desbloqueada corriendo hacia el baño, ahora todo lo que tengo que hacer es ir a esa computadora portátil, instalar el complemento EditThisCookie, tomar sus cookies en plus.google.com utilizando la función de exportación EditThisCookie y ahora tengo su cuenta . Tiempo tomado: 18 segundos.
Pacerier
1
Estoy bastante seguro de que Google tendrá algún tipo de característica de seguridad de construir-en, ya que es, obviamente, el primero que haría pensar en cuando se habla de secuestro de sesión
xorinzor
42

El SSL solo ayuda a detectar ataques. Si un atacante tiene acceso a su máquina, supondré que también puede copiar su cookie segura.

Por lo menos, asegúrese de que las cookies antiguas pierdan su valor después de un tiempo. Incluso un ataque de secuestro exitoso se verá frustrado cuando la cookie deje de funcionar. Si el usuario tiene una cookie de una sesión que inició sesión hace más de un mes, vuelva a ingresar su contraseña. Asegúrese de que cada vez que un usuario haga clic en el enlace "cerrar sesión" de su sitio, que el UUID de la sesión anterior nunca se pueda volver a usar.

No estoy seguro de si esta idea funcionará, pero aquí va: agregue un número de serie en su cookie de sesión, tal vez una cadena como esta:

SessionUUID, número de serie, fecha / hora actual

Cifre esta cadena y úsela como cookie de sesión. Cambie regularmente el número de serie, tal vez cuando la cookie tenga 5 minutos y luego vuelva a emitirla. Incluso podría volver a emitirlo en cada vista de página si lo desea. En el lado del servidor, mantenga un registro del último número de serie que haya emitido para esa sesión. Si alguna vez alguien envía una cookie con el número de serie incorrecto, significa que un atacante puede estar utilizando una cookie que interceptó anteriormente, por lo que invalida el UUID de la sesión y le pide al usuario que vuelva a ingresar su contraseña y luego vuelva a emitir una nueva cookie.

Recuerde que su usuario puede tener más de una computadora, por lo que puede tener más de una sesión activa. No haga algo que los obligue a iniciar sesión nuevamente cada vez que cambien de computadora.


fuente
Sé que esta es una publicación antigua, pero solo quería incluir que si un atacante secuestrara la sesión dentro de la ventana asignada por el "número de serie", entonces esto no lo afectaría.
aplastar
@crush, pero luego el atacante quedaría bloqueado después de la ventana asignada, ¿verdad? Por lo menos, la ventana de ataque es pequeña (er).
Johanneke
2
El único problema es que si el usuario abandona su sitio web durante 5 minutos, tendrá que volver a iniciar sesión
elipoultorak
21

¿Has considerado leer un libro sobre seguridad PHP? Muy recomendable.

He tenido mucho éxito con el siguiente método para sitios no certificados SSL.

  1. Deshabilite varias sesiones bajo la misma cuenta, asegurándose de no verificar esto únicamente por dirección IP. En su lugar, verifique mediante el token generado al iniciar sesión que se almacena con la sesión de los usuarios en la base de datos, así como la dirección IP, HTTP_USER_AGENT, etc.

  2. Uso de hipervínculos basados ​​en relaciones Genera un enlace (por ejemplo, http://example.com/secure.php?token=2349df98sdf98a9asdf8fas98df8 ) El enlace se agrega con una cadena MD5 salada al azar x-BYTE (tamaño preferido), al redireccionar la página, se genera aleatoriamente el token corresponde a una página solicitada.

    • Tras la recarga, se realizan varias verificaciones.
    • Dirección IP de origen
    • HTTP_USER_AGENT
    • Token de sesión
    • tú entiendes.
  3. Cookie de autenticación de sesión de corta duración. como se publicó anteriormente, una cookie que contiene una cadena segura, que es una de las referencias directas a la validez de las sesiones, es una buena idea. Haga que caduque cada x minutos, vuelva a emitir ese token y vuelva a sincronizar la sesión con los nuevos datos. Si hay algún error en los datos, cierre la sesión del usuario o pídale que vuelva a autenticar su sesión.

No soy en absoluto un experto en el tema, he tenido un poco de experiencia en este tema en particular, espero que algo de esto ayude a alguien.

Nathan
fuente
44
¿Hay algún libro que recomendarías?
Rikki
1
Especialmente dado que el OP no indicó nada sobre PHP específicamente, diría que es mejor mirar solo un libro de seguridad general (especialmente porque la seguridad entre diferentes idiomas difiere solo en los detalles de implementación, pero los conceptos siguen siendo los mismos).
matts1
en 2017, incluso facebook / gmail, etc. permite múltiples sesiones bajo la misma cuenta (especialmente con dispositivos móviles) a menos que odie a sus usuarios, el # 1 está un poco desactualizado.
cowbert
20
// Collect this information on every request
$aip = $_SERVER['REMOTE_ADDR'];
$bip = $_SERVER['HTTP_X_FORWARDED_FOR'];
$agent = $_SERVER['HTTP_USER_AGENT'];
session_start();

// Do this each time the user successfully logs in.
$_SESSION['ident'] = hash("sha256", $aip . $bip . $agent);

// Do this every time the client makes a request to the server, after authenticating
$ident = hash("sha256", $aip . $bip . $agent);
if ($ident != $_SESSION['ident'])
{
    end_session();
    header("Location: login.php");
    // add some fancy pants GET/POST var headers for login.php, that lets you
    // know in the login page to notify the user of why they're being challenged
    // for login again, etc.
}

Lo que esto hace es capturar información 'contextual' sobre la sesión del usuario, piezas de información que no deberían cambiar durante la vida de una sola sesión. Un usuario no va a estar en una computadora en los Estados Unidos y en China al mismo tiempo, ¿verdad? Entonces, si la dirección IP cambia repentinamente dentro de la misma sesión, lo que implica un intento de secuestro de la sesión, entonces usted asegura la sesión finalizando la sesión y obligando al usuario a volver a autenticarse. Esto frustra el intento de pirateo, el atacante también se ve obligado a iniciar sesión en lugar de obtener acceso a la sesión. Notifique al usuario del intento (agárrelo un poco), y vola, un usuario ligeramente molesto + informado y su sesión / información está protegida.

Agregamos User Agent y X-FORWARDED-FOR para hacer nuestro mejor esfuerzo para capturar la singularidad de una sesión para sistemas detrás de servidores proxy / redes. Es posible que pueda usar más información que eso, siéntase libre de ser creativo.

No es 100%, pero es bastante efectivo.

Hay más cosas que puede hacer para proteger las sesiones, expirarlas, cuando un usuario abandona un sitio web y regresa, tal vez lo obligue a iniciar sesión nuevamente. Puede detectar un usuario que sale y regresa capturando un HTTP_REFERER en blanco (el dominio se escribió en la barra de URL), o verifique si el valor en HTTP_REFERER es igual o no a su dominio (el usuario hizo clic en un enlace externo / diseñado para llegar a su sitio).

Caduca las sesiones, no dejes que sigan siendo válidas indefinidamente.

No confíes en las cookies, pueden ser robadas, es uno de los vectores de ataque para el secuestro de sesión.

itsonyis
fuente
3
Me he encontrado con una situación anterior en la que un determinado ISP (bastante grande, pero técnicamente atrasado) cambiaría la IP del navegador del usuario de vez en cuando en función de redirigir las conexiones de sus usuarios. Esto hizo que la verificación REMOTE_ADDR nos devolviera falsos negativos.
goofballLogic
¿Por qué molestarse en crear un hash? $_SESSION['ident'] = $aip . $bip . $agent;Sería igual de seguro.
Dan Bray
2
Si tiene usuarios de Mobile que usan su sitio web sobre la marcha y se mueven de un punto de acceso a otro, sus IP seguirán cambiando y se cerrará la sesión de su cuenta.
Kareem
¿Qué pasa con los proxies y las VPN? Cualquier persona que use un proxy TOR será desconectado constantemente de sus cuentas ... de hecho, cada pocos minutos.
Bradley
Incluso si pasa por alto eso, las direcciones IP pueden ser manipuladas por el cliente, por lo que esto no haría mucho para disuadir a un atacante de todos modos.
Bradley
9

Pruebe el protocolo de cookies seguras descrito en este documento por Liu, Kovacs, Huang y Gouda:

Como se indica en el documento:

Un protocolo de cookies seguro que se ejecuta entre un cliente y un servidor debe proporcionar los siguientes cuatro servicios: autenticación, confidencialidad, integridad y antirrepetición.

En cuanto a la facilidad de implementación:

En términos de eficiencia, nuestro protocolo no implica ninguna búsqueda en la base de datos o criptografía de clave pública. En términos de implementación, nuestro protocolo puede implementarse fácilmente en un servidor web existente, y no requiere ningún cambio en la especificación de cookies de Internet.

En resumen: es seguro, liviano, me funciona genial.

Hubert
fuente
9
Su enlace es una especificación del protocolo: ¿tiene un enlace a una implementación? Eso sería genial, gracias.
Adam
9

No hay forma de evitar el secuestro de la sesión al 100%, pero con algún enfoque podemos reducir el tiempo para que un atacante se apodere de la sesión.

Método para evitar el secuestro de sesión:

1 - use siempre la sesión con certificado SSL;

2: envíe la cookie de sesión solo con httponly establecido en true (evite que javascript acceda a la cookie de sesión)

2: use el ID de regeneración de sesión al iniciar y cerrar sesión (nota: no use la regeneración de sesión en cada solicitud porque si tiene una solicitud ajax consecutiva, entonces tiene la oportunidad de crear múltiples sesiones).

3 - establecer un tiempo de espera de sesión

4: almacene el agente de usuario del navegador en una variable $ _SESSION y compárelo con $ _SERVER ['HTTP_USER_AGENT'] en cada solicitud

5: establezca una cookie de token y establezca el tiempo de caducidad de esa cookie en 0 (hasta que se cierre el navegador). Vuelva a generar el valor de la cookie para cada solicitud. (Para la solicitud ajax, no regenere la cookie de token). EX:

    //set a token cookie if one not exist
    if(!isset($_COOKIE['user_token'])){
                    //generate a random string for cookie value
        $cookie_token = bin2hex(mcrypt_create_iv('16' , MCRYPT_DEV_URANDOM));

        //set a session variable with that random string
        $_SESSION['user_token'] = $cookie_token;
        //set cookie with rand value
        setcookie('user_token', $cookie_token , 0 , '/' , 'donategame.com' , true , true);
    }

    //set a sesison variable with request of www.example.com
    if(!isset($_SESSION['request'])){
        $_SESSION['request'] = -1;
    }
    //increment $_SESSION['request'] with 1 for each request at www.example.com
    $_SESSION['request']++;

    //verify if $_SESSION['user_token'] it's equal with $_COOKIE['user_token'] only for $_SESSION['request'] > 0
    if($_SESSION['request'] > 0){

        // if it's equal then regenerete value of token cookie if not then destroy_session
        if($_SESSION['user_token'] === $_COOKIE['user_token']){
            $cookie_token = bin2hex(mcrypt_create_iv('16' , MCRYPT_DEV_URANDOM));

            $_SESSION['user_token'] = $cookie_token;

            setcookie('user_token', $cookie_token , 0 , '/' , 'donategame.com' , true , true);
        }else{
            //code for session_destroy
        }

    }

            //prevent session hijaking with browser user agent
    if(!isset($_SESSION['user_agent'])){
        $_SESSION['user_agent'] = $_SERVER['HTTP_USER_AGENT'];
    }

    if($_SESSION['user_agent'] != $_SERVER['HTTP_USER_AGENT']){
      die('session hijaking - user agent');
    }

nota: no regenere la cookie de token con la solicitud de ajax nota: el código anterior es un ejemplo. nota: si los usuarios cierran sesión, el token de cookie debe destruirse, así como la sesión

6 - no es un buen enfoque utilizar la ip del usuario para evitar el secuestro de sesión porque la ip de algunos usuarios cambia con cada solicitud. QUE AFECTAN A USUARIOS VÁLIDOS

7 - personalmente almaceno los datos de la sesión en la base de datos, depende de usted qué método adopte

Si encuentra un error en mi enfoque, corríjame. Si tiene más formas de evitar la sesión de hyjaking, dígame.

Alexandru
fuente
Hola, estoy tratando de evitar el secuestro de sesión (en ASP.NET) y consideré todos los pasos anteriores que sugerí. Es un trabajo aproximado, pero cuando uso el modo InPrivateBrowsing / incógnito del navegador, la sesión es Secuestrada. ¿Puede sugerir algo adicional para agregar en la cadena sessionId?
Vishwanath Mishra
4

Asegúrese de no usar enteros incrementales para las ID de sesión. Mucho mejor usar un GUID o alguna otra cadena de caracteres larga generada aleatoriamente.

Kibbee
fuente
3

Hay muchas formas de crear protección contra el secuestro de sesión, sin embargo, todas están reduciendo la satisfacción del usuario o no son seguras.

  • Comprobaciones de IP y / o X-FORWARDED-FOR. Estos funcionan, y son bastante seguros ... pero imagina el dolor de los usuarios. Llegan a una oficina con WiFi, obtienen una nueva dirección IP y pierden la sesión. Tengo que iniciar sesión de nuevo.

  • Comprobaciones de agente de usuario. Igual que el anterior, la nueva versión del navegador está fuera y pierde una sesión. Además, estos son realmente fáciles de "hackear". Es trivial para los hackers enviar cadenas falsas de UA.

  • Token localStorage. Al iniciar sesión, genere un token, guárdelo en el almacenamiento del navegador y guárdelo en una cookie cifrada (cifrada en el lado del servidor). Esto no tiene efectos secundarios para el usuario (localStorage persiste a través de las actualizaciones del navegador). No es tan seguro, ya que es solo seguridad a través de la oscuridad. Además, podría agregar algo de lógica (cifrado / descifrado) a JS para ocultarlo aún más.

  • Reedición de cookies. Esta es probablemente la forma correcta de hacerlo. El truco es permitir que solo un cliente use una cookie a la vez. Por lo tanto, el usuario activo volverá a emitir cookies cada hora o menos. La cookie antigua se invalida si se emite una nueva. Los piratas informáticos aún son posibles, pero mucho más difíciles de hacer: se rechazará el acceso de un hacker o un usuario válido.

Escotilla
fuente
1

Consideremos que durante la fase de inicio de sesión, el cliente y el servidor pueden acordar un valor de sal secreto. Posteriormente, el servidor proporciona un valor de recuento con cada actualización y espera que el cliente responda con el hash de (sal secreta + recuento). El secuestrador potencial no tiene ninguna forma de obtener este valor de sal secreto y, por lo tanto, no puede generar el siguiente hash.

davej
fuente
3
Pero, ¿cómo quieres almacenar esta sal en el lado del cliente para que nadie pueda robarla?
Dcortez
1

AFAIK el objeto de sesión no es accesible en el cliente, ya que está almacenado en el servidor web. Sin embargo, la identificación de la sesión se almacena como una Cookie y permite que el servidor web rastree la sesión del usuario.

Para evitar el secuestro de sesión utilizando la identificación de sesión, puede almacenar una cadena hash dentro del objeto de sesión, realizada mediante una combinación de dos atributos, addr remoto y puerto remoto, a los que se puede acceder en el servidor web dentro del objeto de solicitud. Estos atributos vinculan la sesión del usuario al navegador donde el usuario inició sesión.

Si el usuario inicia sesión desde otro navegador o un modo de incógnito en el mismo sistema, la dirección IP seguirá siendo la misma, pero el puerto será diferente. Por lo tanto, cuando se accede a la aplicación, el servidor web le asignará una identificación de sesión diferente.

A continuación se muestra el código que implementé y probé copiando el ID de sesión de una sesión a otra. Funciona bastante bien Si hay una escapatoria, dígame cómo la simuló.

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    HttpSession session = request.getSession();
    String sessionKey = (String) session.getAttribute("sessionkey");
    String remoteAddr = request.getRemoteAddr();
    int remotePort = request.getRemotePort();
    String sha256Hex = DigestUtils.sha256Hex(remoteAddr + remotePort);
    if (sessionKey == null || sessionKey.isEmpty()) {
        session.setAttribute("sessionkey", sha256Hex);
        // save mapping to memory to track which user attempted
        Application.userSessionMap.put(sha256Hex, remoteAddr + remotePort);
    } else if (!sha256Hex.equals(sessionKey)) {
        session.invalidate();
        response.getWriter().append(Application.userSessionMap.get(sessionKey));
        response.getWriter().append(" attempted to hijack session id ").append(request.getRequestedSessionId()); 
        response.getWriter().append("of user ").append(Application.userSessionMap.get(sha256Hex));
        return;
    }
    response.getWriter().append("Valid Session\n");
}

Utilicé el algoritmo SHA-2 para hacer hash del valor usando el ejemplo dado en SHA-256 Hashing en baeldung

Esperamos sus comentarios.

Jzf
fuente
@zaph Lo siento, pero no agregué la respuesta para ganar rep. El punto tampoco es el cifrado SHA-2. Pero el hecho de que pude detectar el uso de la cookie de identificación de sesión de otro usuario en la sesión de otro usuario, es decir, el secuestro de sesión como en la pregunta original. Probé mi solución y descubrí que funciona. Pero no soy un experto en esto, así que me gustaría que la comunidad verifique si mi respuesta es lo suficientemente buena. Tal vez pueda ver qué hace mi fragmento de código y decidir si responde a la pregunta. ¡Gracias!
Jzf
@zaph Gracias por señalar el error. He actualizado mi respuesta según su sugerencia. Elimine su voto negativo si cree que la respuesta es útil.
Jzf
0

Para reducir el riesgo, también puede asociar la IP de origen con la sesión. De esa forma, un atacante debe estar dentro de la misma red privada para poder usar la sesión.

La verificación de los encabezados de referencia también puede ser una opción, pero se pueden suplantar más fácilmente.

Julio Cesar
fuente
77
no, no puede usar la IP de origen, ya que puede cambiar, ya sea a través de IP dinámicas, cambiadas cuando un usuario se desconecta temporalmente, o mediante el uso (implícito o explícito) de una granja de servidores proxy. Además, los secuestradores de sesión que provienen del mismo ISP pueden usar el mismo proxy e IP que un usuario legítimo ...
Olaf Kock
1
PHP-Nuke tiene una buena página sobre su enfoque de sesión, y hablan en detalle sobre cómo conectarlo a la IP no funciona con todos los ISP phpnuke.org/…
Sembiance
44
Cambiar los Ip es muy común con los proveedores de internet móvil. Con Vodafone, mi IP cambia con CADA solicitud.
Blaise
1
Algo de una publicación antigua pero para promover esto. Las IP son, como se mencionó, una mala idea. Como se mencionó, los usuarios móviles tienden a vagar por las IP. Algunos ISP en el pasado también tenían IP itinerantes (como AOL), sin embargo, este enfoque se está volviendo más popular ahora con la escasez de IPv4 IP. Tales ISP incluyen Plus net y BT
Peter
-15

Proteger por:

$ip=$_SERVER['REMOTE_ADDER'];
$_SESSEION['ip']=$ip;
Nima
fuente
12
No veo lo que estás haciendo aquí.
samayo