Protección de Interfaces Web: LoginSkel (Parte II)

Después de todo lo analizado en la primera parte de este artículo y retomando el concepto del título, «Protección de Interfaces Web«, nuestro objetivo era disponer de un sistema seguro para proteger un espacio web sin depender de la autenticación HTTP básica y sus limitaciones, ni de un framework específico. Por eso, desarrollamos LoginSkel (disponible en GitHub), una solución sencilla para proteger un espacio web privado en Internet, además de facilitar la implementación de otros mecanismos de autenticación y autorización.

¿Qué es LoginSkel?

LoginSkel es una herramienta diseñada para abordar las vulnerabilidades que se presentan comúnmente en los procesos de autenticación y autorización, proporcionando una solución de fácil implementación que no depende de librerías externas ni de frameworks específicos. Este sistema de autenticación en PHP utiliza MySQL para gestionar la base de datos y emplea PDO para interactuar con ella de manera segura, combinando también JavaScript y HTML para crear la interfaz de usuario.

El diseño de LoginSkel se ha centrado en la simplicidad y flexibilidad. Toda la lógica principal está contenida en una sola clase, lo que creemos facilita su mantenimiento y comprensión. Esto permite a los desarrolladores adaptar y extender el sistema según las necesidades específicas de sus proyectos, sin tener que aprender un nuevo framework o gestionar múltiples dependencias. A través de esta estructura, los usuarios pueden implementar funcionalidades avanzadas como autenticación de dos factores (2FA), gestión de JSON Web Tokens (JWT), y tokens de refresco, todo con un enfoque en la simplicidad y la claridad.

Es importante señalar que, aunque LoginSkel se ha desarrollado siguiendo prácticas recomendadas en cuanto a seguridad y buenas prácticas de programación, aún no se ha sometido a pruebas exhaustivas de explotación o estrés para detectar posibles fallos o vulnerabilidades. Por ello, recomendamos usar este sistema con precaución en entornos de producción. En la tercera parte de esta serie de artículos, abordaremos el proceso de intentar explotar la aplicación para identificar posibles áreas de mejora y fortalecer aún más su seguridad.

De esta forma, LoginSkel se presenta como una solución inicial para cualquier desarrollador que busque implementar un sistema de autenticación seguro y eficiente sin la necesidad de un framework específico. Sin embargo, mantenemos un enfoque abierto y consciente de que siempre hay espacio para la mejora y que la seguridad es un proceso continuo, no un estado final.

¿Qué funcionalidades incorpora?

  1. Sistema de registro de Usuarios
    • Primer Usuario: El primer usuario registrado se establece como «admin», mientras que los usuarios subsiguientes son registrados como «user» sin privilegios.
    • Protección contra Registros fallidos: Implementa medidas para proteger contra múltiples intentos de registro fallidos.
    • Filtrado de Contraseñas: Permite el filtrado de contraseñas contra listas de contraseñas comprometidas y permite agregar listas personalizadas para filtrado.
    • Recomendaciones de Seguridad de Contraseñas: Proporciona sugerencias para crear contraseñas seguras.
    • Opciones Adicionales: Si se habilitan, incluye activación de cuenta mediante código o enlace de token enviado por correo electrónico y configuración de autenticación de dos factores (2FA) mediante QR para Google Authenticator.
  2. Sistema de Login para proteger zonas privadas
    Permite a los usuarios autenticarse para acceder a áreas privadas del sitio web, garantizando la seguridad de los datos y recursos sensibles.
    • Protección ante Ataques de Fuerza Bruta: Implementa medidas para detectar y mitigar intentos de acceso no autorizados mediante ataques de fuerza bruta, limitando la cantidad de intentos de login fallidos permitidos.
    • Autenticación de Dos Factores (2FA): Ofrece la opción de agregar una capa adicional de seguridad mediante la autenticación de dos factores, utilizando códigos de verificación únicos generados por aplicaciones como Google Authenticator.
    • Restablecimiento de Contraseña: Proporciona un mecanismo seguro para que los usuarios puedan recuperar el acceso a su cuenta en caso de olvidar su contraseña, asegurando que solo el titular legítimo pueda restablecerla.
  3. Registro de Sesiones
    Monitorea y controla todas las actividades de sesión de los usuarios para garantizar la seguridad y detectar posibles anomalías.
    • Registro de sesiones de Usuario: Guarda información detallada sobre cada sesión de usuario, incluyendo tiempo de inicio, duración, y dirección IP, lo que permite un seguimiento preciso y auditoría de accesos.
    • Registro de intentos fallidos: Almacena un historial de intentos de login y registro fallidos, ayudando a identificar patrones de actividad sospechosa y potenciales intentos de ataque.
      • Registro de sesiones de usuario
      • Registro de intentos fallidos en registro y login
  4. Cookies Seguras para el uso de JWT y Refresh Tokens
    LoginSkel utiliza cookies seguras para almacenar los JSON Web Tokens (JWT) y Refresh Tokens, garantizando que solo sean accesibles a través de canales HTTPS y minimizando el riesgo de exposición a ataques de intermediario o «hombre en el medio» (MITM) y otros tipos de vulnerabilidades.
  5. Panel de Control de Administrador
    Proporciona una interfaz intuitiva y centralizada para que los administradores configuren y gestionen todas las funcionalidades de seguridad del sistema.
    • Configuraciones diversas: Permite ajustar configuraciones clave del sistema, como opciones de autenticación, políticas de seguridad, gestión de usuarios y configuraciones de API, todo desde un único panel de control fácil de usar.
  6. Sistema de JWT y Refresh Tokens
    Provee una implementación de JSON Web Tokens (JWT) junto con Refresh Tokens para demostrar cómo estas tecnologías pueden usarse para gestionar la autenticación de sesiones de usuario de manera segura y eficiente.
    • Autenticación Basada en Tokens: Utiliza JWT para autenticar a los usuarios de manera segura, permitiendo un intercambio de información confiable entre el cliente y el servidor sin necesidad de mantener la sesión del usuario en el servidor.
    • Refresh Tokens: Implementa Refresh Tokens para extender la validez de las sesiones de usuario sin requerir que vuelvan a iniciar sesión, mejorando la experiencia del usuario al tiempo que se mantiene la seguridad.
    • Demostración en la Pestaña API: Aunque es completamente funcional, esta característica se presenta principalmente como un ejemplo educativo para ilustrar cómo implementar y utilizar JWT y Refresh Tokens en aplicaciones web modernas.

