¿Es esta una función segura para verificar si un usuario no ha robado una cookie de sesión?

1

Como ejercicio para la clase, estoy creando una clase que administra las sesiones de usuario.

Los detalles de la sesión se almacenan en una base de datos y también hay una variable $_SESSION[user_id] para llevar entre páginas.

La idea es que sería difícil para un atacante robar la cookie Y la dirección IP Y el agente de usuario Y mantener la sesión actualizada, ya que puse un límite de 15 minutos.

Cuando el usuario inicia sesión, se crea el objeto de la base de datos y se verifica su existencia en cada página visitada.

<?php
//Recojo parametros de formulario de logeo
$username = $_POST['username'];
$password = $_POST['password'];

//abro conexion base de datos
$mysqli = new mysqli("localhost", "root", "unir_2014", "wordpress");
if ($mysqli->connect_errno) {
    printf("La conexion ha fallado! El servidor responde: %s\n", $mysqli->connect_error);
    exit();
}
//----------------------------------------------------------------------------------------//       
//----------------------------------------------------------------------------------------//     //EXPIRAR         
            $comienzo = time(); // Momento al logearse
            // Le damos un tiempo de expiracion de 1 minuto
            $expirar = $comienzo + (15 * 60);
//----------------------------------------------------------------------------------------//     //IP ADDRESS  
              if (isset($_SERVER)) {
                  if (isset($_SERVER["HTTP_X_FORWARDED_FOR"]) && ip2long($_SERVER["HTTP_X_FORWARDED_FOR"]) !== false) {
                      $ipadres = $_SERVER["HTTP_X_FORWARDED_FOR"];
                  } elseif (isset($_SERVER["HTTP_CLIENT_IP"])  && ip2long($_SERVER["HTTP_CLIENT_IP"]) !== false) {
                      $ipadres = $_SERVER["HTTP_CLIENT_IP"];
                  } else {
                      $ipadres = $_SERVER["REMOTE_ADDR"];
                  }
              } else {
                  if (getenv('HTTP_X_FORWARDED_FOR') && ip2long(getenv('HTTP_X_FORWARDED_FOR')) !== false) {
                      $ipadres = getenv('HTTP_X_FORWARDED_FOR');
                  } elseif (getenv('HTTP_CLIENT_IP') && ip2long(getenv('HTTP_CLIENT_IP')) !== false) {
                      $ipadres = getenv('HTTP_CLIENT_IP');
                  } else {
                      $ipadres = getenv('REMOTE_ADDR');
                  }
              }
//----------------------------------------------------------------------------------------//      $version_cliente = $_SERVER['HTTP_USER_AGENT'];
//----------------------------------------------------------------------------------------//$query = "SELECT * FROM sesiones WHERE name ='" .$username."'";
if ($result = $mysqli->query($query)) {
    while($row = mysqli_fetch_array($result)) {
        $salt = $row['salt'];
        $passcheck = $row['password'];
        $id_usuario = $row['id_usuario'];
        $passwordin = md5($password.$salt);
        $direccion_ip = $ipadres;
    }
    //compruebo si la contraseña coincide con el hash almacenado en la base de datos
         if( $passcheck === $passwordin){

                echo '<script> window.location = "privatecontent.php" </script>';
                //if the user has javascript

                $url = 'privatecontent.php';
                echo '<META HTTP-EQUIV=Refresh CONTENT="0; URL='.$url.'">';
                //if the user doesnt have javascript*
//----------------------------------------------------------------------------------------//    //INTRODUCIMOS OBJETO SESSION EN LA BASE DE DATOS 
    //mysqli_query($connection, "INSERT INTO 'wordpress'.'session_log' ('id_sesion', 'id_usuario', 'direccion_ip', 'version_cliente', 'expirar') VALUES ('', '".$id_usuario."', '".$direccion_ip."', '".$version_cliente."', '".$expirar."');");
    mysqli_query($mysqli, "INSERT INTO 'wordpress'.'session_log' ('id_sesion', 'id_usuario', 'direccion_ip', 'version_cliente', 'expirar') VALUES ('', '".$id_usuario."', '".$direccion_ip."', '".$version_cliente."', '".$expirar."');"); 
    //la variable de sesion solo almacena la id de usuario en uso, para asociarlo a la sesion de la base de datos
    session_start();
    $_SESSION['user_id'] = $id_usuario;
    }
}
else{    
                 echo '<div id="wrong" class="wrong"> "Nombre de usuario o contraseña incorrectos! <br>';
                 echo "Haz click<a href='FORMULARIO DE REGISTRO!!!'>aqui</a> para registrarte...</div>";  
            }

Ese sería el administrador de inicio de sesión, ahora, la clase check_login:

<?php
// TODAS LAS PAGINAS DEBEN INCLUIR ESTE ARCHIVO!
//abro conexion base de datos
$mysqli = new mysqli("localhost", "root", "unir_2014", "wordpress");
if ($mysqli->connect_errno) {
    printf("La conexion ha fallado! El servidor responde: %s\n", $mysqli->connect_error);
    exit();
}

//buscamos el id del usuario activo.
//recibimo de $_SESSION (o sea la cookie del cliente) solo el id del usuario. que usuario dice ser
//si la cookie ha sido robada, lo mas probable es que la ip y el user agent hayan cambiado, asi que la session FALLARA
//robar una cookie antigua tampoco ayudara, pues solo duran 15 minutos
session_start();
$id_usuario = $_SESSION['user_id'];

