Sandboxing — el pilar fundamental

Android asigna a cada app un UID único de Linux al instalarla. El kernel garantiza que los procesos de diferentes apps no puedan acceder a la memoria ni a los archivos de otras apps. Esta es la primera y más sólida barrera de seguridad.

El resultado práctico: incluso si una app maliciosa se instala en el dispositivo, no puede leer los datos de tu app bancaria, tu historial de mensajes ni tus fotos — a menos que haya una vulnerabilidad en el kernel o en el sistema de archivos.

# Cada app tiene su propio UID:
# u0_a123 → com.ejemplo.miapp
# u0_a124 → com.banco.app
# u0_a125 → com.red.social

# Los archivos de cada app son propiedad de su UID:
ls -la /data/data/
# drwx------ u0_a123 u0_a123  com.ejemplo.miapp/
# drwx------ u0_a124 u0_a124  com.banco.app/
# Solo el propio proceso (o root) puede leer estos directorios

Modelo de permisos

Los permisos en Android son contratos declarados en el Manifest. Hay tres niveles:

  • Normal: se otorgan automáticamente sin preguntarle al usuario. Bajo riesgo (INTERNET, VIBRATE, SET_ALARM).
  • Dangerous: el usuario debe aprobarlos en runtime. Acceden a datos sensibles (cámara, contactos, ubicación, micrófono, almacenamiento).
  • Signature: solo se otorgan a apps firmadas con el mismo keystore. Usados por apps del sistema y grupos de apps del mismo desarrollador.

Declarar no es tenerDeclarar un permiso en el Manifest no garantiza tenerlo. Los permisos "dangerous" hay que pedirlos en runtime y el usuario puede denegarlos. Siempre verificá con checkSelfPermission() antes de usarlos.

Almacenamiento aislado (Scoped Storage)

Desde Android 10, las apps tienen acceso limitado al almacenamiento externo:

  • Almacenamiento interno (filesDir, cacheDir): privado a la app. Nadie más puede leerlo (salvo root o el propio sistema en backups).
  • Almacenamiento externo propio (getExternalFilesDir()): accesible sin permiso, pero solo por la propia app.
  • MediaStore: acceso a fotos, videos y audio del usuario a través de APIs controladas.
  • Documentos externos: requiere que el usuario elija explícitamente con el picker del sistema.
// Almacenamiento interno — privado, seguro, sin permisos
val archivo = File(filesDir, "datos_sensibles.json")

// NO usar getExternalStorageDirectory() — deprecated y accesible por otras apps
// NO guardar datos sensibles en el almacenamiento externo

Qué protege el SO (y qué no)

El SO de Android protege:

  • Aislamiento entre apps (sandboxing)
  • Comunicación entre procesos controlada (Binder IPC)
  • Arranque verificado (Verified Boot) — integridad del SO en el arranque
  • Cifrado del dispositivo (Full-disk o File-Based Encryption)

Lo que no protege automáticamente y es responsabilidad del desarrollador:

  • Datos en tránsito — vos debés usar HTTPS y validarlo correctamente
  • Datos en reposo sensibles dentro del almacenamiento interno — el SO los aísla pero no los cifra
  • Tokens y contraseñas en SharedPreferences en texto plano
  • Logs que contienen información sensible
  • Claves hardcodeadas en el código fuente
  • Comportamiento en dispositivos rooteados

Las amenazas más comunes

# 1. Datos sensibles en texto plano
#    Token de sesión guardado en SharedPreferences sin cifrar
#    → EncryptedSharedPreferences (lección 03)

# 2. Tráfico HTTP o HTTPS mal validado
#    Man-in-the-middle con cert falso en redes corporativas/cafés
#    → Network Security Config + Certificate Pinning (lecciones 04 y 05)

# 3. Información sensible en logs
#    Log.d("TOKEN", token)  ← visible en adb logcat
#    → Nunca loggear datos sensibles, deshabilitar logs en release

# 4. Backup automático de datos sensibles
#    Por default Android incluye filesDir en el backup de Google
#    → Configurar android:allowBackup y android:fullBackupContent

# 5. Claves hardcodeadas
#    val API_KEY = "sk-1234..."  ← visible con strings en el APK
#    → Variables de entorno en build, no en código

# 6. Contenido de Activity expuesto
#    android:exported="true" sin restricciones
#    → Revisar exported en el Manifest

Defensa en capas

La seguridad real no viene de una sola medida — viene de capas. Si una falla, las otras siguen protegiendo:

# Capa 1: HTTPS + Certificate Pinning
#   → Protege datos en tránsito

# Capa 2: EncryptedSharedPreferences + EncryptedFile
#   → Protege datos sensibles en reposo

# Capa 3: Keystore para claves criptográficas
#   → Las claves nunca salen del hardware seguro

# Capa 4: Detección de root/emulador
#   → Reduce la superficie de ataque

# Capa 5: ProGuard/R8 + anti-tampering
#   → Dificulta el reverse engineering

# Ninguna capa es infalible sola.
# La combinación es lo que hace una app segura.