Requerimientos

Para poder instalar y utilizar LoginSkel correctamente, es necesario cumplir con ciertos requisitos previos relacionados con el servidor web, la base de datos y las configuraciones específicas de PHP. A continuación, se detallan los requerimientos que debes tener en cuenta antes de proceder con la instalación:

  • Servidor web: Se recomienda utilizar Apache o Nginx para alojar LoginSkel. Ambos servidores son compatibles con las configuraciones necesarias para el funcionamiento del sistema.
  • ModRewrite: Si estás utilizando Apache, es imprescindible tener habilitado el módulo ModRewrite. Todas las URLs en LoginSkel están reescritas mediante .htaccess para mejorar la seguridad y la apariencia de la web. Sin ModRewrite, el sistema no funcionará correctamente.
  • Base de datos MySQL: Necesitas tener una base de datos MySQL creada en tu servidor, así como las credenciales correspondientes (nombre de usuario y contraseña) que se utilizarán para la conexión desde LoginSkel. Estas credenciales deberán configurarse mediante el instalador de LoginSkel.
  • Directorio para 2FA: Si deseas implementar la autenticación de dos factores (2FA) en tu aplicación, debes crear un directorio llamado .codes fuera del directorio web público. Este directorio se utiliza para almacenar los códigos de verificación de manera segura, evitando que sean accesibles públicamente. Asegúrate que el usuario «www-data» correspondiente a tu servidor web tenga permisos de lectura escritura sobre este archivo.
  • Directorio para JWT cifrado: En caso de que decidas implementar JWT cifrado, es necesario crear un directorio llamado .keys fuera del directorio web público (recomendado). Este directorio almacenará las claves privadas necesarias para el cifrado y descifrado de los tokens JWT, manteniéndolas seguras y fuera del alcance de posibles atacantes. Asegúrate que el usuario «www-data» correspondiente a tu servidor web tenga permisos de lectura escritura sobre este archivo.
  • Argon2: Para mejorar la seguridad de las contraseñas almacenadas, LoginSkel permite el uso del algoritmo de hashing Argon2, considerado uno de los más seguros en la actualidad. Para utilizar Argon2, asegúrate de que tu instalación de PHP sea la versión 7.2 o superior y que este algoritmo esté disponible en tu entorno.
  • Sendmail: En esta versión inicial de LoginSystem, los correos electrónicos se envían utilizando la función mail() de PHP. Aunque sabemos que existen opciones más seguras para el envío de correos, como el uso de bibliotecas especializadas como PHPMailer, hemos optado por esta solución simple para comenzar. Debido a esto, necesitarás configurar Sendmail en tu servidor. Asegúrate de agregar la siguiente variable de configuración en el archivo php.ini de tu dominio, reemplazando con tu propio correo electrónico:
