Sandbox de aplicativos

A plataforma Android aproveita a proteção baseada no usuário do Linux para identificar e isolar os recursos do app. Isso isola os apps uns dos outros e protege os apps e o sistema contra apps maliciosos. Para fazer isso, o Android atribui um ID de usuário exclusivo (UID) a cada app Android e o executa no próprio processo.

O Android usa o UID para configurar um sandbox de aplicativo no nível do kernel. O kernel reforça a segurança entre apps e o sistema no nível do processo por meio de recursos padrão do Linux, como IDs de usuário e de grupo atribuídos a apps. Por padrão, os apps não podem interagir entre si e têm acesso limitado ao SO. Se o app A tentar fazer algo malicioso, como ler os dados do app B ou discar o telefone sem permissão, ele não poderá fazer isso porque não tem os privilégios de usuário padrão adequados. O sandbox é simples, auditável e baseado na separação de processos e permissões de arquivos do estilo UNIX, que existe há décadas.

Como o sandbox do aplicativo está no kernel, esse modelo de segurança se estende ao código nativo e aos apps do SO. Todos os softwares acima do kernel, como bibliotecas do SO, framework do app, ambiente de execução do app e todos os apps, são executados no sandbox do aplicativo. Em algumas plataformas, os desenvolvedores são restritos a um framework de desenvolvimento, conjunto de APIs ou língua específicos. No Android, não há restrições sobre como um app pode ser escrito para aplicar a segurança. Nesse sentido, o código nativo é colocado em sandbox como código interpretado.

Proteções

Geralmente, para sair do sandbox de aplicativos em um dispositivo configurado corretamente, é necessário comprometer a segurança do kernel do Linux. No entanto, semelhante a outros recursos de segurança, as proteções individuais que aplicam o sandbox do app não são invulneráveis. Portanto, a defesa em profundidade é importante para evitar que vulnerabilidades únicas comprometam o SO ou outros apps.

O Android depende de várias proteções para aplicar o sandbox do app. Essas restrições foram introduzidas ao longo do tempo e fortaleceram significativamente o sandbox de controle de acesso discricionário (DAC, na sigla em inglês) baseado em UID. As versões anteriores do Android incluíam as seguintes proteções:

  • No Android 5.0, o SELinux oferecia separação de controle de acesso obrigatório (MAC) entre o sistema e os apps. No entanto, todos os apps de terceiros eram executados no mesmo contexto do SELinux, então o isolamento entre apps era aplicado principalmente pelo UID DAC.
  • No Android 6.0, o sandbox do SELinux foi estendido para isolar apps no limite por usuário físico. Além disso, o Android também definiu padrões mais seguros para dados de apps: para apps com targetSdkVersion >= 24, as permissões DAC padrão no diretório principal de um app foram alteradas de 751 para 700. Isso forneceu um padrão mais seguro para dados de apps particulares, embora os apps possam substituir esses padrões.
  • No Android 8.0, todos os apps foram configurados para serem executados com um filtro seccomp-bpf que limitava as syscalls que os apps podiam usar, fortalecendo a fronteira entre o app e o kernel.
  • No Android 9, todos os apps não privilegiados com targetSdkVersion >= 28 precisam ser executados em sandboxes SELinux individuais, fornecendo MAC por app. Essa proteção melhora a separação de apps, impede a substituição de padrões seguros e, mais importante, impede que os apps tornem os dados acessíveis.
  • No Android 10, os apps têm uma visualização bruta limitada do sistema de arquivos, sem acesso direto a caminhos como /sdcard/DCIM. No entanto, os apps mantêm acesso bruto completo aos caminhos específicos do pacote, quando retornados por métodos aplicáveis, como Context.getExternalFilesDir().

Diretrizes para compartilhar arquivos

Definir os dados do app como acessíveis para todo o mundo é uma prática de segurança ruim. O acesso é concedido a todos, e não é possível limitar o acesso apenas aos destinatários intencionais. Essa prática levou a vazamentos de informações e vulnerabilidades de subdelegação, e é o alvo preferido de malwares que visam apps com dados sensíveis (como clientes de e-mail). No Android 9 e versões mais recentes, o compartilhamento de arquivos dessa maneira é explicitamente proibido para apps com targetSdkVersion>=28.

Em vez de tornar os dados do app acessíveis em todo o mundo, use as seguintes diretrizes ao compartilhar arquivos:

  • Se o app precisar compartilhar arquivos com outro app, use um provedor de conteúdo. Os provedores de conteúdo compartilham dados com a granularidade adequada e sem as muitas desvantagens das permissões de acesso universal do UNIX. Para saber mais, consulte Fundamentos do provedor de conteúdo.
  • Se o app tiver arquivos que realmente precisam ser acessíveis para todos (como fotos), eles precisam ser específicos de mídia (somente fotos, vídeos e arquivos de áudio) e armazenados usando a classe MediaStore. Para mais detalhes sobre como adicionar um item de mídia, consulte Acessar arquivos de mídia do armazenamento compartilhado.

A permissão de tempo de execução Armazenamento controla o acesso a coleções com tipo forte usando a MediaStore. Para acessar arquivos com tipificação fraca, como PDFs e a classe MediaStore.Downloads, os apps precisam usar intents como a ACTION_OPEN_DOCUMENT.

Para ativar o comportamento do Android 10, use o atributo de manifesto requestLegacyExternalStorage e siga as práticas recomendadas de permissões do app.

  • O valor padrão da flag do manifesto é true para apps destinados ao Android 9 (e versões anteriores).
  • O valor padrão é falso para apps destinados ao Android 10. Para desativar temporariamente a visualização de armazenamento filtrado em apps direcionados ao Android 10, defina o valor da flag do manifesto como true.
  • Usando permissões restritas, o instalador autoriza apps com permissão para armazenamento sem sandbox. Os apps que não estão na lista são colocados em sandbox.