5. Arquitectura y Diseño
5.6. Atributos de calidad
5.6.3. Seguridad
Limitar exposición e identificación de actores
La primera táctica empleada para proteger la aplicación empieza en el primer paso para acceder al sistema: el registro. El sistema está habilitado únicamente para usuarios miembros de la clínica, es por esto que se identificó que el registro debía hacerse por parte de los especialistas y que no sea un registro abierto tal como se pudo ver en la Ilustración 1 4. Esto reduce en gran parte, la cantidad de usuarios que consiguen un token de acceso al sistema.
Además de esto, el equipo decidió identificar a sus actores mediante su correo electrónico.
Una vez realizado el registro por parte del especialista, el nuevo usuario (sea paciente o especialista), recibe un mail de confirmación a su casilla de correo para que verifique su mail . Hasta no realizar este paso, el usuario no tendrá acceso a su cuenta. De esta manera se asegura poder identificar las acciones realizadas por el usuario. En la Ilustración 1 5 se puede ver el mail de confirmación recibido por un usuario.
Diagrama 13 - Secuencia de registro de un paciente.
Como se puede ver en el diagrama, previo al envío del mail se genera un token para confirmar que el usuario que recibe el mail es el mismo que se está dando de alta en el sistema. En la URI enviada al backend se pasa este token . Si el mismo es válido, el usuario es redirigido a iniciar sesión, de lo contrario a una página de error. Cabe destacar que el elemento
“SendGrid” del diagrama es el servicio de envío de mails que utilizó el equipo.
Autenticación
Una vez que el usuario inicia sesión con su usuario y clave, el backend devuelve su token de acceso. Este token de acceso es generado por la librería Laravel Sanctum [104] , paquete que es parte del framework y es quien genera (usando criptografía sobre la clave APP_KEY del .env, se hablará de la encriptación posteriormente en esta sección), verifica (usando un
middleware ) y guarda (en la tabla de Personal_Access_Tokens , ver en Diagrama 8 ) los tokens personales de acceso. De esta manera todas las rutas se encuentran protegidas. Cabe destacar que el token expira de dos formas, por tiempo y en caso de que el usuario cierre sesión manualmente se eliminan todos sus tokens .
Autorización
La autorización del sistema está basada en roles y permisos, como ya se comentó
previamente. Con respecto a su implementación, se usó un paquete de Laravel Permissions de Spatie, se pueden ver estos detalles en el punto de Roles y Permisos dentro de 5.3.4. Modelo de datos [76] . Con esta explicación y la anterior se completa el RNF-SE2 - Autorización y autenticación .
● Los roles que existen son: administrador, especialista y paciente.
● Los permisos disponibles son: manejo de administradores, manejo de especialistas, manejo de pacientes, manejo de planes, manejo de medidas, manejo de categorías, manejo de unidades, manejo de comidas, manejo de ingredientes, manejo de grupos, manejo de datos de usuario.
Dicho esto, la forma de obtener acceso a un recurso puede darse de 3 formas diferentes, teniendo el permiso para hacerlo (especialista), ser el dueño de ese recurso (paciente) o tener acceso a todo el sistema (administrador). Para lograrlo, cada rol tiene cierto nivel de acceso que es verificado con cada request entrante al sistema mediante Gates de Laravel [105] . Las gates o en español “puertas” son literalmente eso: el sistema más básico de autorización de Laravel, pudiendo editar la lógica que se ejecuta a gusto. Las puertas se definen en el AuthorizationServiceProvider.php .
Ilustración 67 - Lógica de las Gates .
Como se puede ver, la primera gate permite al administrador ser autorizado siempre. La segunda limita el acceso al dueño del recurso o si el usuario tiene ese permiso. La forma de llamarla es por ejemplo “ Gate::authorize('owned_or_permission', [$user,
Permission::MANAGE_MEASURES]);” . Esta línea de código es ejecutada en caso de que se quiera actualizar una medida del usuario, pudiendo ser él mismo quien la actualice o un especialista con ese permiso.
Datos Sensibles: Encriptación y GoogleFit
En este punto se cubre el cumplimiento del RNF-SE1 - Encriptación de los datos . Los datos sensibles son encriptados en la base de datos como una capa adicional de seguridad. Por otro lado, los datos de Google Fit no son guardados en la aplicación, en caso de quererlos se consulta directamente la API. El equipo se cuestionó esta decisión y decidió que por motivos de seguridad y sobre todo integridad de los datos, lo mejor es traer los datos cada vez que sean necesarios. La integridad se debe a que con el paso del tiempo, Google Fit puede
modificar las estadísticas mostradas debido a que los datos que muestra son de un conjunto de diversas fuentes (sensores, wearables ) y se procesan mediante algoritmos específicos de la aplicación [106] . La alternativa hubiese sido tener un cron que corra todos los días guardando la información del usuario y actualizando en caso de que sea necesario (siendo costoso e innecesario).
Con respecto a la encriptación, se usa el servicio de Laravel que usa algoritmos AES-256 y AES-128 y como clave criptográfica usa la APP_KEY autogenerada en el . env [107] . Usar esta clave por entorno permite que los diferentes ambientes no puedan decodificar datos de otro. Los datos encriptados son las medidas registradas por el usuario y su clave.
Ilustración 68 - Datos encriptados.
Logs de auditoría
Para el cumplimiento de RNF-SE4 - Logs de auditoría , se usó la herramienta Sentry [108] , más detalles acerca de la herramienta se pueden ver en 5.6.8. Observabilidad . Gracias a esta herramienta, el equipo tiene acceso a un registro de eventos del sistema asociado a sus diferentes usuarios. En caso de que existan acciones sin un usuario autenticado, se obtiene la dirección IP. En la imagen se puede notar el seguimiento de eventos para un usuario referente a un miembro del equipo.
Ilustración 69 - Eventos de usuario.
Al entrar a cierto evento específico, se obtienen detalles minuciosos acerca de la ejecución.
Desde queries a la base de datos (sin mostrar datos concretos), tiempos de ejecución, detalles del cliente y un gran número de detalles útiles en caso de necesidad de hacer un seguimiento de un ataque al software .
Ilustración 70 - Evento concreto en Sentry . Validación de inputs
El equipo protegió los diferentes inputs del sistema gracias al uso de form requests de Laravel [58] y Eloquent [48] , su ORM, cumpliendo así con RNF-SE3 - Protección contra Inyecciones . Las form requests permiten realizar validaciones entrantes al sistema, teniendo como
resultado un array con los datos y el formato ya validado. En caso de que una validación falle, se devuelve una respuesta con status 422 y un mensaje de error descriptivo acerca de la falla.
Eloquent por su lado, parametriza las queries antes de ejecutarlas por lo que de esta forma se evita cualquier tipo de inyección SQL. El único caso en el que esto puede fallar sería usar sentencias raw, pero el equipo no usó ninguna de ellas. La documentación oficial de Laravel advierte explícitamente tener cuidado al hacer uso de este tipo de sentencias por las posibles
inyecciones [109] . HTTPS
Todas las comunicaciones que puedan tener interacción con un cliente se hacen mediante el protocolo seguro HTTPS. Hoy en día este es un requerimiento básico para cualquier
aplicación web que quiera evitar que los datos transferidos a través de la red sean vistos por usuarios sin autorización. Gracias a este protocolo, los datos van encriptados en base a un certificado SSL. Para más profundidad ver la sección 5.5.3. DNS en Infraestructura . Denegación de servicio
Con la intención de evitar ataques por denegación de servicio el equipo implementó un sencillo mecanismo de seguridad que se puede ver en la siguiente ilustración:
Ilustración 71 - Rate Limit por ID de usuario o IP.
El límite de peticiones aceptadas por el servidor es de 60 por minuto por ID de usuario si lo tiene y si no por IP de origen. En 7.4.2.4. Pruebas de carga con JMeter se puede comprobar el mensaje de error.