// Ver la sección Anexos: Configuración segura de PHP Mail para una explicación
// de los modificadores y otras questiones relativas a la seguridad.

sendmail_path="/usr/sbin/sendmail -t -i -f micorreo@miservidordecorreo.com"

NOTA: Consulta la sección de Anexos: Configuración segura de PHP Mail() para obtener más detalles sobre cómo configurar y usar mail() en PHP de manera segura.

Con estos requerimientos preparados, podrás proceder con la instalación de LoginSkel de manera efectiva y segura.

Instalación

Supongamos que tu proyecto o aplicación PHP se encuentra en un subdominio de desarrollo, como https://devs.dominioejemplo.com/. Para instalar LoginSkel, puedes seguir uno de los siguientes métodos:

Descargar manualmente: Descarga el repositorio desde GitHub y súbelo a la raíz de tu subdominio mediante FTP o cualquier otro método de transferencia de archivos.

Uso de terminal: Si prefieres usar la terminal, accede al directorio web de tu servidor y ejecuta el siguiente comando para clonar el repositorio directamente:

git clone https://github.com/Parkteknia/LoginSkel.git

Una vez que hayas clonado el repositorio en la raíz de tu proyecto, puedes acceder a https://devs.dominioejemplo.com/loginskel/ en tu navegador. Esto iniciará la página de instalación de LoginSkel.

1. Instalación de la Base de Datos

En la primera pantalla configuramos las credenciales de acceso a la Base de Datos y se crean las tablas necesarias (puede tardar unos segundos).

2. Idioma por defecto

Por defecto, LoginSkel se inicia en Español. En esta sección puedes cambiar el idioma de la aplicación..

Configuración básica inicial

En la siguiente pantalla configuramos los siguientes parámetros globales que deberían aparecer configurados por defecto en función del entorno en el que se esté ejecutando el instalador, en especial los tres primeros campos.

  • Zona horaria: La zona horaria configurada en tu servidor
  • App url: La URL donde reside el proyecto o aplicación que quieres proteger
  • App path: A menos que hayas cambiado el nombre por defecto del directorio que contiene LoginSkel
  • Intentos máximos fallidos en Login y Registro
  • Intervalo de tiempo en el que se permiten dichos intentos
  • Duración del bloqueo de la IP que supera el número máximo de intentos fallidos en el login o en el registro

Configuraciones de seguridad adicionales

  • Validación cuenta: Método de validación post-registro. La validación se realiza mediante el envío de un correo electrónico desde la dirección configurada en la directiva sendmail arriba descrita. Este correo puede contener o un código de activación «code» o un link?t=token».
  • Autentiación 2FA: Activa el segundo factor de autenticación
  • JWT: Activa la demostración de uso de JWT
  • JWT cifrado: Activa la demostración de cifrado del JWT (Ver Anexos)

Instalación completada

Una vez finalizada la instalación ya puedes registrar el usuario «Admin».

Registro, Inicio de Sesión y acceso al Panel de Control Admin

Antes de poder entrar al Panel de Administrador de LoginSkel debes registrar tu primer usuario, que por defecto será el Admin, posteriormente puedes hacer login en la aplicación. Dependiendo de como hayas instalado LoginSkel, el proceso de registro variará:

  • Activaste la Activación de Cuenta: Un email te será enviado con el método de validación que hayas configurado y deberás activar tu cuenta de la forma correspondiente.
    • Si activaste 2FA (doble factor de autenticación): Una vez hayas validado tu cuenta se te redirigirá a la pantalla de configuración del 2FA mediante el escaneo de un QR para que puedas iniciar sesión posteriormente.
  • No activaste la Validación de Cuenta pero si el 2FA: Si el registro es satisfactorio te redirigirá directamente a la configuración del 2FA mediante el escaneo de un QR para que puedas iniciar sesión posteriormente.

Página de Registro de Usuario

Página de Inicio de Sesión

Registro y 2FA (Doble factor)

Validación 2FA post Inicio de Sesión

