Categoría: Seguridad

  • 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.

  • Validaciones… ¿lado cliente o lado servidor?

    Validaciones… ¿lado cliente o lado servidor?

    Nadie duda de que los campos de los formularios que envían los usuarios deben ser validados.

    Seguro eso es lo que te dijeron cuando empezaste a estudiar, lo que no es muy claro cuando se trata de programación web es cuál es la manera correcta de hacerlo.

    En otras palabras, ¿cuáles son las mejores prácticas cuando se trata de validar?

    Más allá de las herramientas que vayas a usar para realizar la validación, lo primero que debes responder es dónde debe realizarse esa validación, ¿en el cliente o en el servidor?

    La respuesta corta primero: Idealmente las dos, y si sólo puedo elegir una, definitivamente del lado servidor.

    ¿Querés más detalles? Te invito a acompañarme a la respuesta larga 🙂

    Respuesta larga:

    ¿Por qué es más importante la validación del lado servidor que del lado cliente?

    Sencillamente porque tenés mucho más control sobre lo que sucede.

    En una aplicación de escritorio (o una que no sea de tipo cliente-servidor) no existe este problema: la aplicación es una sola con lo cual, lo que el front-end captura puede ser considerado confiable y volver a realizar la validación en el backend resultaría redundante.

    Cuando hablamos de una aplicación web, en realidad estamos hablando de dos aplicaciones independientes. Compartir en X

    Pensá un momento en cómo es el modelo de ejecución de una aplicación web:

    1. El cliente realiza un pedido
    2. El servidor responde con HTML, JavaScript, CSS, etc…
    3. El cliente dibuja la página
    4. El usuario completa los datos
    5. El cliente realiza un nuevo pedido enviando los datos ingresados
    6. El servidor los procesa y eventualmente almacena
    7. Vuelta al paso 2

    Desde el punto de vista del servidor, el pedido que se le realiza puede haber sido generado usando el HTML que él mismo ha enviado o no… imposible saberlo.

    De modo que, en definitiva, los datos recibidos no pueden ser considerados confiables.

    Podés ver cómo «fabricar» un pedido cualquiera usando una herramienta como cURL.

    Tomemos un sitio cualquiera como http://www.recruitersonline.com/members/ron4_add.php:

    Si vemos el código fuente:

    Podemos notar rápidamente que los datos que se introduzcan en este formulario serán enviados a ron4_add_thanks.php.

    Valiéndonos de cURL podemos armar un pedido como:

    Esto haría que el servidor reciba XXXX como valor del campo adm_first_name.

    Suponiendo que tal valor no sea aceptable y que la validación sólo se realizara a través de JavaScript… habríamos logrado saltearnos esta validación simplemente usando un cliente diferente.

    De hecho, en este tipo de problemas se basan los ataques tales como sql injection.

    Pero entonces…

    ¿Vale la pena hacer validaciones del lado cliente?

    ¡Claro que SI!.

    Las validaciones del lado del cliente son un favor que le hacemos a los usuarios bien intencionados que simplemente han cometido un error al ingresar información de buena fé.

    El favor consiste en ahorrarles el round-trip al servidor con información que sabemos de antemano que será rechazada.

    Es cierto que hoy en día el tiempo de ida y vuelta se ha reducido en forma significativa, sin embargo, aún hay escenarios en los que puede hacer una diferencia (Por ejemplo en el caso de aplicaciones móviles donde la red es inestable o peor, se consumen datos del plan).

    La validación del lado servidor es una necesidad mientras que la validación del lado cliente es una comodidad. Compartir en X
  • Algunas consideraciones de seguridad cuando se suben archivos vía PHP

    Algunas consideraciones de seguridad cuando se suben archivos vía PHP

    Php permite subir archivos vía HTTP de un modo bastante simple (Si tenés dudas consultá acá).

    Un uso bastante común de esta funcionalidad es la de permitir al visitante ingresar imágenes, por ejemplo: su foto de perfil.

    Existe una serie de consideraciones respecto de la seguridad a tener en cuenta cuando se realiza una tarea de este tipo.

    Con estas medidas estamos intentando evitar que un atacante engañe a nuestro sistema subiendo código malicioso que podría, por ejemplo, darle acceso a información privilegiada.

    Validar que el archivo recibido sea del tipo esperado

    Lo primero de lo que querremos estar seguros es de que el archivo que acabamos de recibir sea efectivamente una imagen (GIF, JPG, etc…). La forma inocente de hacer esta verificación es a través del nombre del archivo (si las últimas tres letras son…).

    La forma correcta de hacer esta verificación es a través del mime-type (Ver acá para más información).

    No almacenarlos en un directorio accesible públicamente

    En general, es conveniente que los archivos recibidos desde terceras partes (especialmente cuando se trata de visitantes), sean almacenados fuera del directorio raíz de nuestro proyecto.

    Desde un script de nuestro proyecto siempre se puede abrir un archivo con algo como:

    fopen(__DIR__.'/../uploads/foto.jpg');

    Contar con un método propio para ver su contenido

    Por último, es conveniente contar con algún método (puede ser un script especialmente diseñado para este efecto) que reciba como parámetro el nombre del archivo que se está solicitando y devuelva su contenido.

    Por ejemplo:

    showFile.php:
    
    <?php
    
    echo file_get_scontents($_GET['f']);

    De este modo, si alguien lograra de algún modo subir código malicioso, al intentar ejecutarlo se encontraría con que en su navegador se vería su propio código (sin haber sido ejecutado nada).