Skip to content

MASTG-KNOW-0042: Armazenamento Externo

Os dispositivos Android suportam armazenamento externo compartilhado. Esse armazenamento pode ser removível (como um cartão SD) ou emulado (não removível). Um aplicativo malicioso com as permissões adequadas executado no Android 10 ou inferior pode acessar dados que você grava em diretórios específicos do aplicativo "externos". O usuário também pode modificar esses arquivos quando o armazenamento em massa USB está habilitado.

Os arquivos armazenados nesses diretórios são removidos quando seu aplicativo é desinstalado.

O armazenamento externo deve ser usado com cuidado, pois existem muitos riscos associados a ele. Por exemplo, um invasor pode recuperar dados sensíveis ou obter controle arbitrário do aplicativo.

Diretrizes de segurança do Android: O Android recomenda não armazenar dados sensíveis no armazenamento externo e realizar validação de entrada em todos os dados armazenados no armazenamento externo. Consulte as Diretrizes de segurança do Android. O Android também fornece um guia sobre como usar o armazenamento externo com segurança.

Armazenamento com Escopo (Scoped Storage)

Para dar aos usuários mais controle sobre seus arquivos e limitar a desorganização de arquivos, os aplicativos que têm como destino o Android 10 (API level 29) e superior recebem acesso com escopo ao armazenamento externo, ou armazenamento com escopo, por padrão. Quando o armazenamento com escopo está habilitado, os aplicativos não podem acessar os diretórios específicos de aplicativos que pertencem a outros aplicativos.

A documentação de desenvolvedores Android fornece um guia detalhado destacando casos de uso de armazenamento e melhores práticas comuns, diferenciando o tratamento de arquivos de mídia e não mídia e considerando o armazenamento com escopo.

Optando por não usar: Aplicativos com destino ao Android 10 (API level 29) ou inferior podem optar temporariamente por não usar o armazenamento com escopo usando android:requestLegacyExternalStorage="true" em seu manifesto do aplicativo. Uma vez que o aplicativo tem como destino o Android 11 (API level 30), o sistema ignora o atributo requestLegacyExternalStorage quando executado em dispositivos Android 11.

Atribuição de aplicativo para arquivos de mídia (Desenvolvedores Android): Quando o armazenamento com escopo está habilitado para um aplicativo que tem como destino o Android 10 ou superior, o sistema atribui um aplicativo a cada arquivo de mídia, o que determina os arquivos que seu aplicativo pode acessar quando não solicitou nenhuma permissão de armazenamento. Cada arquivo pode ser atribuído a apenas um aplicativo. Portanto, se seu aplicativo criar um arquivo de mídia armazenado na coleção de mídia de fotos, vídeos ou arquivos de áudio, seu aplicativo terá acesso ao arquivo.

No entanto, se o usuário desinstalar e reinstalar seu aplicativo, você deve solicitar READ_EXTERNAL_STORAGE para acessar os arquivos que seu aplicativo originalmente criou. Essa solicitação de permissão é necessária porque o sistema considera o arquivo atribuído à versão anteriormente instalada do aplicativo, em vez da recém-instalada.

Por exemplo, tentar acessar um arquivo armazenado usando a API MediaStore com um URI content:// como content://media/external_primary só funcionará enquanto a imagem pertencer ao aplicativo invocador (devido ao atributo owner_package_name no MediaStore). Se o aplicativo chamar um URI content:// que não pertence ao aplicativo, ele falhará com uma SecurityException:

Cannot open content uri: content://media/external_primary/images/media/1000000041
java.lang.SecurityException: org.owasp.mastestapp has no access to content://media/external_primary/images/media/1000000041

Você pode validar isso consultando o MediaStore via adb, por exemplo:

  • adb shell content query --uri content://media/external_primary/images/media
  • adb shell content query --uri content://media/external_primary/file

Para poder acessar o conteúdo, o aplicativo deve ter as permissões necessárias, por exemplo, READ_EXTERNAL_STORAGE antes do Android 10 (API level 29), READ_MEDIA_IMAGES ou MANAGE_EXTERNAL_STORAGE a partir do Android 10 (API level 29) em diante.