Principales funcionalidades del Panel de Administración

  • Configuración global de todas las funcionalidades vistas
  • Configuraciones adicionales:
    • Tipo de cifrado (Bcrypt o Argon2)
    • Listas de protección de contraseñas (Por defecto incluye 10-million-password-list-top-10000.txt
    • Posibilidad de escanear los archivos con listas mediante la API de VirusTotal antes de subir la lista al servidor.
    • Visualización de Usuarios
    • Visualización de información de la Sesión (útil para debuguear modificaciones u otras implementaciones)
  • Cuando JWT está activo permite la configuración y contenido del token JWT
  • Si JWT se activó y configuró, se puede realizar un simple test contra una API «ficticia» mediante JWT y Refresh Token (ver las cookies) y JWE

Protección del proyecto o aplicación

Una vez que se haya realizado la configuración de LoginSkel, siguiendo con la url que pusimos de ejemplo más arriba, https://devs.dominioejemplo.com/ y suponiendo que en dicha URL se renderice un archivo index.php, deberemos incluir en dicho archivo lo siguiente (estas porciones de código deben añadirse en todas y cada una de las páginas a las que se quiera restringir el acceso de forma pública):

// Protección para usuarios con role "user" (usuario sin privilegios)
require '../LoginSkel.php';

$loginskel = new LoginSkel();

if (!$loginskel->isLoggedIn() || ($loginskel->get2Factor() && !$loginskel->has2faValidated())) {
    header('Location: login');
    exit();
}

// Para que solo usuarios "admin" puedan acceder al recurso, a continuación del código anterior se debe añadir:

$user = $loginskel->getUser();

if(!$loginskel->isUserAdmin($user['username'])) {
    header('Location: index');
    exit();  
}
echo "recurso para admins";

Anexos

Consideraciones sobre las librerías incluidas

LoginSkel incluye una variedad de librerías desarrolladas internamente (JWT, JWE, RSAKeyManager, TOTP, Base32, VirusTotal, etc.) diseñadas para simplificar la implementación y evitar dependencias externas. Aunque estas librerías han sido creadas con énfasis en la estabilidad, los usuarios pueden optar por utilizar librerías de terceros más conocidas y mantenidas. En ese caso, deberán ajustar el código según sea necesario para integrar las librerías de su elección.

Árbol de directorios de LoginSkel

LoginSkel/
├── Install.php // Clase Install con la lógica principal del instalador de LoginSkel
├── LoginSkel.php // Clase LoginSkel con la lógica principal de la aplicación
├── config
│   ├── config.php // Archivo que guarda la configuración de la base de datos
│                  // así como otras variables de seguridad globales
│   └── loginskel.sql // El SQL para la creación de la Base de Datos e inserción
│                     // de algunos valores por defecto.
├── filters
│   └── 10-million-password-list-top-10000.txt // Filtro incluido por defecto para la validación
│                                              // de la contraseña durante el registro
├── libs
│   ├── Base32.php // Implementación de Base32 para la codificación de la llave secreta generada desde TOTP
│   ├── TOTP.php // Implementación de TOTP para la generación de códigos QR
│                // usados por el doble factor de autenticación (2FA)
│   ├── JWT.php // Implementación de JWT
│   ├── LSException.php // Clase para manejar las excepciones de la app (no implementado, se devuelven errores)
│   ├── phpqrcode // Implementación de https://phpqrcode.sourceforge.net
│   ├── qrServer.php // "Servidor" de imagen QR desde una ruta específica.
│   ├── serveQRImage.php // Llamada al servidor para devolver la generación de imágenes QR
│   ├── RSAKeyManager.php // Manejo de llaves RSA
│   ├── Translator.php // Devuelve traducciones
│   └── VirusTotal.php // Simple implementación que verifica un archivo antes de
│                      // subirlo al servidor.
│                      // Concretamente se usa para subir listas de contraseñas
│                      // (su uso es opcional en el momento de la subida)
├── locale // Las diferentes traducciones de LoginSkel
│   ├── ca_ES // Catalán
│   │   └── messages.php
│   ├── de_DE // Alemán
│   │   └── messages.php
│   ├── en_US //Inglés
│   │   └── messages.php
│   ├── es_ES //Español
│   │   └── messages.php
│   ├── fr_FR // Francés
│   │   └── messages.php
│   ├── it_IT // Italiano
│   │   └── messages.php
│   └── pt_PT // Portugués
│       └── messages.php
├── public // Todas las páginas públicas
│   ├── assets // Contiene estilos y javascript
│   │   ├── password_strength.php
│   │   └── styles.css
│   ├── 2fa_setup.php // Para escanear el código QR
│   ├── 2fa_validate.php // Para validar el código QR
│   ├── admin.php // Panel de Administración
│   ├── api.php // "Simulación API", cuando se ha configurado JWT,
│               // se puede simular una llamada tipo API a
│               // este archivo para ver el proceso de validación
│               // y recreación de JWT y Refresh Tokens
│   ├── banned.php // Usuario baneado (bloqueado) es redirigido a esta página
│   ├── error.php // No implementado pero puede usarse para debuguear
│                 // errores redirigiendo a este archivo
│   ├── forgot_pass.php // Proceso de solicitud de cambio de contraseña
│   ├── reset_pass.php // Proceso de cambio de contraseña
│   ├── index.php // Actúa a modo de "enrutador", si LoginSkel no está
│                 // instalado redirige a Install, si lo está reenvía a Login
│   ├── login.php // Iniciar sesión
│   ├── logout.php // Cerrar y destruir la sesión
│   ├── register.php // Registro de Usuario
│   ├── resend.php // Maneja el reenvío del email de validación de cuenta
│                  // cuando el token o el código de validación expiraron
│   ├── success.php // Cuenta de usuario registrada correctamente
│   └── validate.php // Solicita códigos de validación
└── template
    ├── admin-dash.php // Template del Panel de Administración
    ├── header.php // Template para la cabecera de la página
    └── footer.php // Template para el pie de página

Configuración segura de PHP Mail()

Los modificadores tienen las siguientes funciones:

  • -t: Indica a sendmail que lea los destinatarios del correo desde los encabezados («To«, «Cc«, «Bcc«).
  • -i: Hace que sendmail ignore las líneas que contienen solo un punto (.), evitando que termine el mensaje antes de tiempo.
  • -f: Permite especificar la dirección de correo del remitente, configurando el campo «Return-Path» para gestionar correctamente los rebotes de correos.

Cuando se configura sendmail_path con sendmail, es importante tener en cuenta varias consideraciones de seguridad:

  1. Validación y Saneamiento de Entradas: Asegúrate de que todas las entradas que se envían a través de sendmail sean adecuadamente saneadas y validadas para evitar inyecciones de comandos. Sin una sanitización adecuada, un atacante podría inyectar comandos adicionales a través de los parámetros de correo electrónico, lo cual puede ser explotado si se están usando variables que no se han limpiado correctamente.
  2. Control de Permisos y Acceso: La configuración del sistema y los permisos del archivo sendmail deben ser revisados para asegurarse de que solo los usuarios y procesos necesarios tengan acceso para ejecutar sendmail. Esto evita que usuarios no autorizados puedan enviar correos no deseados o potencialmente dañinos.
  3. Configuración de sendmail: Es crucial que el servidor de sendmail esté bien configurado para prevenir abuso. Esto incluye configurar adecuadamente las políticas de autenticación y autorización para asegurar que solo los usuarios autorizados puedan enviar correos electrónicos a través del servidor.
  4. Configuración de PHP.ini: La configuración de sendmail_path debe ser protegida de cambios no autorizados. Esto implica configurar el archivo php.ini para que no sea editable por usuarios no autorizados y revisar regularmente los permisos de archivo.
  5. Uso de SPF/DKIM: Implementar y configurar SPF (Sender Policy Framework) y DKIM (DomainKeys Identified Mail) ayuda a prevenir suplantación de identidad (spoofing)

JWT, JWE cifrado y pruebas contra la «API»

Tanto JWT (utilizado en un esquema de Token + Refresh Token mediante cookies) como la implementación de JWE están incluidos en LoginSkel como demostración. Su uso en un entorno real dependerá de las necesidades específicas de la aplicación o proyecto a proteger, quedando la implementación final a cargo del usuario.

Por otro lado, si mientras adaptas LoginSystem a tus necesidades tu directorio de trabajo sigue estando protegido mediante HTTP Basic Auth, para que las llamadas a la API de prueba no te den problemas deberás configurar en public/admin.php las credenciales de tu entorno correctamente:

// Credentials for basic authentication
const http_auth_basic = true;
const username = 'usuario';
const password = 'contraseña';

Qué no incluye LoginSkel

  • Los datos en la base de datos no están cifrados y podría ser una buena práctica dependiendo del tipo de proyecto.
  • El JWT podría incluir algún tipo de control de IP (tokens válidos solo para la IP a la que se entregaron o configuraciones de JWT entre IPs estáticas.
  • «Remember me» para que la sesión del usuario no se cierre pasada una hora de inactividad.

This post has 0 likes
Like this Post

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Scroll al inicio