Ciberseguridad - ISPC-WEB-2025/TodoStock-AppMovil GitHub Wiki
Responsables del Módulo de Seguridad: Aylén Bartolino Luna / Pedro González (#RNF-SEG)
Responsable de Documentación y Marco Legal: Octavio Arnaudo (#TK31 - Sprint 1 / #TK105 - Sprint 2)
Candelaria Barjollo (#TK53 - Sprint 2) · Última revisión: 14/10/2026
Enlace: https://drive.google.com/file/d/15kLuM3k91j3ies_6rDmanfDK_S5aUV2n/view?usp=sharing
Video: https://drive.google.com/drive/folders/1Dv_zDifi0bG0tjF0XcN1aloTNVybkpWS?usp=sharing
En TodoStock Mobile se maneja información del stock y datos de los empleados, como nombres, correos, DNI y fechas de nacimiento. En este documento dejamos asentado qué riesgos vimos en el sistema, las medidas que tomamos para frenarlos, quién se encarga de cada cosa y cada cuánto se revisan.
Aclaramos que acá detallamos únicamente lo que ya está funcionando en la app de Android y en el servidor con Django. Lo que todavía nos queda pendiente lo dejamos anotado al final, en la sección 5.
El sistema cumple estrictamente con las normas confirmadas de ciberseguridad y privacidad:
- Ley N° 25.326 de Protección de Datos Personales (Argentina): Garantía de Derechos ARCO (Acceso, Rectificación, Cancelación y Oposición). Órgano de Control: Agencia de Acceso a la Información Pública (AAIP).
- Reglamento General de Protección de Datos (RGPD / GDPR - UE 2016/679): Principios de Privacy by Design, Privacy by Default y Minimización de Datos.
- Ley N° 24.240 y Resolución SCI N° 272/2020: Botón de Arrepentimiento / Opción "Darme de baja" y revocación del servicio adaptada a la aplicación móvil.
- Ley N° 26.388 (Delitos Informáticos): Prevención de acceso indebido y alteración de datos.
📄 Documentación legal completa: Consultar el documento detallado en la Wiki: Protección de Datos.
Para prevenir ataques de fuerza bruta y asegurar las cuentas de los usuarios:
- Longitud mínima: 9 caracteres.
- Complejidad: Debe incluir letras (mayúsculas/minúsculas), números y al menos un carácter especial.
-
Validación: Se implementan validaciones en el cliente (
TextInputLayout) y en el servidor. - Hashing: Las contraseñas se almacenan en el backend con algoritmos de hash unidireccional de alta entropía (BCrypt / PBKDF2).
-
Tokens Temporales: Las sesiones se gestionan mediante tokens JWT (
token_accessytoken_refresh) de corta duración con posibilidad de refresh transparente. - Gestión por Roles: La aplicación adapta el menú y las funciones según el rol del usuario (Administrador vs Empleado).
-
Cierre de Sesión: El usuario puede cerrar sesión manualmente desde
MenuPrincipalActivity, lo que limpia de inmediato las credenciales almacenadas enSesionManager.
- Toda comunicación entre la aplicación móvil y el servidor backend se realiza exclusivamente a través de HTTPS.
- Se utiliza el protocolo TLS 1.2 o superior para cifrar los datos en tránsito, evitando ataques de Man-in-the-Middle (MitM).
- Bitácora de Movimientos y Eventos: Cada ajuste de stock, traslado o baja/arrepentimiento de usuario queda registrado con timestamp, evento e ID de usuario.
- Logs de Error: Los errores críticos se registran en el servidor para detectar intentos de acceso no autorizados.
TodoStock Mobile utiliza JSON Web Tokens (JWT) como mecanismo principal de autenticación.
-
Transmisión: Se inyecta automáticamente en el encabezado
Authorization: Bearer <token>medianteAuthInterceptoren OkHttp/Retrofit. -
Almacenamiento: Gestión de sesión centralizada con
SesionManager(SharedPreferences) para guardar de forma aislada los tokenstoken_accessytoken_refresh, el rol de usuario y los datos del usuario activo.
- Se activa R8/ProGuard en el modo
releasepara renombrar clases y eliminar logs de depuración.
Caution
Queda terminantemente prohibido subir archivos de configuración, claves API o secretos de firma al repositorio público.
-
Persistencia Segura de Tokens (
SesionManager): Los tokens JWT (access_tokenyrefresh_token) se almacenan de forma aislada y encriptada en la aplicación móvil, evitando exposición en almacenamiento secundario. -
Inyección Transparente de Autenticación (
AuthInterceptor): Cada llamada a la API REST a través de Retrofit intercepta la petición HTTP e inyecta la cabeceraAuthorization: Bearer <token>(PR #49, PR #50). -
Tráfico Encriptado SSL/TLS (
network_security_config.xml): La comunicación con el backend en Alwaysdata (https://todostock.alwaysdata.net/api/) se fuerza exclusivamente sobre HTTPS, rechazando conexiones en texto plano HTTP en compilaciones de producción.
-
Control de Throttling y Rate Limiting: Protección activa contra ataques de fuerza bruta en
/api/usuarios/login/mediante Django REST FrameworkUserRateThrottleyAnonRateThrottle(auditado en PR #160). -
Secreción de Claves: Eliminación total de claves hardcodeadas en el código fuente, utilizando variables de entorno
.enven el servidor Alwaysdata (cumpliendo la tarea #TK45). -
Protección CORS y Headers HTTP: Configuración restringida de
CORS_ALLOWED_ORIGINSyALLOWED_HOSTSpara impedir consumo no autorizado desde orígenes web no permisionados.
| # | Medida / Política | ¿Qué problema evita? | ¿Cómo lo resolvimos en el sistema? | Revisión y frecuencia | Responsable |
|---|---|---|---|---|---|
| P1 | Claves difíciles | Que adivinen contraseñas fáciles | Pedimos al menos 9 caracteres con letras, números y símbolos, sin espacios. Se chequea en la app y en el backend, y las claves se guardan encriptadas con PBKDF2. | Corremos los tests de ValidadoresTest y casos TC-SEG en cada entrega. |
Aylén |
| P2 | Límite de intentos al entrar | Que prueben mil contraseñas seguidas para entrar (fuerza bruta) | Dejamos hasta 5 intentos por minuto en el login. Si se bloquea, queda guardado en la auditoría como BLOQUEO_FUERZA_BRUTA. |
Se revisa la auditoría todas las semanas. | Aylén (configura) / Admin (revisa) |
| P3 | Sesiones que vencen (JWT) | Que usen una sesión robada por mucho tiempo | El pase de acceso dura 60 minutos y el token de refresco dura 5 días. | Se chequea en cada sprint junto a los ajustes del backend. | Aylén |
| P4 | Bloqueo por defecto sin login | Que cualquiera entre sin cuenta a ver o tocar el inventario | Todo pide haber iniciado sesión, salvo registrarse, loguearse y la parte de contacto. | Se prueba en cada sprint con los tests de backend (test_auth_enforcement). |
Miguel |
| P5 | Permisos según el rol | Que un empleado común toque cosas de un encargado o administrador | Un usuario común solo puede consultar. Crear, modificar o borrar cosas del stock y ver usuarios queda solo para administradores (en la app también se esconden los botones). | Se corre por sprint con pruebas de permisos. | Miguel / Aylén |
| P6 | Jerarquía entre administradores | Que un admin le quite el acceso a otro admin | Solo el Super Admin puede cambiarle cosas o desactivar a otro admin, y a él nadie lo puede desactivar ni tocar. | Revisión semanal de cambios de rol en los registros. | Super Administrador |
| P7 | Cuentas nuevas pausadas | Que cualquiera se cree una cuenta y empiece a usar el sistema | Al registrarse, la cuenta queda en pausa hasta que un admin la aprueba y le da su rol. | Se revisa la lista de pendientes cada vez que alguien nuevo se anota. | Administrador |
| P8 | Registro de movimientos | Que pasen cosas raras y no sepamos quién fue | Se guarda un registro con fecha, usuario e IP de logins, bloqueos, altas y bajas. Los cambios de stock se guardan en la tabla MOVIMIENTO. |
Revisión semanal de la bitácora. | Administrador |
| P9 | Claves seguras en el celular | Que si alguien agarra el teléfono pueda sacar los accesos guardados | La sesión se guarda encriptada en el celular con AES-256 (EncryptedSharedPreferences) y al salir se borra todo. |
Se revisa en cada release. | Aylén |
| P10 | Conexión segura (HTTPS) | Que alguien espíe los datos mientras viajan por internet | La app se conecta por HTTPS en la versión final. El tráfico común sin cifrar solo se permite para pruebas en la compu del programador. | Se revisa en cada release. | Miguel |
| P11 | Claves del servidor escondidas | Que queden claves maestras a la vista en el código | Las contraseñas del servidor y de la base de datos se leen desde un archivo oculto (.env) y no quedan escritas en el código. |
Se revisa antes de subir los cambios al código principal. | Aylén / Miguel |
| P12 | Cuidado de datos y baja | Tener problemas legales por el manejo de datos de la gente | Pusimos los Términos y la Política de Privacidad visibles, y cualquiera puede pedir la baja de su cuenta desde la app. | Se revisa en cada sprint. | Octavio |
No todo lo que pusimos vino pedido directamente por el cliente; varias cosas las sumamos porque son básicas para que el sistema no sea vulnerable:
| Requerimiento / Historia de usuario | Medidas que lo respaldan | ¿Lo pidió el cliente? |
|---|---|---|
| US01 Iniciar sesión y ver menú según rol | P1, P3, P5, P9 | Sí |
| US01 Iniciar sesión | P2 (frenar intentos seguidos) | No, por seguridad del sistema |
| US07 Registro de usuarios | P1, P7 | Sí |
| US08 Manejo de cuentas y roles | P5, P6, P7 | Sí |
| US05 y US09 Alta, edición y baja de productos | P5 | Sí |
| US06 Mover stock entre sucursales | P4, P8 (deja guardado quién lo movió) | A medias |
| US11 Borrar la cuenta y leyes | P12 | Sí |
| US12 Perfil de usuario | P4 | Sí |
| US12 Perfil de usuario | Que el usuario no se pueda poner rol admin ni cambiarse el mail solo | No, por seguridad del sistema |
| Todo el sistema | P8 (auditoría), P10 (HTTPS), P11 (claves en variables) | No, por seguridad del sistema |
Para resumir la parte técnica de lo que ya tenemos listo:
En el servidor (Django):
- Usamos tokens JWT para validar quién entra y cerramos el paso por defecto a quien no tenga sesión.
- Armamos permisos a mano para distinguir administradores y superadministradores.
- Se controlan las contraseñas para que no pongan cualquier cosa al registrarse o cambiarlas.
- El login se frena si insisten más de 5 veces en un minuto.
- Hay una tabla (
LogAuditoria) donde queda registrado lo importante y solo la ven los administradores. - Dejamos tests automáticos armados para verificar que los permisos y la auditoría no fallen.
En el celular (Android):
- Los tokens y datos de sesión se guardan de forma encriptada en el teléfono.
- Cada consulta que hace la app le pega al servidor mandando el token correspondiente.
- La app usa conexiones seguras HTTPS para conectarse a internet.
- Si la contraseña o el mail no cumplen el formato, la app avisa antes de mandar los datos.
- La interfaz esconde los botones de administrador si entra un empleado común.
- Agregamos la pantalla de Términos y el botón para pedir la baja.
Nota: Aunque la app no muestre ciertos botones según el usuario, la traba real está en el servidor: si alguien intenta saltearse la pantalla, el backend le rebota el pedido igual.
Dejamos en claro lo que nos falta implementar más adelante para que el sistema quede todavía más protegido:
| Pendiente | Cómo está hoy |
|---|---|
| Usar el token de refresco | La app lo guarda pero todavía no lo usa; cuando pasan los 60 minutos hay que volver a loguearse. |
| Rotación de tokens de refresco | Está apagada en el backend. |
| Ocultar el código de la app (ofuscación) | Está desactivado por ahora (minifyEnabled false). |
| Archivo de seguridad de red en Android | Todavía no lo creamos, aunque Android ya bloquea conexiones inseguras por su cuenta. |
| Limpiar datos personales en las bajas | Cuando alguien se da de baja la cuenta se apaga, pero los datos personales todavía quedan guardados en la base. |
| Límites de intentos en otros formularios | Por ahora solo limitamos los intentos en el login, no en el registro ni en contacto. |
Control al abrir la app (SplashActivity) |
Manda siempre al login directamente en vez de fijarse si ya estaba logueado. |
| Reglas para copias de seguridad del celular | El backup del teléfono está prendido pero sin filtros claros sobre qué carpetas no respaldar. |
| Alertas por caídas o errores raros | No tenemos un sistema específico que nos avise si alguien está intentando vulnerar cosas más allá de leer la tabla de logs. |
Nos basamos en lo que pide la Ley 25.326 de Protección de Datos Personales y normas de defensa del consumidor sobre el derecho a darse de baja.
Hoy en día cumplimos con mostrar los términos antes del registro, dejar que la persona modifique sus datos y permitir que solicite la baja. Lo que nos queda pendiente para estar 100% al día con esto es borrar o tapar los datos personales una vez que la cuenta se desactiva.
- Al terminar cada sprint, el equipo se junta a revisar si la matriz sigue reflejando la realidad del código.
- Si agregamos una traba o cambiamos algo, actualizamos la tabla y cambiamos la fecha de revisión del encabezado.
- Solo ponemos en la matriz lo que ya esté programado y probado; lo que no se llegó a hacer queda en la lista de pendientes.