Lista de verificación de seguridad de aplicaciones Flutter
Fase 0: Gobernanza, entorno y CI/CD
Herramientas y versiones
- Mantener actualizados Flutter, el SDK de Dart, Android Studio/Xcode y todos los plugins/dependencias.
- Revisar los avisos de seguridad (security advisories) para paquetes de Flutter y SDKs nativos antes de cada versión.
Aplicar controles de CI (CI gates)
- En cada PR, ejecutar:
-
dart analyze -
flutter test --coverage - Linter de Android/Gradle
- Comprobaciones de compilación de iOS
- Auditorías de dependencias
- Fallar las compilaciones ante errores del analizador y cualquier advertencia configurada como error.
- Exigir cero errores de linter en las ramas de lanzamiento (release).
Establecer controles de seguridad
- Ejecutar escaneos móviles de SAST/SCA/DAST en cada PR y antes de cada lanzamiento.
- Bloquear ante hallazgos de severidad Alta o Crítica.
- Integrar los escaneos directamente en el pipeline de CI/CD para que los hallazgos Altos/Críticos detengan la compilación.
Gestión de secretos
- Garantizar la ausencia de secretos en:
- Código fuente de Dart
- Código nativo
-
AndroidManifest.xml -
Info.plist - Recursos (assets)
- Registros (logs)
- Utilizar variables de entorno, almacenes de secretos de CI y/o gestores de secretos (secret managers).
- Ocultar (redactar) secretos en herramientas de analítica y registro.
- Rotar claves de API y tokens de forma regular y siempre que se sospeche de una fuga.
Evidencia y trazabilidad
- Generar y archivar para cada artefacto:
- Informes de escaneo
- SBOMs
- Registros de compilación (build logs)
- Informes de pruebas
- Notas de la versión (release notes)
Fase 1: Modelado de amenazas, clasificación de datos e inventario
- Clasificar los tipos de datos (PII, credenciales, tokens, datos de pago, datos de salud).
- Documentar dónde se recopila, procesa, almacena y transmite cada tipo en:
- Código de la aplicación Flutter
- Capas nativas
- Identificar los límites de confianza (trust boundaries):
- Código de la aplicación Flutter
- Canales de plataforma nativa (Android/iOS)
- Almacenamiento del dispositivo
- WebView/navegador
- APIs de backend
- Servicios de terceros
- Realizar un inventario de todos los paquetes de Dart, plugins y SDKs nativos.
- Priorizar dependencias bien mantenidas, firmadas y con privilegios mínimos.
- Minimizar el número total y el alcance de las dependencias.
- Definir criterios de aceptación de seguridad por clase de riesgo (p. ej., "Sin datos sensibles en reposo en texto claro", "Todo el tráfico de autenticación con pinning", "Sin registros de depuración en release").
Fase 2: Fortalecimiento de la compilación y configuración (Flutter + Android + iOS)
Compilaciones de lanzamiento de Flutter
- Compilar con ofuscación y división de símbolos de depuración para Android:
-
flutter build appbundle --release --obfuscate --split-debug-info=build/symbols - Compilar con ofuscación y división de símbolos de depuración para iOS:
-
flutter build ipa --release --obfuscate --split-debug-info=build/symbols - Almacenar
build/symbolsde forma segura en el servidor. - Nunca incluir símbolos ni archivos de mapeo en el paquete de la aplicación.
Higiene del registro (logging)
- Proteger los registros tras
kReleaseModeo su equivalente. - Eliminar
print/debugPrint/ registros detallados de las rutas de código de producción. - Añadir comprobaciones de CI para fallar las compilaciones si aparecen registros de depuración en código que no sea de prueba en ramas de lanzamiento.
Android (Gradle + Manifest)
- Habilitar R8/ProGuard y la reducción de recursos (resource shrinking) para release:
-
minifyEnabled true -
shrinkResources true - Utilizar reglas optimizadas de ProGuard.
- Fortalecer
AndroidManifest.xml: -
android:debuggable="false"en release. -
android:allowBackup="false"a menos que cuente con un diseño de respaldo seguro. -
android:usesCleartextTraffic="false"; sin degradación a HTTP en producción. - Establecer
android:exportedexplícito en los componentes; evitar exportar sin controles estrictos de permisos. - Configurar el Network Security Config:
- Deshabilitar el tráfico en texto claro globalmente.
- Definir configuraciones por dominio.
- Si se utiliza pinning, definir conjuntos de pines con pines de respaldo.
- Firma e integridad:
- Utilizar Play App Signing donde corresponda.
- Proteger los keystores.
- Habilitar Play Integrity API e integrar sus señales con las decisiones de riesgo en el backend.
iOS (Xcode + Info.plist dentro del proyecto Flutter)
- App Transport Security (ATS):
-
NSAllowsArbitraryLoads = false. - Utilizar
NSExceptionDomainsestrictos solo para excepciones necesarias y limitadas en el tiempo. - Ajustes de compilación de release:
- Eliminar (strip) símbolos de depuración.
- Habilitar la eliminación de código muerto (dead code stripping).
- Habilitar la optimización de módulo completo (whole-module optimization).
- Asegurarse de que no existan indicadores de
DEBUGni bibliotecas de prueba en las compilaciones de lanzamiento. - Valores predeterminados del Keychain para almacenamiento nativo/plugins:
- Priorizar clases
ThisDeviceOnlysiempre que sea posible. - Enmascarar las capturas en segundo plano (vía código nativo o plugins de Flutter) para que el conmutador de aplicaciones nunca muestre datos sensibles.
Fase 3: Seguridad de red y TLS/pinning
Cumplimiento estricto de HTTPS/TLS
- Garantizar que todo el tráfico hacia las APIs utilice HTTPS/TLS 1.2+.
- Rechazar certificados no válidos, certificados autofirmados (si no son explícitamente de confianza) y endpoints con discrepancia de nombre de host (hostname mismatch).
- Configurar tiempos de espera (timeouts) razonables.
- Implementar reintentos con variación aleatoria (jitter) donde sea apropiado.
- Proceder siempre con cierre seguro ante fallos (fail-closed) en errores de TLS (sin degradación a HTTP).
Fijación de certificados (Certificate pinning)
- Para dominios críticos, implementar fijación de certificados o de SPKI SHA-256 en:
- El cliente HTTP utilizado por Flutter.
- Cualquier mecanismo de red nativo utilizado por los plugins.
- Mantener al menos un pin de respaldo por host.
- Diseñar y probar escenarios de rotación de pines.
- Validar el comportamiento de pinning ante:
- Intentos de ataque MITM.
- Certificados caducados.
- CAs no confiables.
- Registrar fallos de pinning y enviar la telemetría correspondiente.
Seguridad del lado del servidor
- Aplicar HSTS en los endpoints del backend.
- Utilizar suites de cifrado robustas y versiones de protocolo modernas.
- Utilizar cookies seguras con atributos Secure, HttpOnly y SameSite para endpoints web accedidos a través de WebView o navegadores integrados.
- Evitar tokens de portador (bearer tokens) de larga duración en el cliente.
Fase 4: Almacenamiento local y gestión de secretos
Secretos y tokens
- Nunca almacenar secretos o tokens en:
-
SharedPreferences - Archivos
plist - SQLite sin cifrar
- Archivos de texto claro desde Dart
- No incrustar secretos en:
- Valores
const - Recursos (assets)
- Código generado
Almacenamiento seguro
- Utilizar almacenamiento seguro vinculado a los keystores de la plataforma para tokens y claves (p. ej., Android Keystore, iOS Keychain mediante plugins de Flutter).
- Cuando la experiencia de usuario (UX) lo permita, condicionar el descifrado/uso de claves de alto riesgo a biometría o al código de bloqueo del SO.
- Priorizar claves vinculadas al dispositivo (
ThisDeviceOnly/ respaldadas por hardware) para tokens de alto valor.
Almacenamiento cifrado (archivos/bases de datos)
- Utilizar SQLite cifrado o cifrado de archivos equivalente para registros sensibles.
- Asegurarse de que las capas de caché (p. ej., caché HTTP, persistencia local) no almacenen PII ni secretos en texto claro.
Ciclo de vida de los datos
- Limpiar:
- Cachés
- Entradas del almacenamiento seguro
- Objetos sensibles en memoria
al cerrar sesión y al eliminar la cuenta. - Borrar los datos de WebView o del navegador integrado tras flujos de autenticación o sesiones de alto riesgo.
- Configurar las reglas de copia de seguridad de Android/iOS para evitar respaldos de datos sensibles de la aplicación sin cifrar.
Fase 5: Medidas de privacidad (UI, portapapeles, capturas de pantalla)
- Enmascarar las pantallas sensibles de Flutter cuando la app pase a segundo plano o al conmutador de tareas:
-
FLAG_SECUREen Android. - Enmascaramiento de instantáneas (snapshot masking) en iOS.
- Para vistas extremadamente sensibles (p. ej., números de tarjeta completos, secretos), utilizar un patrón de "pantalla segura" dedicado con:
- Enmascaramiento adicional.
- Bloqueo de capturas y grabación de pantalla.
- Evitar la lectura del portapapeles al iniciar la aplicación.
- Nunca copiar contraseñas, tokens o enlaces de restablecimiento en el portapapeles.
- Asegurarse de que las capturas o exportaciones dentro de la app omitan secretos/PII salvo que se requiera explícitamente y se comunique con claridad al usuario.
Fase 6: Autenticación, autorización y sesión
Flujos de autenticación
- Utilizar OAuth2/OIDC con PKCE para clientes públicos de Flutter.
- No incrustar secretos de cliente (client secrets) en la aplicación.
- Priorizar flujos de autenticación del navegador del sistema / plataforma:
- Chrome Custom Tabs en Android.
-
SFSafariViewController/ASWebAuthenticationSessionen iOS a través de plugins. - Evitar el inicio de sesión dentro de WebView siempre que sea posible.
Tokens
- Utilizar tokens de acceso de corta duración.
- Almacenar tokens de actualización (refresh tokens) únicamente en almacenamiento seguro vinculado a los keystores de la plataforma.
- Rotar tokens regularmente.
- Invalidar tokens ante:
- Cierre de sesión.
- Cambio de dispositivo.
- Patrones sospechosos.
- Considerar la vinculación al dispositivo (device binding) y verificaciones basadas en riesgo para acciones altamente sensibles, utilizando señales del dispositivo desde Android e iOS.
Autorización
- Aplicar el control de acceso en el servidor.
- No confiar en la lógica de UI o de Dart para proteger los recursos.
- Realizar pruebas de:
- IDOR/BOLA.
- Asignación masiva (mass assignment).
- Escalada de privilegios vertical y horizontal
en todos los endpoints de API utilizados por la aplicación Flutter.
Fase 7: Fortalecimiento de WebView y flujos basados en navegador
Patrón preferido
- Utilizar el navegador del sistema o vistas web seguras proporcionadas por la plataforma para autenticación y pagos cuando sea posible:
- Custom Tabs.
-
SFSafariViewController.
Si se requiere WebView (Flutter WebView o nativo)
- Deshabilitar JavaScript por defecto.
- Habilitar JavaScript únicamente si es estrictamente necesario y limitando sus capacidades.
- Restringir la navegación a una lista de permitidos (allowlist) de hosts y esquemas de confianza.
- Bloquear
file://,javascript:y otras URLs peligrosas. - Deshabilitar la depuración de contenido web en compilaciones de lanzamiento en Android e iOS.
- Limpiar cookies, caché y almacenamiento de WebView tras sesiones sensibles (autenticación, pagos, edición de PII).
- Asegurarse de que el contenido web propio (first-party):
- Aplique CSP.
- Utilice únicamente HTTPS.
- No contenga contenido mixto (mixed content).
Fase 8: Comunicación entre aplicaciones, deep links y canales de plataforma
Enlaces profundos (Deep links) y flujos entre aplicaciones
- Priorizar Android App Links y iOS Universal Links para enlaces profundos.
- Validar los orígenes de los enlaces antes de ejecutar acciones.
- Validar y sanear los parámetros de los enlaces antes de actuar.
- Evitar esquemas de URL personalizados (custom URL schemes) inseguros.
- Si se utilizan esquemas personalizados:
- Elegir esquemas únicos.
- Validar rigurosamente todos los parámetros y redirecciones.
Canales de plataforma (MethodChannel / EventChannel)
- Tratar todos los datos transmitidos desde Flutter al entorno nativo y viceversa como no confiables hasta que sean validados.
- Validar los nombres de los métodos y los parámetros en el lado nativo.
- Evitar exponer directamente APIs nativas privilegiadas a través de canales.
- Nunca transferir datos sin procesar y no confiables desde Flutter directamente a llamadas nativas con privilegios (sistema de archivos, ajustes del sistema, telecomunicaciones, etc.) sin validación y saneamiento previos.
- Aplicar fuzzing a las entradas de los canales de plataforma durante las pruebas.
- Registrar y gestionar de forma segura llamadas a métodos inesperadas o datos malformados.
Fase 9: Ingeniería inversa y resistencia a la manipulación (tamper resilience)
Reducir la exposición estática
- Ofuscar el código Dart.
- Habilitar R8/ProGuard/reducción de recursos en Android.
- Eliminar símbolos e información de depuración de los binarios distribuidos en ambas plataformas.
- Eliminar registros detallados, menús de depuración, endpoints de prueba, feature flags ocultas y puertas traseras en las compilaciones de lanzamiento.
- Evitar incrustar secretos o lógica empresarial sensible de forma fácilmente extraíble (p. ej., cadenas de texto en claro en los assets).
Comprobaciones del entorno
- Incorporar detección de root, jailbreak, hooking y depuradores tanto en Android como en iOS (mediante plugins o código nativo).
- Registrar las señales detectadas para la monitorización de seguridad.
- Responder de manera proporcional:
- Degradar funcionalidades.
- Requerir verificaciones adicionales.
- Bloquear operaciones de alto riesgo
en lugar de continuar silenciosamente con normalidad.
Pruebas de manipulación e integridad
- Validar que las aplicaciones Flutter reempaquetadas o refirmadas sean detectadas mediante comprobaciones de integridad o atestación del lado del servidor:
- Play Integrity (Android).
- DeviceCheck / App Attest en iOS.
- Tratar las comprobaciones de manipulación en el cliente como señales para el backend.
- Nunca utilizar las comprobaciones de manipulación del lado del cliente como único control de seguridad.
Fase 10: Criptografía y aleatoriedad
- Utilizar bibliotecas criptográficas reconocidas y aprobadas por la plataforma (p. ej., plugins que encapsulen Android Keystore/iOS Keychain o bibliotecas criptográficas rigurosamente evaluadas).
- No implementar algoritmos criptográficos personalizados en Dart.
- Para el cifrado, utilizar modos AEAD modernos:
- AES-GCM.
- ChaCha20-Poly1305.
- Para KDFs, utilizar:
- PBKDF2.
- HKDF
con parámetros apropiados y sales únicas por valor. - Generar claves, IVs y nonces utilizando aleatoriedad criptográficamente segura (SecureRandom o RNGs de la plataforma mediante plugins).
- Nunca reutilizar IVs ni nonces.
- Mantener las claves criptográficas protegidas en Keystore/Keychain o cifradas en reposo, nunca en memoria o configuración más tiempo del estrictamente necesario.
Fase 11: Permisos, notificaciones e identificadores
Permisos
- Solicitar el mínimo de permisos estrictamente necesarios.
- Solicitar permisos únicamente en el momento de su uso.
- Ofrecer una experiencia de usuario (UX) clara que explique por qué es necesario cada permiso.
- Implementar flujos adecuados de denegación y revocación (funcionalidad limitada en lugar de cierres inesperados o solicitudes insistentes).
Privacidad e identificadores
- Utilizar identificadores de publicidad/analítica solo según las políticas de la plataforma (p. ej., GAID/IDFA) con los flujos de consentimiento correspondientes.
- Evitar la creación de huellas persistentes entre aplicaciones (cross-app fingerprinting) mediante:
- IDs de hardware.
- Direcciones MAC.
- Otros identificadores prohibidos.
Notificaciones
- Reducir al mínimo el contenido sensible en notificaciones push y locales.
- Utilizar títulos y descripciones genéricas para las notificaciones que se muestren en la pantalla de bloqueo.
- Permitir a los usuarios configurar las categorías y la sensibilidad de las notificaciones.
- Nunca incluir secretos ni datos PII completos en las cargas útiles (payloads) de las notificaciones.
Fase 12: Registro (logging), analítica y reporte de fallos
- Estandarizar el registro estructurado.
- Deshabilitar el registro detallado/de depuración en las compilaciones de lanzamiento.
- Ocultar (redactar) PII y secretos de:
- Registros (logs)
- Eventos de analítica
- Informes de fallos (crash reports)
- Priorizar la agregación y el muestreo para las analíticas.
- Almacenar de forma segura en el servidor los archivos de mapeo/símbolos (información de depuración dividida de Flutter, mapeos de R8, dSYMs) para la desofuscación de fallos.
- Nunca enviar archivos de mapeo o símbolos dentro del paquete de la aplicación.
- Revisar periódicamente las analíticas y registros en busca de datos inesperados (campos sensibles, parámetros de consulta, encabezados, payloads).
Fase 13: Pruebas, DAST y verificación en tiempo de ejecución
Pruebas de intercepción de tráfico
- Verificar que la validación de TLS rechace:
- Certificados inválidos.
- Certificados caducados.
- Certificados autofirmados (a menos que sean explícitamente de confianza).
- Discrepancias de nombre de host (hostname mismatches).
- Confirmar que el certificate pinning (donde esté habilitado) bloquee las herramientas de intercepción MITM.
Inspección en tiempo de ejecución
- Durante las pruebas, inspeccionar:
- Almacenamiento de la app (
SharedPreferences, archivos, bases de datos). - Almacenamiento de WebView.
- Registros (logs)
en busca de secretos o PII. - Confirmar que el almacenamiento seguro y el cifrado se apliquen correctamente.
- Confirmar que la limpieza al cerrar sesión o eliminar la cuenta sea efectiva.
Pruebas de abuso de API
- Validar:
- Límites de tasa (rate limits).
- Protecciones contra repetición (replay protections).
- Límites de paginación.
- Validación de entradas
para todas las APIs utilizadas por la aplicación Flutter. - Comprobar que los mensajes de error del servidor no sean excesivamente detallados y no filtren información de implementación.
Análisis dinámico y DAST
- Ejecutar herramientas móviles de DAST mientras se prueban los flujos principales de Flutter (autenticación, pagos, perfil, configuración).
- Utilizar DAST para detectar:
- Problemas en el transporte de datos.
- Problemas en el almacenamiento.
- Problemas en WebView.
- Exportar evidencias para el triaje.
- Corregir hallazgos y volver a probar antes de promover las compilaciones.
Fase 14: SBOM y evidencia
SBOM y dependencias
- Generar y archivar SBOMs para:
- Flutter (
pubspec.lock). - Módulos nativos (Gradle/CocoaPods).
- Rastrear CVEs y avisos de seguridad para su conjunto de paquetes a lo largo del tiempo.
- Programar actualizaciones de dependencias como parte de la preparación de versiones.
Paquete de evidencias
- Adjuntar a cada registro de lanzamiento:
- Informes de SAST/SCA/DAST.
- SBOMs.
- Configuraciones de compilación (ofuscación, pinning, ATS/networkSecurityConfig).
- Informes de pruebas (automatizadas y manuales).
Fase 15: Informes y alineación con estándares
Informes
- Generar para aplicaciones Flutter:
- Resumen ejecutivo.
- Alcance y metodología.
- Hallazgos detallados con PoCs y capturas de pantalla.
- Calificaciones de riesgo.
- Planes de remediación.
- Resultados de reevaluación (re-test).
Mapeo con OWASP MASVS
- PLATFORM: Fases 2, 7–8, 11.
- STORAGE: Fases 3–4.
- CRYPTO: Fase 10.
- AUTH: Fase 6.
- NETWORK: Fase 5.
- CODE: Fases 2, 8, 12.
- RESILIENCE: Fase 9.
Referencia rápida para profesionales
- Compilaciones:
--obfuscate --split-debug-info, R8 conminifyEnabled true,shrinkResources true; sin símbolos de depuración en los artefactos distribuidos. - Red: Solo HTTPS; pinning de certificados/SPKI (con respaldos) para APIs críticas; verificar que fallen los ataques MITM.
- Almacenamiento: Almacenamiento seguro para tokens; bases de datos y archivos cifrados para datos sensibles; purga al cerrar sesión; evitar copias de seguridad de datos sensibles.
- Autenticación: OIDC + PKCE; tokens de corta duración; tokens de actualización en almacenamiento seguro; autorización en el servidor; probar IDOR/BOLA.
- WebView: Priorizar el navegador del sistema para autenticación; si se usa WebView, JS deshabilitado por defecto, lista de hosts permitidos, purga de datos tras flujos sensibles.
- Privacidad: Enmascarar capturas de pantalla en segundo plano mediante flags de la plataforma; evitar secretos en el portapapeles; permisos mínimos con UX clara.
- Controles de CI: Bloquear ante SAST/SCA Alto/Crítico; exigir DAST "sin hallazgos Altos"; cero errores de analizador/linter para producción.