Reglas de Seguridad para Dispositivos Móviles
Manejo de secretos, almacenamiento seguro, seguridad de transporte y decisiones de fijación de certificados para aplicaciones Expo en SDK 57. Los clientes móviles son entornos no confiables - asume que los atacantes pueden extraer valores agrupados, interceptar tráfico en dispositivos comprometidos y reproducir tokens. Estas reglas definen la barra mínima antes del envío a tienda.
- Completa Tier 1 antes de que se fusione la primera función de autenticación o pago - la seguridad de almacenamiento de retrofit es dolorosa y a menudo falla casos extremos.
- Revisa Tiers 2-3 en cualquier PR que toque variables de entorno, almacenamiento, redes o claves de SDK de terceros.
- Ejecuta Tier 4 en la checklist de lanzamiento -
expo config --type public y los flujos de logout son fallas de auditoría comunes.
- Las excepciones de fijación de certificados y saltos requieren un ADR con modelo de amenaza - no es un atajo de fin de sprint.
- Coordina con el equipo backend en tiempos de vida de token y revocación - las reglas solo del cliente no detienen el secuestro de sesión.
-
Nunca pongas secretos en EXPO_PUBLIC_* o extra: Ambos se insertan en línea en el bundle del cliente - los atacantes los extraen del IPA/APK o bytecode de Hermes.
- Solo público: IDs de cliente de análisis destinados a exposición, URLs de base de API pública, claves de banderas de características diseñadas para SDKs del lado del cliente.
- Servidor: Intenciones de pago, tokens de admin y secretos de firma permanecen en backend y EAS Secrets solo para hooks de compilación.
-
EAS Secrets para valores de tiempo de compilación y CI: eas secret:create y variables de alcance de entorno - no Slack, no .env.production comprometido.
- Extrae localmente:
eas env:pull --environment development - .env.local se mantiene gitignored.
- OTA:
eas update --environment production usa variables de entorno de EAS (SDK 55+) - .env local se ignora en ejecutores de actualización.
-
Audita configuración pública antes de cada lanzamiento: npx expo config --type public - confirma que no hay URLs de staging, nombres de host internos ni claves de depuración enviados al perfil de producción.
- CI: El script falla el trabajo de lanzamiento si aparecen substrings prohibidos en la salida de configuración pública.
- Rechaza: "Eliminaremos la URL de staging en una PR de seguimiento."
-
.env.example documenta claves, no valores: Lista variables EXPO_PUBLIC_* y APP_ENV requeridas con valores de placeholder - incorporación sin filtrar secretos de prod.
- Rota: Si se comprometió alguna vez un secreto, rota inmediatamente - el historial de git lo retiene.
- Escanea: Habilita escaneo de secretos en GitHub para commits accidentales.
-
Sin secretos en registros de caída o migas de análisis: Las utilidades de Sentry y logging deben limpiar tokens, correos electrónicos y fragmentos de PAN antes de cargarse.
- Patrón: Redacta encabezados
Authorization en migas de red.
- Prueba: Desencadena un crash de prueba en staging e inspecciona la carga útil de Sentry.
-
Las claves de SDK de terceros se revisan para exposición del cliente: Las claves de mapas, análisis y atribución en el bundle se asumen públicas - restringe por ID de bundle y plataforma en el panel del proveedor.
- Rechaza: Usar una clave secreta de Stripe solo para servidor en código React Native.
- ADR: Documenta la recopilación de datos de cada SDK de terceros para alineación de política de privacidad.
-
Tokens de actualización y acceso en expo-secure-store: Almacén de claves respaldado por hardware en dispositivos compatibles - no AsyncStorage, MMKV sin encriptar o archivos simples de expo-file-system.
- Instala:
npx expo install expo-secure-store.
- Límites de tamaño: El almacenamiento seguro es para tokens y pequeños secretos - no grandes blobs JSON.
-
AsyncStorage solo para preferencias no sensibles: Tema, última pestaña, estado del UI de borrador - nunca artefactos de autenticación o cachés de PII.
- Migración: Mover tokens de AsyncStorage a almacenamiento seguro requiere una migración única en actualización de aplicación.
- Auditoría: Grep para
AsyncStorage.setItem con claves tipo token en revisión de PR.
-
Limpia almacenamiento seguro al cerrar sesión: SecureStore.deleteItemAsync para todas las claves de auth - emparejadas con reinicio de pila de navegación (ver Navigation & Routing Rules).
- Prueba: Logout - matar app - relanzar - sin llamadas API autenticadas.
- Rechaza: Logout que solo limpia estado React.
-
Tokens de acceso de corta vida con rotación de actualización: Los clientes móviles deben actualizarse de forma proactiva - maneja 401 con un único reintento, no bucles infinitos.
- Background: Actualiza en foreground de
AppState si el token se acerca al vencimiento.
- Revocación: Revoca del lado del servidor al cerrar sesión y cambio de contraseña.
-
Puerta biométrica para acciones sensibles, no reemplazo de almacenamiento: expo-local-authentication desbloquea UI o confirma transacciones - no reemplaza almacenamiento de enclave seguro para tokens.
- UX: Re-solicitud biométrica opcional antes de mostrar números de tarjeta completos o exportar.
- Fallback: PIN o re-auth cuando la biometría falla.
-
Encripta cachés offline que contienen PII: Si MMKV o SQLite cachean datos de salud o financieros del usuario, usa encriptación o minimización del lado del servidor - MMKV por defecto es rápido, no confidencial.
- Prefiere: Obtén bajo demanda; cachea solo vistas derivadas no sensibles.
- ADR: Documenta alcance de PII offline para revisores de cumplimiento.
-
Solo HTTPS para llamadas API de producción: Rechaza excepciones de texto plano en app.config de producción - android.usesCleartextTraffic es solo para compilaciones de desarrollo local.
- Dev:
http://localhost en perfil de desarrollo con APP_ENV=development.
- CI: Lint o grep bloquea
http:// en src/ fuera de __tests__.
-
La fijación de certificados es una decisión explícita de producto: Por defecto a validación de certificado del sistema en SDK 57 - la fijación rompe proxies corporativos, complica la rotación y requiere módulos nativos.
- Cuándo fijar: Aplicaciones de alto riesgo (finanzas, salud) con equipo de seguridad para operar runbooks de rotación.
- ADR requerida: Modelo de amenaza, procedimiento de rotación y fallback cuando vencen los pins.
-
Si fijas, planifica la rotación antes de la implementación: Fija hashes SPKI con pins de respaldo - las actualizaciones almacenadas se retrasan semanas; los pins vencidos rompen la aplicación.
- Nativo: Las bibliotecas de fijación necesitan recompilaciones de dev-client - no solo OTA.
- Monitor: Alerta 30 días antes de renovación de certificado.
-
Valida TLS en la capa del cliente API: El wrapper central fetch rechaza no-HTTPS en compilaciones de producción - un único punto de control para encabezados y adición de auth.
- Patrón:
api/client.ts adjunta portador desde almacenamiento seguro; las características nunca llaman fetch sin formato a URLs arbitrarias.
- Rechaza:
fetch(process.env.EXPO_PUBLIC_API_URL + path) dispersas sin validación.
-
No desactives verificación SSL en producción: rejectUnauthorized: false y agentes fetch personalizados son solo depuración - grep CI los bloquea en main.
- Staging: Usa certificados de staging adecuados, no verificación deshabilitada.
- Charles proxy: Documenta configuración de proxy solo para dev; nunca envíes almacenes de confianza de proxy a prod.
-
OAuth y enlaces profundos usan PKCE y parámetros de estado: expo-auth-session con redirección segura - valida state en retorno; nunca incrustes secretos de cliente en flujos OAuth móviles.
- Redirección: Los esquemas registrados coinciden con
app.config - sin URIs de redirección comodín en consola del proveedor.
- Almacén: Tokens a través de almacenamiento seguro después del intercambio de código.
-
La detección de jailbreak/root impulsada por política, no teatro de seguridad: Si es requerida por cumplimiento, usa un SDK mantenido y documenta limitaciones de bypass - no afirmes "imposible de hackear."
- Graceful: Advierte o limita características; evita crash duro que atrapia usuarios de poder legítimos.
- ADR: Cita de requisito de cumplimiento.
-
Política de captura de pantalla y grabación de pantalla para pantallas sensibles: iOS UITextField bandera segura u overlay para entrada de CVV - equilibra UX con guía PCI e HIPAA.
- Android:
FLAG_SECURE a través de plugin de config cuando es obligatorio.
- Prueba: Captura de pantalla de pantallas sensibles en matriz de QA.
-
Permisos son mínimos y justificados: Solicita cámara, ubicación y contactos solo cuando la característica está activa - la revisión de iOS/Android y la confianza del usuario dependen de ello.
- Strings: Justificación de permiso visible para el usuario en
app.config y locales/ localizados.
- Rechaza: Bombardeo de alfombra de permiso anticipado en primer lanzamiento.
-
Auditoría de dependencias antes del envío a tienda: npm audit, expo-doctor y revisión de manifiestos de privacidad de SDK nativos (Etiquetas de Nutrición de Privacidad de Apple).
- Cadena de suministro: Fija lockfile; revisa nuevas dependencias nativas en PRs sensibles a seguridad.
- Actualizaciones: Parcha CVEs críticos en dependencias JS a través de OTA cuando no se requiere bump nativo.
-
Las banderas de características no eluden la autorización del servidor: Las banderas de cliente ocultan UI - el servidor debe aplicar derechos en cada mutación.
- OTA: Un usuario malicioso puede cargar bundles antiguos - la API es la fuente de verdad.
- Ver: Release & OTA Rules para reversión de canal en banderas deficientes.
-
Runbook de incidentes para compromiso de token y clave: Documenta quién rota EAS Secrets, revoca clientes OAuth y fuerza logout - los líderes móviles conocen los pasos antes de un incidente.
- Fuerza logout: Servidor invalida refresh tokens; envía banner OTA si es necesario.
- Postmortem: Actualiza esta checklist cuando una regla habría prevenido el incidente.
- Tier 1 (1-6): Secretos y config - radio de impacto más alto; arregla antes de que código de red se envíe.
- Tier 2 (7-12): Almacenamiento y sesiones - previene robo de token y bugs de logout.
- Tier 3 (13-18): Transporte - los defaults usualmente son suficientes; la fijación es la excepción con papeleo.
- Tier 4 (19-24): Cumplimiento y operaciones - bloquea envío a tienda y preparación de incidentes.
¿Puedo poner claves de API en EXPO_PUBLIC_?
Solo si la clave está diseñada para exposición del cliente (p. ej., clave de cliente de Google Maps restringida por ID de bundle). Secretos del servidor, claves secretas de Stripe y tokens de admin nunca pertenecen en EXPO_PUBLIC_*.
¿Almacenamiento seguro vs MMKV encriptado?
Por defecto a expo-secure-store para tokens en SDK 57. MMKV con encriptación es una opción para datos estructurados más grandes - aún requiere un ADR y una historia de gestión de claves; el almacenamiento seguro es más simple para artefactos de auth.
¿Deberíamos implementar fijación de certificados?
La mayoría de aplicaciones no deberían fijar inicialmente - TLS del sistema más ciclo de vida de certificado adecuado en el servidor es suficiente. Fija cuando el modelo de amenaza y operaciones de seguridad puedan poseer la rotación; documenta en un ADR.
¿Cómo difieren EAS Secrets de EXPO_PUBLIC_?
EAS Secrets y variables de entorno se inyectan en tiempo de compilación/actualización en trabajadores de EAS - no significan automáticamente seguro para bundles del cliente. Solo valores no sensibles deberían alcanzar JS a través de extra o env público. Los secretos verdaderos permanecen del lado del servidor.
¿Es Expo Go seguro para probar flujos de auth?
Expo Go usa el identificador de bundle de Expo - la redirección de OAuth y algunas restricciones de SDK difieren de producción. Prueba auth en dev-client o compilaciones de preview con tu ID de bundle real antes del lanzamiento.
¿Cómo verifico que nada secreto se filtró?
Ejecuta npx expo config --type public con variables de entorno de producción e inspecciona la salida. Agrega CI grep para patrones como sk_live, BEGIN PRIVATE KEY y nombres de host internos.
¿Qué se limpia al logout?
Claves de auth de almacenamiento seguro, estado de sesión en memoria, cachés de consulta con PII y pila de navegación a auth - en ese orden. Verifica con prueba automatizada o Maestro smoke.
¿Pueden las actualizaciones OTA arreglar una filtración de secreto?
OTA puede eliminar una clave filtrada de nuevos bundles - pero instalaciones existentes pueden retener bundles antiguos hasta la actualización. Rota el secreto comprometido inmediatamente en el servidor; trata OTA como corrección de distribución, no rotación.
¿Necesito detección de jailbreak?
Solo cuando cumplimiento o política de fraude lo requiere - entiende que es eludible. Documenta limitaciones en ADR; no confíes en ello para autorización central.
¿Cuánto deberían vivir los tokens de acceso?
Corta (minutos a decenas bajas de minutos) con rotación de actualización - las aplicaciones móviles son instalaciones de larga vida. Coordina lógica de actualización con manejadores de AppState background.
¿Son parámetros de consulta de enlace profundo seguros para auth?
No - trata parámetros de URL como entrada no confiable. Nunca otorgues privilegios de ?role=admin. Valida sesión del lado del servidor.
¿Qué hay sobre almacenar imágenes con PII?
Evita cachear imágenes sensibles en disco sin encriptación. Usa URLs firmadas que expiren y limpia cachés al logout.
¿Cambia la Nueva Arquitectura de React Native las reglas de seguridad?
No - los secretos aún se envían en bundles, las APIs de almacenamiento seguro son iguales. Mantén la misma checklist en RN 0.86.
Versiones de Stack: Esta página fue escrita para React 19.2.3, React Native 0.86.0 y Expo SDK 57 (expo ~57.0.4).