READ_EXTERNAL_STORAGE está obsoleto (e não é concedido) quando o destino é Android 13 (API level 33) e superior. Se você precisa consultar ou interagir com o MediaStore ou arquivos de mídia no armazenamento compartilhado, você deve usar uma ou mais das novas permissões de armazenamento: READ_MEDIA_IMAGES, READ_MEDIA_VIDEO ou READ_MEDIA_AUDIO.

O armazenamento com escopo é aplicado a partir do Android 10 (API level 29) (ou Android 11 se usando requestLegacyExternalStorage). Em particular, WRITE_EXTERNAL_STORAGE não fornecerá mais acesso de gravação a todos os arquivos; em vez disso, fornecerá o equivalente a READ_EXTERNAL_STORAGE.

A partir do Android 13 (API level 33), se você precisa consultar ou interagir com o MediaStore ou arquivos de mídia no armazenamento compartilhado, você deve usar uma ou mais das novas permissões de armazenamento: READ_MEDIA_IMAGES, READ_MEDIA_VIDEO ou READ_MEDIA_AUDIO.

Após declarar a permissão no manifesto, você pode concedê-la com adb:

adb shell pm grant org.owasp.mastestapp android.permission.READ_MEDIA_IMAGES

Você pode revogar a permissão com:

adb shell pm revoke org.owasp.mastestapp android.permission.READ_MEDIA_IMAGES

APIs de Armazenamento Externo

Existem APIs como getExternalStoragePublicDirectory que retornam caminhos para um local compartilhado que outros aplicativos podem acessar. Um aplicativo pode obter um caminho para um local "externo" e gravar dados sensíveis nele. Esse local é considerado "Armazenamento Compartilhado que Não Requer Interação do Usuário", o que significa que um aplicativo de terceiros com as permissões adequadas pode ler esses dados sensíveis.

Por exemplo, o seguinte snippet em Kotlin armazena informações sensíveis em texto claro em um arquivo password.txt localizado no armazenamento externo.

val password = "SecretPassword"
val path = context.getExternalFilesDir(null)
val file = File(path, "password.txt")
file.appendText(password)

API MediaStore

A API MediaStore fornece uma maneira para os aplicativos interagirem com dois tipos de arquivos armazenados no dispositivo:

  • arquivos de mídia, incluindo imagens (MediaStore.Images), vídeos (MediaStore.Video), áudio (MediaStore.Audio) e downloads (MediaStore.Downloads), e
  • arquivos não de mídia (por exemplo, texto, HTML, PDF, etc.) armazenados na coleção MediaStore.Files.

O uso dessa API requer um objeto ContentResolver recuperado do Context do aplicativo. Veja um exemplo na documentação de desenvolvedores Android.

Aplicativos em execução no Android 9 (API level 28) ou inferior:

  • Eles podem acessar os arquivos específicos do aplicativo que pertencem a outros aplicativos se optaram por não usar o armazenamento com escopo e solicitaram a permissão READ_EXTERNAL_STORAGE.
  • Para modificar os arquivos, o aplicativo também deve solicitar a permissão WRITE_EXTERNAL_STORAGE.

Aplicativos em execução no Android 10 (API level 29) ou superior:

  • Acessando próprios arquivos de mídia:

    • Os aplicativos podem sempre acessar seus próprios arquivos de mídia armazenados usando a API MediaStore sem precisar de nenhuma permissão relacionada ao armazenamento. Isso inclui arquivos nos diretórios específicos do aplicativo dentro do armazenamento externo (armazenamento com escopo) e arquivos no MediaStore que o aplicativo criou.
  • Acessando arquivos de mídia de outros aplicativos:

    • Os aplicativos requerem certas permissões e APIs para acessar arquivos de mídia que pertencem a outros aplicativos.
    • Se o armazenamento com escopo estiver habilitado, os aplicativos não podem acessar os arquivos de mídia específicos do aplicativo que pertencem a outros aplicativos. No entanto, se o armazenamento com escopo estiver desabilitado, os aplicativos podem acessar os arquivos de mídia específicos do aplicativo que pertencem a outros aplicativos usando a consulta MediaStore.Files.
  • Acessando downloads (coleção MediaStore.Downloads):