//busco en la tabla SESIONES si existe un numbre de usuario como ese
$query = "SELECT * FROM session_log WHERE id_usuario ='".$id_usuario."'";

//si existe, saco sus datos
if ($result = $mysqli->query($query)) {
    while($row = mysqli_fetch_array($result)) {
        $ip_check = $row['direccion_ip'];
        $expirar = $row['expirar'];
        $cliente_check = $row['version_cliente'];
        $id_sesion = $row['id_sesion'];
    }
}



//comprobamos que el usuario esta logeado, tiene buen user_agent, la misma direccion ip y no se ha pasado de tiempo

    //COMPROBAR SI LA SESION HA EXPIRADO
        $now = time(); 
        if ($now > $expirar) {
            $url = 'NO_SESSION.php';
            echo '<script> window.location = "'.$url.'" </script>';
            echo '<META HTTP-EQUIV=Refresh CONTENT="0; URL='.$url.'">';
        }

    //COMPROBAR QUE VIENE DE LA MISMA IP   
            if (isset($_SERVER)) {
                  if (isset($_SERVER["HTTP_X_FORWARDED_FOR"]) && ip2long($_SERVER["HTTP_X_FORWARDED_FOR"]) !== false) {
                      $ipadres = $_SERVER["HTTP_X_FORWARDED_FOR"];
                  } elseif (isset($_SERVER["HTTP_CLIENT_IP"])  && ip2long($_SERVER["HTTP_CLIENT_IP"]) !== false) {
                      $ipadres = $_SERVER["HTTP_CLIENT_IP"];
                  } else {
                      $ipadres = $_SERVER["REMOTE_ADDR"];
                  }
              } else {
                  if (getenv('HTTP_X_FORWARDED_FOR') && ip2long(getenv('HTTP_X_FORWARDED_FOR')) !== false) {
                      $ipadres = getenv('HTTP_X_FORWARDED_FOR');
                  } elseif (getenv('HTTP_CLIENT_IP') && ip2long(getenv('HTTP_CLIENT_IP')) !== false) {
                      $ipadres = getenv('HTTP_CLIENT_IP');
                  } else {
                      $ipadres = getenv('REMOTE_ADDR');
                  }
              }    


        if ($ip_check !== $ipadres){ 
            $url = 'NO_SESSION.php';
            echo '<script> window.location = "'.$url.'" </script>';
            echo '<META HTTP-EQUIV=Refresh CONTENT="0; URL='.$url.'">';
        }



    //COMPROBAR QUE TIENE EL MISMO USER AGENT   
    $version_cliente = $_SERVER['HTTP_USER_AGENT'];    
        if ($cliente_check != $version_cliente){
            $url = 'NO_SESSION.php';
            echo '<script> window.location = "'.$url.'" </script>';
            echo '<META HTTP-EQUIV=Refresh CONTENT="0; URL='.$url.'">';
        }




    //si ninguno de estos controles falla, llego hasta aqui
    //significa que el usuario ha visitado una pagina nueva y sigue con la misma session, asi que debo
    //actualizar el campo "expirar" para que la session dure mas

    $new_expirar =  time() + (15 * 60);
    mysqli_query($mysqli, "UPDATE 'wordpress'.'session_log' SET 'expirar' = '".$new_expirar."' WHERE 'session_log'.'id_sesion' =$id_sesion;");
    
pregunta user3453619 14.05.2014 - 13:24
fuente

3 respuestas

1

Sí, es seguro, pero tiene la posibilidad de que los usuarios no puedan cambiar sus ips. Por ejemplo, si llego a casa con mi teléfono Android y cambio de gprs a wifi, su sitio verá un cambio de IP, aunque ni siquiera necesito que mi navegador se reinicie.

    
respondido por el peterh 14.05.2014 - 13:42
fuente
1
  

La idea es que sería difícil para un atacante robar la cookie.   Y la dirección IP Y el agente de usuario Y para mantener la sesión   refrescante,

Solo quería señalar que muchos ataques tienen lugar localmente, lo que hace que el atacante probablemente comparta la misma dirección IP. Si puede obtener la clave de sesión, también puede obtener el agente de usuario del navegador.

    
respondido por el David Houde 14.05.2014 - 15:50
fuente
1

Para decidir si se trata de un enfoque válido o no, debe considerar el caso de uso de la aplicación y contra qué ataque está tratando de proteger a sus usuarios.

En este caso, el escenario de ataque del que intenta proteger a su usuario es que alguien robe la cookie de sesión y luego la reutilice desde una máquina diferente. La consecuencia de la defensa que está proponiendo es que es necesario que los usuarios vuelvan a iniciar sesión cada vez que cambian las direcciones IP.

Juzgar si las ventajas de su solución valen o no los inconvenientes que crea depende mucho del contexto. Por ejemplo, si los datos de su aplicación son de alto valor y se suelen utilizar durante un período limitado de tiempo entre los que desea que sus usuarios se autentiquen cada vez (por ejemplo, una interfaz de banca web), el compromiso parece perfectamente aceptable.

Si, por otro lado, está accediendo a datos de bajo valor y desea minimizar el impacto en sus usuarios (por ejemplo, un carrito web de sitios de compras), entonces es mejor no limitar la sesión a misma dirección IP.

    
respondido por el Stephane 14.05.2014 - 16:07
fuente

Lea otras preguntas en las etiquetas