Etiqueta: Sesiones

  • ¿Qué puede guardarse en las sesiones PHP?

    ¿Qué puede guardarse en las sesiones PHP?

    Es un hecho: las sesiones de PHP son una fuente de confusión y frustración para muchos desarrolladores.

    Desde mi punto de vista, el problema es que hay muchos puntos de fallo posible.

    En este artículo quiero detenerme sobre un punto que, si bien parece simple, tiene sus grises.

    Todo el mundo pre-supone que las sesiones son una suerte de baúl mágico donde puede guardarse cualquier cosa y, cual juego de rol, acompaña al héroe a donde vaya.

    La realidad no es tan así.

    Hay algunos objetos que no pueden ser almacenados en las sesiones PHP.

    Un ejemplo que veo con frecuencia es código similar a este:

    include("Conexion.php");
    $Conexion = Conectar(); --> Donde conectar es una funcion que conecta a mysql
    $_SESSION['Conex'] = $Conexion;

    Y luego, al querer levantar el dato en otro archivo:

    $Conexion = $_SESSION['Conex'];
    $Conexion->query('SELECT * FROM user;'); 

    Te encontrás con que la conexión no está en la sesión… ¿qué sucedió?

    El problema es que los datos que se guardan en la sesión tienen que ser serializados primero y no todos los objetos son serializables.

    De hecho, los objetos de tipo Recurso (Tales como las conexiones a MySQL) no lo son.

    Si lo que buscas es evitar abrir y cerrar conexiones a la base de datos en cada script lo que debes hacer es utilizar conexiones persistentes

  • Por qué se pierden las variables de sesión PHP

    Por qué se pierden las variables de sesión PHP

    Pocas cosas hay más frustrantes que ir a buscar algo donde sabés que lo dejaste y no encontrar nada.

    ¿Cómo es posible?

    Pusiste el session_start() al comienzo como Dios manda.

    El código es claro:

    $_SESSION['user'] = $user;

    ¿Qué puede ser más simple?

    Cuando hacés un echo $_SESSION['user'] en la misma página todo sale perfecto pero apenas clickeás en un link… nada por aquí, nada por allá.

    Y lo peor de todo es que el código funciona perfectamente en tu XAMPP pero en tu hosting no.

    ¿Cómo puede ser?

    Funcionó perfectamente bien durante meses y ahora, nadie sabe por qué, dejó de funcionar.

    Obviamente, dejar el problema sin resolver no es opción… ¿qué clase de sitio no recuerda al usuario que está logeado?

    No te preocupes, el manejo de sesiones en PHP es uno de los temas que más confusión trae a los que están recién empezando.

    Te sugiero comenzar por entender bien cómo funcionan las sesiones de PHP.

    En este artículo voy a explorar las causas más frecuentes que hacen que las variables de sesión se pierdan y qué podés hacer para solucionarlas.

    Te dejo las preguntas que deberías hacerte:

    ¿Todas las páginas tienen el session_start?

    En realidad, no es necesario que todas las páginas lo tengan… de hecho, hasta puede ser contraproducente.

    Lo que es seguro es que todas las páginas donde necesites guardar o leer información de la sesión deben invocar esta función.

    ¿La llamada a session_start está antes de enviar contenido al cliente?

    Esta pregunta puede parecer poco sensata. Después de todo, si la llamada a session_start estuviese después de enviar código al cliente verías un error como:

    PHP Warning: session_start(): Cannot start session when headers already sent

    ¿no?

    Pues… no necesariamente.

    El error se producirá, eso es seguro, pero que lo veas o no en pantalla depende de lo que figure en tu archivo php.ini (Específicamente en la entrada display_errors).

    ¿El valor de session.use_cookies es 1?

    Esta configuración determina que el mecanismo de propagación del ID de sesión sea el uso de una cookie.

    Muchas veces ocurre que el valor que tenés en tu entorno local no se condice con el del hosting.

    ¿El navegador está generando la cookie de sesión?

    Esto es fácil de verificar: usualmente esta cookie se llama PHPSESSID (aunque este nombre puede modificarse, también a través del archivo php.ini o la función ini_set).

    Si esto no sucede habría que probar si otras cookies se están generando (Lo más probable es que no).

    Esto puede deberse a la configuración del navegador (Que no acepta cookies).

    La verdad es que en este caso no hay mucho que puedas hacer… más allá de pedir por favor a los visitantes del sitio que habiliten las cookies.

    La buena noticia es que la gran mayoría sí lo harán 🙂

    ¿Cuál es el valor de session.cookie_lifetime?

    La configuración session.cookie_lifetime determina cuánto tiempo debe el navegador mantener la cookie de sesión.

    Si este tiempo es pequeño la cookie no vivirá lo suficiente como para llegar a la siguiente página.

    ¿La interacción desde el frontend es muy larga?

    Este es un problema que se da mucho en las SPA (Aplicación de una única página) donde casi toda la interacción se da a través de JavaScript.

    Si no se realiza ningún pedido al servidor en mucho tiempo se corre el riesgo de que la sesión se considere inactiva y se cierre automáticamente.

    En este artículo podés ver un ejemplo de esto (y cómo solucionarlo).

    ¿Qué valor tiene session.save_path?

    Esta configuración determina dónde se almacenan los archivos de sesión (asumiendo, claro, que el mecanismo de almacenamiento elegido sea en archivos).

    Si este valor es incorrecto no habrá dónde guardar la información.

    Si el valor corresponde a un directorio existente en tu servidor la siguiente pregunta es ¿los archivos de sesión están ahí?

    Si no están es probable que haya un problema de permisos: debes validar que el usuario con el que ejecuta tu servidor web sea capaz de escribir allí.

    Conclusión

    Si estás teniendo problemas para recuperar las variables de sesión es muy probable que se deba a fallas en la configuración de tu entorno, no desesperes: todo tiene solución 🙂

    Recorriendo esta lista de preguntas podrás identificar la causa específica de tu problema y resolverlo.

    ¡Vamos que los usuarios esperan!

  • Cómo funcionan las sesiones en PHP

    Cómo funcionan las sesiones en PHP

    Una fuente de mucha frustración y confusión para quienes arrancan con PHP es el manejo de sesiones.

    Hay muchas partes móviles y, a veces, tener todo esto en la cabeza marea…

    En este artículo intentaré hacer un repaso por cuáles son esas partes y cómo interactúan entre sí de modo que no te queden dudas respecto de cómo usar esta poderosa herramienta.

    Para qué sirven las sesiones

    Por supuesto que no puedo avanzar sin antes hablar de lo más importante: ¿para qué sirven las sesiones? O, dicho de otro modo: ¿por qué querrías complicarte la vida entendiendo todo esto?

    En pocas palabras: las sesiones sirven para compartir información no entre una página y otra (Un formulario HTML y el php que lo procesa por ejemplo), si no entre todas las páginas por las que el visitante pase.

    Un ejemplo simple de esto es cuando visitas un sitio y ves tu nombre de usuario en todas las páginas:

    Aunque sólo te identificaste una vez.

    Dónde se almacena la información de las sesiones

    Una pregunta sumamente importante es dónde se almacena esta información.

    Para empezar es importante comprender que la información de la sesión está almacenada del lado del servidor.

    Usualmente se guarda físicamente en archivos en el disco de la computadora que actúa como WebServer, aunque esta no es la única opción.

    Si querés saber exactamente dónde está guardada la información de las sesiones tenés que consultar dos variables de configuración de php:

    En cualquiera de los casos, la información almacenada es el resultado de la serialización de la información.

    Cómo se guardan datos en la sesión

    Para guardar datos en la sesión de un usuario existe un arreglo llamado $_SESSION.

    Este arreglo está presente siempre (es lo que se conoce como una variable super global).

    Entonces, guardar un elemento en la sesión del usuario es tan simple como hacer:

    <?php
    
    $_SESSION['var'] = 'value';

    Cómo se recuperan datos de la sesión

    Del mismo modo, recuperar datos de la sesión se reduce a leer el contenido del arreglo:

    <?php
    
    $var = $_SESSION['var'];

    Cómo se eliminan datos de la sesión

    Si lo que necesitas es quitar algún dato de la sesión basta con utilizar la función unset():

    <?php
    
    unset($_SESSION['var']);

    Cómo se vincula una sesión en el servidor con un cliente

    Esperablemente tu aplicación web tendrá muchos usuarios conectados a la vez.

    Seguramente no estés muy interesado en que el usuario A vea (o peor… ¡modifique!) los datos de la sesión del usuario B.

    Para evitar que esto suceda se necesita que cada sesión pueda vincularse a un (y sólo un) cliente.

    Efectivamente, cada sesión tiene un identificador único: el ID de sesión.

    En el caso del almacenamiento en archivos, el nombre de cada uno de ellos corresponde al ID de la sesión cuyo contenido está guardado dentro.

    Es decir, si tenemos un ID de sesión toqn1cl46210ear4e5t7seg6g7 encontraremos un archivo con ese mismo nombre en el directorio donde se almacenan las sesiones en el servidor.

    Si querés saber cuál es tu ID de sesión podés usar la función session_id()

    Este ID se genera cuando se crea la sesión, mediante el uso de la función session_start()

    Hasta acá no creo que haya mucho misterio, ¿cierto?

    Bueno, pues aquí es donde tenemos que ir un poco más atrás para comprender realmente qué pasa.

    Las aplicaciones web están basadas en el protocolo HTTP.

    Este protocolo estuvo pensado y diseñado en función de las necesidades de la web estática (Es decir, una web en la cual a todos los visitantes se les mostraba el mismo contenido).

    En un contexto donde da lo mismo si el que pidió la página B antes había pedido la página A no tiene sentido gastar recursos en implementar sesiones…

    Claro que, hoy en día las cosas son MUY diferentes… desafortunadamente, las aplicaciones web siguen estando basadas en HTTP, con lo cual, para mantener la coherencia entre diferentes peticiones sucesivas es necesario recurrir a algunos trucos.

    Básicamente, se necesita que el cliente informe al servidor cuál es su ID de sesión en cada petición.

    Esto puede realizarse de dos formas:

    1. A través de la URL (agregando un parámetro ?SID=$sid)
    2. Mediante una cookie

    El primer método no es muy aconsejable por un tema de seguridad, el segundo, si bien no es infalible, es mucho mejor.

    En caso de optar por la segunda opción, necesitarás que esa cookie se genere en el cliente luego de iniciar la sesión.

    Podrías usar setcookie, pero sería un poco redundante: session_start() ya lo hace 😉

    Claro que, dado que todo este proceso se realiza mediante el intercambio de encabezados HTTP, debes tener cuidado de llamar a session_start() antes de enviar contenido al cliente.

    Qué hace exactamente la función session_start()

    session_start() es una función algo rara.

    Digo rara porque realiza varias tareas según el caso, algo que en general no es muy aconsejable.

    Si la petición NO viene con una cookie (o un parámetro SID) O el valor no corresponde con una sesión activa en el servidor:

    1. Se genera un nuevo ID de sesión
    2. Se inicializa el espacio de almacenamiento en el servidor
    3. Se envía el encabezado correspondiente a la creación de la cookie de sesión (Asumiendo por supuesto que este el método de propagación de ID seleccionado)

    Si la petición SI viene con una cookie (o un parámetro SID) Y el valor corresponde con una sesión activa en el servidor:

    1. Se lee el contenido del archivo de sesión correspondiente
    2. Se inicializa el arreglo $_SESSION con los valores contenidos en dicho archivo

    Cómo se destruye una sesión

    Por último, en el caso de que quieras destruir por completo el contenido de una sesión (Por ejemplo, el caso en que un visitante esté abandonando tu aplicación), la función session_destroy() se encargará de ello.

    Un detalle importante a tener en cuenta es que session_destroy() sólo actuará del lado del servidor, así que, para mayor seguridad es conveniente usar setcookie() para eliminar la cookie del lado del cliente

  • 5 formas de reforzar la seguridad de tus sesiones en PHP

    5 formas de reforzar la seguridad de tus sesiones en PHP

    En un post anterior había mencionado cuáles son los riesgos a los que están sujetas las sesiones PHP.

    En este artículo voy a darte algunos tips para mejorar la seguridad de tus sesiones y dormir más tranquilo 🙂

    1. Usa siempre HTTPS

    La mejor forma de reforzar la seguridad de tus aplicaciones (No sólo de las sesiones) es utilizar tráfico cifrado, de esta forma, aún si alguien logra capturar el tráfico le será virtualmente imposible leer el contenido.

    Puedes conseguir certificados gratuitos usando, por ejemplo, LetsEncrypt

    2. Cambia el nombre de tu cookie de sesión

    El nombre por defecto de la cookie de sesión es PHPSESSID pero puedes cambiarlo usando session_name() o desde la configuración de php (La variable session.name).

    Al cambiar este dato harás más dificultoso para un atacante saber cuál es la cookie que contiene el id de sesión.

    3. Habilita el modo de sesión estricto

    En este modo (deshabilitado por defecto) el servidor sólo reconocerá como válidas aquellas sesiones cuyo identificador haya sido generado por él.

    Este cambio se realiza a través de la entrada session.use_strict_mode del archivo php.ini.

    4. Fuerza el uso de cookies de sesión

    Con este cambio harás imposible que alguien, sin darse cuenta, comparta un enlace que contiene su id de sesión.

    Para ello debes modificar el valor de session.use-only-cookies

    5. Mantén información adicional dentro de las variables de sesión

    Al momento de inicializar una sesión no guardes sólo el id de usuario si no algún otro dato que permita validar la identidad del visitante, por ejemplo:

    <?php
    
    session_start();
    if (successfulLogin()){
       $_SESSION['uid'] = $userId;
       $_SESSION['userAgent'] = $_SERVER['HTTP_USER_AGENT'];
       $_SESSION['ip'] = $_SERVER['REMOTE_ADDR'];
    }

    Luego, en cada página donde debas validar la identidad del usuario:

    <?php
    
    session_start();
    if (empty($_SESSION['uid']) || isValidUser($_SESSION['uid'])) {
           http_response_code(403);
          
           die;
       }
    
    if ($_SESSION['userAgent'] !== $_SERVER['HTTP_USER_AGENT']) {
        http_response_code(403);
          
        die;
    }
    
    if ($_SESSION['ip'] !== $_SERVER['REMOTE_ADDR']) {
        http_response_code(403);
          
        die;
    }

    De este modo, aún si alguien logra robar la cookie de sesión le será imposible utilizarla

    Espero que estos tips te hayan servido, si te quedó alguna pregunta no dudes en dejarla en los comentarios!

  • ¿Qué tan seguras son las sesiones de PHP?

    ¿Qué tan seguras son las sesiones de PHP?

    Seguramente escuchaste alguna versión de estas preguntas:

    ¿Es posible que alguien modifique sus cookies, les otorgue diferentes privilegios o inicie sesión como un usuario diferente?

    ¿Puede alguien robar las variables mientras están guardadas en el lado del servidor?

    ¿Que tan posible es que alguien te copie una session para usarla en su navegador?

    Una de nuestras principales preocupaciones como desarrolladores de software es la posibilidad de que algún hacker pueda robar información que los usuarios han confiado a nuestras aplicaciones.

    Si eso llegara a suceder nuestros clientes podrían verse en serias dificultades (y por lo tanto, nosotros también).

    Existen muchos modos en que un atacante puede colarse en nuestros sistemas y, lamentablemente, las sesiones no están exentas de riesgos.

    Para qué sirven las sesiones en PHP

    Las sesiones de PHP son un modo bastante cómodo de compartir información entre peticiones.

    Un ejemplo clásico es el login: independientemente de cuál sea el método de autenticación usado, una vez validada la identidad del visitante, es necesario indicar a las siguientes páginas que este usuario está autorizado a verlas.

    Para ello un modo muy común es utilizar el arreglo $_SESSION con algún código similar a:

     <?php
    
    // Obtener el $userId de la base de datos
    session_start();
    $_SESSION['userId'] = $userId;

    Y, en las siguientes páginas tener un chequeo similar a:

     <?php
    
    session_start();
    if (empty($_SESSION['userId'])) {
      header('Location: login.html');
    
      die;
    }

    Usar las sesiones no es realmente complejo pero si para responder qué tan seguras son las sesiones primero debemos comprender cómo funcionan internamente.

    Cómo funcionan las sesiones en PHP

    Del lado de nuestros scripts tenemos ese arreglo superglobal ($_SESSION) que, en principio, puede guardar cualquier valor que se desee y estará ahí cuando lo necesitemos.

    Existen varias formas de almacenar esta información. La más común es la utilización de archivos temporales en algún lugar del disco del servidor, aunque existen varias alternativas (Puedes consultar más sobre esto en el manual de PHP).

    Claro que un mismo servidor web puede estar atendiendo a muchos visitantes a la vez (al menos eso es lo que esperamos que suceda :)), de modo que necesitamos alguna forma de asociar ese archivo en el disco del servidor al visitante que realizó la solicitud:

    Múltiples clientes son atendidos en forma simultánea por un servidor web

    El protocolo HTTP (En el que se basa la web) pertenece al conjunto conocido como sin-estado (stateless).

    Esto significa que cada petición es independiente de las otras… ¡lo cual es precisamente lo contrario de lo que necesitamos!

    Debido a esta característica de HTTP, cada aplicación que quiera vincular una petición con otras deberá hacerlo por sus propios medios.

    En el caso de PHP la forma de asociar a un visitante con su sesión es agregar un parámetro a cada petición: el ID de sesión.

    Hoy en día lo más usual es guardar este id en una cookie especial (La cookie de sesión) y de ese modo asegurarse de que este valor:

    • Acompañe al usuario en su recorrido por nuestro sitio
    • Desaparezca en forma automática cuando ya no se lo necesita

    Qué riesgos presentan las sesiones de PHP

    Como vemos, toda la información de las sesiones está almacenada del lado del servidor, con lo cual, el riesgo de que alguien acceda a dicha información se reduce a dos posibilidades:

    1. Que una persona no autorizada pueda acceder directamente a los archivos del servidor
    2. Que un atacante suplante la identidad de un usuario que ha iniciado sesión

    Evitar el primer riesgo no depende de nuestro código si no de la configuración del servidor.

    Una forma de atacar una aplicación web a través del mecanismo de sesiones consiste en el secuestro de la sesión (session hi-jacking).

    De lo que se trata es de copiar el contenido de una cookie de sesión y crear con él otra cookie en otra computadora.

    Si no se han tomado medidas precautorias, el servidor no será capaz de distinguir a un visitante del otro.

    Obtener una cookie de sesión no es algo sencillo pero tampoco imposible.

    Basta con:

    • Tener acceso a la computadora de la víctima
    • Interceptar el tráfico de red (Suponiendo que no esté cifrado)
    • Ejecutar un ataque de tipo XSS

    En definitiva: las seguridad de las sesiones depende fuertemente de qué tan seguro sea el mecanismo de validación de identidad de un visitante.

  • Cómo armar un carrito de compras con PHP

    Cómo armar un carrito de compras con PHP

    Tema popular si los hay, ¿cierto? 🙂

    Muchos clientes se acercan a cualquier desarrollador con la idea de agregar a su sitio un «carrito de compras» pero, cuando indagamos un poco más vemos que el tema no es tan simple.

    Por ejemplo: ¿sirve de algo el carrito de compras sin la posisbilidad de realizar el pago al final?

    Pero bueno, para no hacer un post enorme, comencemos por la parte del carrito propiamente dicho y dejemos el tema de los pagos para otro.

    Qué puede hacerse con un carrito de compras

    El carrito de compras es un espacio donde un visitante puede llevar registro de los productos que desea comprar.

    Desde el punto de vista técnico/funcional, debe ser posible:

    • Ingresar productos
    • Quitar productos
    • Ver los productos existentes
    • Confirmar la compra

    Para poder ingresar productos al carrito será necesario visualizar cuáles son los productos disponibles en la tienda.

    Qué se necesita para armar un carrito de compras

    La implementación de todo el mecanismo de administración del carrito requerirá de:

    • Algún tipo de base de datos que contenga el catálogo de productos
    • Una aplicación que permita al visitante:
      • Ver ese catálogo
      • Ver los detalles de cada producto
      • Agregar productos a su carrito
      • Ver los contenidos de su carrito
      • Eliminar productos del carrito
      • Confirmar su compra
    • Una pasarela de pagos para completar la transacción

    Por simplicidad imaginemos que tenemos una primera página tipo catalog.php:

    <?php
    
    $dsn = require_once 'db.php';
    
    $pdo = new PDO($dsn);
    ?>
    <table>
      <thead>
         <tr>
            <th>SKU</th>
            <th>Nombre</th>
            <th>Precio</th>
            <th> </th>    
        </tr>
      </thead>
      <tbody>
         <?php
    $sql = "SELECT * FROM products";
    
    foreach ($pdo->query($sql, PDO::FETCH_ASSOC) as $product ) {
    ?>
         <tr>
              <td><a href="product_details?product_id=<?php echo $product['id'];?>"><?php echo $product['sku']; ?></a></td>
              <td><?php echo $product['name']; ?></td>
              <td><?php echo $product['price']; ?></td>
              <td><button onclick="window.location.href='add_to_cart.php?product_id=<?php echo $product['id']; ?>'">Agregar al carrito</button></td>
         </tr>
    <?php
    }?>
      </tbody>
    </table>

    Estoy dejando de lado unos cuantos detalles para no complicar el ejemplo: como ser categorías de productos, cantidad a agregar en cada interacción, etc…

    Continuemos por el archivo add_to_cart.php.

    Aquí es donde reside la clave de la cuestión: el carrito debe acompañar al visitante durante toda su estadía en el sitio.

    Precisamente, la idea del carrito es permitir que la compra se vaya armando conforme el usuario va descubriendo los productos.

    De modo que necesitaremos un medio de almacenamiento que persista durante la navegación.

    A estos efectos php pone a nuestra disposición el arreglo $_SESSION.

    Es ahí donde vamos a almacenar los productos seleccionados por el visitante:

    <?php
    $product_id = $_GET['product_id'];
    session_start();
    
    if (!array_key_exists('products', $_SESSION) {
         $_SESSION['products'] = [];
    }
    
    $_SESSION['products'][$product_id] = array_key_exists($product_id, $_SESSION['products']) ? $_SESSION['products'][$product_id] + 1 : 1;
    
    header('Location: catalog.php');

    De este modo guardamos los ids de los productos seleccionados y su cantidad.

    No es necesario guardar más que los ids de producto ya que con eso será suficiente para recuperar toda la información a la hora de mostrar el carrito o confirmar la compra.

    Pensemos en un archivo tipo show_cart.php:

    <?php
    session_start();
    
    $ids = implode( ', ', array_keys($_SESSION['products']));
    $sql = "SELECT * FROM products WHERE id IN ($ids);"
    ?>
    <table>
      <thead>
         <tr>
            <th>SKU</th>
            <th>Nombre</th>
            <th>Precio</th>
            <th>Cantidad</th>
            <th>Subtotal</th>
            <th> </th>    
        </tr>
      </thead>
      <tbody>
    <?php
    $total = 0;
    foreach ($pdo->query($sql, PDO::FETCH_ASSOC) as $product ) {
          $quantity = $_SESSION['products'][$product['id']];
          $subtotal = $quantity * $product['price'];
          $total += $subtotal;
    ?>
         <tr>
              <td><a href="product_details?product_id=<?php echo $product['id'];?>"><?php echo $product['sku']; ?></a></td>
              <td><?php echo $product['name']; ?></td>
              <td><?php echo $product['price']; ?></td>
              <td><?php echo $quantity; ?></td>
              <td><?php echo $subtotal; ?></td>
              <td><button onclick="window.location.href='remove_from_cart.php?product_id=<?php echo $product['id']; ?>'">Quitar del carrito</button></td>
         </tr>
    <?php
    }?>
      </tbody>
    </table>
    <p>Total: <?php echo $total;?></p>

    Queda por completar los archivos de ver el detalle del producto y remover del carrito pero creo que con lo que viste hasta aquí no deberías tener problemas para armarlos.

    Un detalle que haría más amena la experiencia para el usuario sería utilizar AJAX para meter y sacar productos del carrito.

    Y, por supuesto, deberás tener un enlace para realizar el pago.

  • Cómo definir la configuración de la sesión en Symfony

    Cómo definir la configuración de la sesión en Symfony

     

    Ante todo, una aclaración:

    PHP maneja las sesiones a través de cookies (Antiguamente también se podía propagar el ID de sesión vía URL, aunque es una práctica muy poco segura y, sinceramente, hace mucho que no lo veo).

    Bien, ahora… ¿qué cosas podrías querer cambiar de la configuración de la sesión? Varias.

    1. El nombre de la cookie
    2. El tiempo de duración
    3. El lugar donde se almacena la información del lado del servidor

    Sobre la segunda y la tercera, acá tenés un ejemplo de por qué querrías hacerlo 🙂

    Respecto de la primera, más que nada se trata de un tema de seguridad. Fijate esta captura de pantalla de la consola del navegador:

    El nombre PHPSESSID es el nombre por defecto que se le asigna a la cookie de sesión de una aplicación hecha en PHP, eso significa que, si te encontrás con una cookie con este nombre es altamente probable (Por no decir seguro) que del otro lado se encuentre una aplicación desarrollada en PHP.

    Ese tipo de información es super útil para un atacante, ya que al conocer qué software está corriendo el servidor se le facilita enormemente la tarea de buscar una forma de explotarlo…

    Bien, ahora que te convencí de que es una buena idea cambiar el nombre de la cookie, te voy a mostrar cómo hacerlo en Symfony:

    Es muy simple, se trata de agregar un par de líneas al archivo config.yml:

    framework:
        session:
            # http://symfony.com/doc/current/reference/configuration/framework.html#handler-id
            handler_id:  session.handler.native_file
            save_path:   "%kernel.root_dir%/../var/sessions/%kernel.environment%"
            cookie_lifetime: 28800
            name: MIAPPSID

    Se puede configurar todos los parámetros de la sesión mediante este mecanismo y después, por ejemplo, se puede modificar algunos valores para el entorno de desarrollo definiendo un archivo config_dev.yml con algo como:

    imports:
        - { resource: config.yml }
    
    framework:
        session:
            save_path:   "/var/lib/php/sessions"

    Listo. Ahora tu aplicación es un poco menos vulnerable que antes :).

    P.D.: Si querés incorporar un framework maduro como Symfony a tu herramental, el curso Desarrollo de Aplicaciones Web Profesionales con PHP te puede interesar.

  • Cómo evitar la expiración de las sesiones en PHP

    Cómo evitar la expiración de las sesiones en PHP

    En un proyecto que hice para un cliente me sucedió algo que no había previsto: un formulario dinámico resultó muy largo para la persona que tenía que realizar la carga y, cuando terminó el sistema la deslogueó automáticamente y perdió su trabajo 🙁

    Analizando un poco el problema me di cuenta de que la sesión había expirado a pesar de que el usuario estaba interactuando con el sistema… sólo que no se estaba produciendo ninguna comunicación cliente-servidor, ya que toda la acción estaba pasando del lado cliente.

    A juzgar por algunos comentarios que he leído por ahí, como:

    Tengo un archivo sesion.php que se incluye en cada pagina del proyecto, para validar tanto si la sesión esta activa, como si la sesión ha expirado, estoy haciendo pruebas con 30 segundos para no tardar tanto.

    El problema surge que el código se ejecuta cada vez que visito una pagina, por lo tanto si estoy navegando sobre la misma pagina, como por ejemplo haciendo click o registrando datos, la sesión aún así expira.

    O también:

    Tengo mi web en un servidor de GoDaddy y manejo sesiones pero estas caducan solas por inactividad..

    Parece que no estoy solo en este sufrimiento 🙂

    La solución que encontré fue diseñar un mecanismo de tipo keepAlive de modo de avisar al servidor que todavía había actividad del lado del cliente (¡y pedir por favor que no me dejen afuera!).

    Lo primero que hice entonces fue agregar este pequeño código javascript:

    <script type="text/javascript">
        var keep_alive = false;
    
        $(document).bind("click keydown keyup mousemove", function() {
            keep_alive = true;
        });
    
        setInterval(function() {
            if ( keep_alive ) {
                pingServer();
                keep_alive = false;
            }
        }, 1200000 );
    
        function pingServer() {
            $.ajax('/keepAlive');
        }
    </script>

    La idea es llevar un control sobre cualquier evento que se suceda del lado cliente (Click, presionar una tecla o mover el mouse) y, cada tanto (20 minutos en mi caso), si hubo actividad, avisarle al server para prolongar la vida de la sesión.

    Cómo extender dinámicamente la vida de una sesión

    Del lado del servidor no hay mucho que hacer en realidad, basta con tener algún script que responda a la URI /keepAlive (Preferentemente con un 200 OK) y listo.

    Hay algunas otras cosas a tener en cuenta si, como en mi caso, la aplicación está corriendo en un ambiente de hosting compartido (Algo que trato de evitar por todos los medios, pero bueno… en este caso no pude):

    1. Dónde se almacena la información de las sesiones propias de la aplicación
    2. Cuál es el tiempo de vida de la sesión
    3. Cada cuánto tiempo se libera la basura de las sesiones

    La respuesta a estas tres preguntas (y otras más) está en el viejo y querido php.ini. Específicamente en las claves:

    Como cualquier otro setting de php, puede modificarse desde el propio código de nuestra aplicación (¡Pero hay que acordarse de hacerlo!).

    Un detalle interesante es esta notita sobre session.gc_maxlifetime:

    Nota: Si diferentes scripts tienen diferentes valores de session.gc_maxlifetime pero comparten la misma ubicación para almacenar la información de sesión, la información del script con el mínimo valor será limpiada. En este caso use esta directiva junto con session.save_path.

    No puedo estar seguro al 100%, pero mi apuesta más fuerte es que este fue el problema: mi aplicación estaba guardando sus archivos de sesión en el mismo lugar que otra y, cuando pasó el garbage collector… ¡adiós!

    ¿Tuviste alguna vez problemas de este tipo con tus aplicaciones web?