Permissões do Manifesto

O Android define as seguintes permissões para acessar o armazenamento externo: READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE e MANAGE_EXTERNAL_STORAGE.

Um aplicativo deve declarar no arquivo Android Manifest a intenção de gravar em locais compartilhados. Abaixo você pode encontrar uma lista de tais permissões de manifesto:

  • READ_EXTERNAL_STORAGE: permite que um aplicativo leia do armazenamento externo.

    • Antes do Android 4.4 (API level 19), esta permissão não é aplicada e todos os aplicativos têm acesso para ler todo o armazenamento externo (incluindo arquivos de outros aplicativos).
    • A partir do Android 4.4 (API level 19), os aplicativos não precisam solicitar esta permissão para acessar seus próprios diretórios específicos do aplicativo dentro do armazenamento externo.
    • A partir do Android 10 (API level 29), o armazenamento com escopo se aplica por padrão:
      • Os aplicativos não podem ler os diretórios específicos do aplicativo que pertencem a outros aplicativos (o que era possível antes quando se tinha READ_EXTERNAL_STORAGE concedido).
      • Os aplicativos não precisam ter esta permissão para ler arquivos de seus próprios diretórios específicos do aplicativo dentro do armazenamento externo (armazenamento com escopo), ou seus próprios arquivos no MediaStore.
    • A partir do Android 13 (API level 33), esta permissão não tem efeito. Se for necessário acessar arquivos de mídia de outros aplicativos, os aplicativos devem solicitar uma ou mais destas permissões: READ_MEDIA_IMAGES, READ_MEDIA_VIDEO ou READ_MEDIA_AUDIO.
  • WRITE_EXTERNAL_STORAGE: permite que um aplicativo grave um arquivo no "armazenamento externo", independentemente da origem real do armazenamento (disco externo ou internamente emulado pelo sistema).

    • A partir do Android 4.4 (API level 19), os aplicativos não precisam solicitar esta permissão para acessar seus próprios diretórios específicos do aplicativo dentro do armazenamento externo.
    • A partir do Android 10 (API level 29), o armazenamento com escopo se aplica por padrão:
      • Os aplicativos não podem gravar nos diretórios específicos do aplicativo que pertencem a outros aplicativos (o que era possível antes quando se tinha WRITE_EXTERNAL_STORAGE concedido).
      • Os aplicativos não precisam desta permissão para gravar arquivos em seus próprios diretórios específicos do aplicativo dentro do armazenamento externo.
    • A partir do Android 11 (API level 30), esta permissão está obsoleta e não tem efeito, mas pode ser preservada com requestLegacyExternalStorage e preserveLegacyExternalStorage.
  • MANAGE_EXTERNAL_STORAGE: Alguns aplicativos requerem acesso amplo a todos os arquivos.

    • Esta permissão só se aplica a aplicativos com destino ao Android 11.0 (API level 30) ou superior.
    • O uso desta permissão é restringido pelo Google Play, a menos que o aplicativo satisfaça determinados requisitos e requira acesso especial de aplicativo chamado "Acesso a todos os arquivos".
    • O armazenamento com escopo não afeta a capacidade do aplicativo de acessar diretórios específicos do aplicativo quando tem esta permissão.
  • READ_MEDIA_IMAGES, READ_MEDIA_VIDEO e READ_MEDIA_AUDIO: permitem que um aplicativo leia arquivos de mídia da coleção MediaStore.

    • A partir do Android 13 (API level 33), uma vez que READ_EXTERNAL_STORAGE não tem efeito, estas permissões são necessárias para acessar arquivos de mídia das coleções MediaStore.Images, MediaStore.Video e MediaStore.Audio, respectivamente.