Register now for Android Dev Summit 2019!

Permissões do sistema

Padrões de design

Permissões

Vídeo

Google I/O 2015 — Permissões do Android M: Práticas recomendadas para desenvolvedores

O Android é um sistema operacional de privilégio separado em que cada aplicativo executa com uma identidade de sistema distinta (ID de grupo e de usuário do Linux). Partes do sistema também são separadas em identidades distintas. O Linux, por meio disso, isola os aplicativos uns dos outros e do sistema.

Recursos de segurança mais refinados adicionais são fornecidos por um mecanismo de “permissão” que impõe restrições nas operações específicas que um processo particular pode realizar e as permissões por URI para conceder acesso ad hoc a partes específicas de dados.

Este documento descreve como fazer os desenvolvedores de aplicativo podem usar os recursos de segurança fornecidos pelo Android. O projeto de código aberto do Android contém uma Visão geral da segurança do Android mais geral.

Arquitetura de segurança

Um dos pontos de projeto centrais da arquitetura de segurança do Android é que, por padrão, nenhum aplicativo tem permissão de realizar nenhuma operação que prejudique sobre outros aplicativos, o sistema operacional ou o usuário. Isso abrange a leitura e a gravação de dados privados do usuário (como contatos ou e-mails), leitura ou gravação dos arquivos de outro aplicativo, realização de acesso de rede, manter o dispositivo ativo etc.

Como cada aplicativo do Android opera em uma sandbox de processo, os aplicativos devem compartilhar explicitamente os recursos e os dados. Para isso, declaram-se as permissões necessárias para recursos adicionais não fornecidos pela sandbox básica. Os aplicativos declaram estaticamente as permissões que exigem e o sistema Android solicita o consentimento do usuário.

A sandbox do aplicativo não depende da tecnologia usada para compilar um aplicativo. Em particular, o Dalvik VM não é um limite de segurança, e qualquer aplicativo pode executar código nativo (confira o Android NDK). Todos os tipos de aplicativo — Java, nativo e híbrido — são colocados em sandbox da mesma forma e têm o mesmo grau de segurança.

Assinatura do aplicativo

É preciso assinar todos os APKs (arquivos .apk) com um certificado cuja chave privada seja mantida pelo desenvolvedor. Esse certificado identifica o autor do aplicativo. Não é necessário certificado não precisa ser inscrito por uma autoridade de certificação; ele é perfeitamente permissível e é comum aplicativos Android usar certificações assinadas automaticamente. O propósito dos certificados no Android é distinguir os autores dos aplicativos. Isto permite que o sistema conceda ou negue acesso de aplicativos a permissões de nível de assinatura e conceda ou negue a solicitação de um aplicativo para receber a mesma identidade do Linux como outro aplicativo.

Acesso de arquivo e IDs de usuário

No momento da instalação, o Android dá a cada pacote um ID de usuário distinto do Linux. A identidade permanece constante pela duração da vida do pacote no dispositivo. Em outro dispositivo, o mesmo pacote pode ter um UID diferente — o que importa é que cada pacote tenha um UID distinto em determinado dispositivo.

Como imposições de segurança acontecem no nível de processo, o código de qualquer dois pacotes não pode executar normalmente no mesmo processo, pois precisam executar como usuários de Linux distintos. É possível usar o atributo sharedUserId na tag do AndroidManifest.xml's manifest de cada pacote para atribuí-los ao mesmo ID de usuário. Assim, por motivos de segurança, os dois pacotes são tratados como sendo o mesmo aplicativo, com o mesmo ID de usuário e mesmas permissões de arquivo. Observe que, para reter a segurança, somente dois aplicativos com a mesma assinatura (e que solicitam o mesmo sharedUserId) receberão o mesmo ID de usuário.

Todos os dados armazenados por um aplicativo serão atribuídos ao ID de usuário deste aplicativo e, normalmente, ficam inacessíveis a outros pacotes. Ao criar um novo arquivo com getSharedPreferences(String, int), openFileOutput(String, int) ou openOrCreateDatabase(String, int, SQLiteDatabase.CursorFactory), é possível usar sinalizadores MODE_WORLD_READABLE e/ou MODE_WORLD_WRITEABLE para permitir que qualquer outro aplicativo leia/grave dados no arquivo. Ao definir esses sinalizadores, o arquivo ainda é mantido pelo aplicativo, mas suas permissões de leitura e/ou gravação globais são definidas adequadamente para que todos os outros aplicativos o vejam.

Uso de permissões

Os aplicativos básicos do Android não têm permissões associadas por padrão, o que significa que não podem fazer nada que prejudique a experiência do usuário ou os dados naquele dispositivo. Para usar os recursos protegidos do dispositivo, é preciso incluir uma ou mais tags <uses-permission> no manifesto do aplicativo.

Por exemplo, um aplicativo que precisa monitorar mensagens SMS recebidas especificaria:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.app.myapp" >
    <uses-permission android:name="android.permission.RECEIVE_SMS" />
    ...
</manifest>

Se o seu aplicativo lista permissões normais no seu manifesto (ou seja, permissões que não apresentam muito risco à privacidade do usuário nem à operação do dispositivo), o sistema automaticamente concede essas permissões. Se o seu aplicativo lista permissões perigosas no seu manifesto (ou seja, permissões que possam afetar a privacidade do usuário ou a operação do dispositivo), o sistema solicita ao usuário para conceder essas permissões explicitamente. A forma como o Android faz as solicitações depende da versão do sistema e da versão do sistema que o aplicativo quer:

  • Se o dispositivo está executando o Android 6.0 (nível da API 23) ou superior e o targetSdkVersion do aplicativo é 23 ou superior, o aplicativo solicita as permissões do usuário no momento da execução. O usuário pode revogar as permissões a qualquer momento, portanto o aplicativo precisa verificar se tem as permissões sempre que for executado. Para obter mais informações sobre solicitação de permissões no aplicativo, consulte o guia de treinamento Trabalho com permissões do sistema.
  • Se o dispositivo está executando Android 5.1 (nível da API 22) ou inferior ou o targetSdkVersion do aplicativo é 22 ou inferior, o sistema pede ao usuário que conceda a permissão quando da instalação do aplicativo. Se você adicionar uma nova permissão a uma versão atualizada do aplicativo, o sistema pedirá para que o usuário conceda essa permissão ao atualizar o aplicativo. Quando o usuário instala o aplicativo, a única forma de revogar a permissão é desinstalando o aplicativo.

Frequentemente, uma falha de permissão resultará em um SecurityException devolvido ao aplicativo. No entanto, não é garantido que isso aconteça em todos os casos. Por exemplo: o método sendBroadcast(Intent) verifica as permissões à medida que os dados são entregues a cada receptor, depois que a chamada ao método é retornada para que você não receba nenhuma exceção se houver falhas de permissão. Em quase todos os casos, no entanto, uma falha de permissão será impressa no registro do sistema.

As permissões fornecidas pelo sistema Android se encontram em Manifest.permission. Qualquer aplicativo pode também definir ou impor suas próprias permissões. Portanto, essa lista não abrange todas as permissões possíveis.

É possível impor uma permissão específica em alguns lugares durante a operação do seu programa:

  • No momento da chamada para o sistema, para evitar que um aplicativo execute determinadas funções.
  • Ao iniciar uma atividade, para evitar que aplicativos inicializem atividades de outros aplicativos.
  • Ao enviar e receber transmissões, para controlar quem recebe sua transmissão ou quem pode enviar uma transmissão ao usuário.
  • Ao acessar e operar em um provedor de conteúdo.
  • Ao iniciar ou vincular um serviço.

Ajustes de permissões automáticas

Com o tempo, podem-se adicionar novas restrições à plataforma de forma que, para usar determinadas APIs, o seu aplicativo precise solicitar uma permissão que não tinha anteriormente. Como os aplicativos existentes presumem que o acesso a essas APIs está livremente disponível, o Android pode aplicar a nova solicitação de permissão no manifesto do aplicativo para evitar erros na versão da nova plataforma. O Android decide se um aplicativo precisará da permissão com base no valor fornecido para o atributo targetSdkVersion. Se o valor é menor do que a versão a qual a permissão foi adicionada, o Android adiciona a permissão.

Por exemplo: a permissão WRITE_EXTERNAL_STORAGE foi adicionada no nível da API 4 para restringir o acesso ao espaço de armazenamento compartilhado. Se o targetSdkVersion é igual ou inferior a 3, essa permissão é adicionada ao seu aplicativo em versões mais recentes do Android.

Atenção: Se uma permissão é adicionada automaticamente ao aplicativo, a listagem do aplicativo no Google Play lista essas permissões adicionais mesmo que o aplicativo não as exija.

Para evitar isso e remover as permissões padrão desnecessárias, atualize sempre o targetSdkVersion para a versão mais recente possível. É possível ver as permissões adicionadas com cada lançamento na documentação Build.VERSION_CODES.

Permissões normais e perigosas

As permissões do sistema são divididas em vários níveis de proteção. Os dois níveis de proteção mais importantes que devem ser considerados são as permissões normais e perigosas:

  • Permissões normais cobrem áreas onde o seu aplicativo precisa acessar dados ou recursos fora da sandbox do aplicativo, mas apresenta pouco risco à privacidade do usuário ou à operação de outros aplicativos. Por exemplo: a permissão para definir o fuso horário é normal. Se um aplicativo declara que precisa de uma permissão normal, o sistema automaticamente concede a permissão ao aplicativo. Para obter uma listagem completa das permissões normais atuais, consulte Permissões normais.
  • Permissões perigosas abrangem áreas onde o aplicativo precisa de dados ou recursos que envolvem informações pessoais do usuário ou que podem afetar os dados armazenados do usuário ou a operação de outros aplicativos. Por exemplo: a capacidade de ler os contatos do usuário é uma permissão perigosa. Se um aplicativo declara que precisa de uma permissão perigosa, o usuário precisa conceder explicitamente a permissão ao aplicativo.

Grupos de permissões

Todas as permissões perigosas do sistema Android pertencem a grupos de permissão. Se um dispositivo está executando o Android 6.0 (nível da API 23) e a targetSdkVersion é 23 ou superior, o seguinte comportamento de sistema se aplica quando o aplicativo solicita uma permissão perigosa:

  • Se um aplicativo solicita uma permissão perigosa listada no seu manifesto e não tem nenhuma permissão no grupo de permissões, o sistema mostra uma caixa de diálogo ao usuário que descreve o grupo de permissões que o aplicativo quer acessar. A caixa de diálogo não descreve a permissão específica dentro do grupo. Por exemplo: se um aplicativo solicita a permissão READ_CONTACTS, a caixa de diálogo do sistema simplesmente dirá que o aplicativo precisa acessar os contatos do dispositivo. Se o usuário concede aprovação, o sistema dá ao usuário apenas a permissão que ele solicitou.
  • Se um aplicativo solicita uma permissão perigosa listada no seu manifesto e o aplicativo já tem outra permissão perigosa no mesmo grupo de permissões, o sistema imediatamente concede a permissão sem nenhuma interação com o usuário. Por exemplo: se um aplicativo já solicitou uma permissão e recebeu a permissão READ_CONTACTS e, em seguida, solicita WRITE_CONTACTS, o sistema imediatamente concede essa permissão.

Qualquer permissão pode pertencer a um grupo de permissões, inclusive permissões normais e permissões definidas pelo seu aplicativo. No entanto, os grupos de permissão só afetam a experiência do usuário se a permissão for perigosa. É possível ignorar um grupo de permissões pelas permissões normais.

Se o dispositivo está executando Android 5.1 (nível da API 22) ou inferior ou a targetSdkVersion do aplicativo é 22 ou inferior, o sistema pede ao usuário que conceda a permissão no momento da instalação. Mais uma vez, o sistema apenas diz ao usuário que grupos de permissões o aplicativo precisa, não as permissões individuais.

Tabela 1. Permissões perigosas e grupos de permissões.

Grupo de permissões Permissões
CALENDAR
CAMERA
CONTACTS
LOCATION
MICROPHONE
PHONE
SENSORS
SMS
STORAGE

Definir e impor permissões

Para impor suas próprias permissões, você deve primeiro declará-las no AndroidManifest.xml com um ou mais elementos <permission>.

Por exemplo, um aplicativo que controle quem inicia uma de suas atividades poderia declarar uma permissão para essa operação da seguinte forma:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp" >
    <permission android:name="com.example.myapp.permission.DEADLY_ACTIVITY"
        android:label="@string/permlab_deadlyActivity"
        android:description="@string/permdesc_deadlyActivity"
        android:permissionGroup="android.permission-group.COST_MONEY"
        android:protectionLevel="dangerous" />
    ...
</manifest>

Observação: O sistema não permite que vários pacotes declarem uma permissão de mesmo nome a não ser que todos os pacotes sejam assinados com o mesmo certificado. Se um pacote declara uma permissão, o sistema não permite que o usuário instale outros pacotes com o mesmo nome de permissão, exceto pelos pacotes assinados com o mesmo certificado que o primeiro pacote. Para evitar conflitos de nomes, recomendamos a nomeação no estilo de domínio reverso para permissões personalizadas, por exemplo: com.example.myapp.ENGAGE_HYPERSPACE.

O atributo protectionLevel é necessário para dizer ao sistema como informar o usuário sobre aplicativos que exigem a permissão ou quem tem permissão para manter essa permissão, como descrito no documento vinculado.

O atributo android:permissionGroup é opcional e somente usado para ajudar o sistema a exibir permissões ao usuário. Na maioria dos casos, você vai querer definir isso a um grupo de sistema padrão (listado em android.Manifest.permission_group), apesar de ser possível definir um grupo por conta própria. Recomendamos o uso de um grupo existente, pois simplifica a IU de permissão mostrada ao usuário.

Você precisará fornecer um rótulo e uma descrição para a permissão. Estes são alguns recursos de string que o usuário pode ver ao acessar uma lista de permissões (android:label) ou detalhes de uma única permissão (android:description). O rótulo deve ser curto — algumas palavras que descrevem a parte principal da funcionalidade que a permissão protege. A descrição deve conter algumas frases que descrevam o que a permissão concede ao retentor. Nossa referência é uma descrição de duas frases: a primeira frase descreve a permissão e, a segunda, avisa ao usuário o tipo de coisas que pode dar de errado se um aplicativo tiver a permissão.

Eis um exemplo de rótulo e descrição para a permissão CALL_PHONE:

<string name="permlab_callPhone">directly call phone numbers</string>
<string name="permdesc_callPhone">Allows the application to call
    phone numbers without your intervention. Malicious applications may
    cause unexpected calls on your phone bill. Note that this does not
    allow the application to call emergency numbers.</string>

É possível ver as permissões atualmente definidas no sistema usando o aplicativo Configurações e o comando de estrutura adb shell pm list permissions. Para usar o aplicativo Configurações, acesse Settings > Applications. Escolha um aplicativo e role para baixo para ver as permissões que ele usa. Para desenvolvedores, a opção adb '-s' exibe as permissões em uma forma semelhante a como o usuário as verá:

$ adb shell pm list permissions -s
All Permissions:

Network communication: view Wi-Fi state, create Bluetooth connections, full
Internet access, view network state

Your location: access extra location provider commands, fine (GPS) location,
mock location sources for testing, coarse (network-based) location

Services that cost you money: send SMS messages, directly call phone numbers

...

Recomendações de permissão personalizada

Os aplicativos podem definir as próprias permissões personalizadas e solicitar as de outros aplicativos definido os elementos <uses-permission>. No entanto, você deve avaliar cuidadosamente se é necessário que seu aplicativo faça isso.

  • Se estiver projetando um conjunto de aplicativos que exponha a funcionalidade um ao outro, tente projetar aplicativos para que cada permissão seja definida uma só vez. Você deve fazer isso se os aplicativos não estiverem assinado com os mesmos certificados. Mesmo se os aplicativos estiverem assinado com o mesmo certificado, a melhor prática é definir cada permissão apenas uma vez.
  • Se a funcionalidade só estiver disponível para aplicativos conectados com a mesma assinatura que o aplicativo fornecedor, você poderá usar verificações de assinatura para evitar definir permissões personalizadas. Quando um dos aplicativos faz uma solicitação a outro aplicativo, o segundo pode verificar se os dois estão assinados com o mesmo certificado antes de concordar com a solicitação.
  • Se você estiver desenvolvendo um conjunto de execuções de aplicativos apenas em dispositivos próprios, recomenda-se desenvolver e instalar um pacote que gerencia as permissões de todos os aplicativos no conjunto. Este pacote não precisa fornecer nenhum serviço. Ele só declara todas as permissões, e os outros aplicativos no conjunto solicitam essas permissões com o elemento <uses-permission>.

Impor permissões no AndroidManifest.xml

É possível aplicar permissões que restrinjam o acesso a componentes inteiros do sistema ou do aplicativo pelo AndroidManifest.xml. Para isso, inclua um atributo android:permission no componente desejado, nomeando a permissão que controla o acesso a ele.

Permissões Activity (aplicadas à tag <activity>) restringem quem pode iniciar a atividade associada. A permissão é verificada durante Context.startActivity() e Activity.startActivityForResult(); se o autor da chamada não tiver a permissão necessária, SecurityException é devolvido da chamada.

Permissões Service (aplicadas à tag <service>) restringem quem pode iniciar ou vincular o serviço associado. A permissão é verificada durante Context.startService(), Context.stopService() e Context.bindService(); se o autor da chamada não tiver a permissão necessária, SecurityException é devolvido da chamada.

Permissões BroadcastReceiver (aplicadas à tag <receiver>) restringem quem pode enviar transmissões ao receptor associado. A permissão é verificada depois que Context.sendBroadcast() retorna enquanto o sistema tenta entregar a transmissão enviada a um determinado receptor. Como resultado, uma falha de permissão não resultará em uma exceção devolvida ao autor da chamada: ela apenas não entregará a intent. Da mesma forma, é possível fornecer uma permissão a Context.registerReceiver() para controlar quem pode transmitir para um receptor registrado programaticamente. De outra forma, é possível fornecer uma permissão ao chamar Context.sendBroadcast() para restringir que objetos BroadcastReceiver podem receber a transmissão (veja abaixo).

Permissões ContentProvider (aplicadas à tag <provider>) restringem quem pode acessar os dados em um ContentProvider. (Provedores de conteúdo têm uma unidade de segurança adicional importante chamada permissões URI, descrita a seguir.) Diferente de outros componentes, há dois atributos separados de permissão que se podem definir: android:readPermission restringe quem pode ler dados no provedor e android:writePermission restringe quem pode gravar nele. Observe que, se um provedor é protegido com ambas as permissões de leitura e gravação, a permissão de gravação sozinha não significará que seja possível ler dados de um provedor. Essas permissões são verificadas ao recuperar um provedor pela primeira vez (se não tiver nenhuma das permissões, SecurityException será devolvido) e à medida que se realizam operações no provedor. O uso de ContentResolver.query() exige reter a permissão de leitura; o uso de ContentResolver.insert() ContentResolver.update() e ContentResolver.delete() exige a permissão de gravação. Em todos esses casos, não reter a permissão exigida resulta em um SecurityException devolvido pela chamada.

Impor permissões ao enviar transmissões

Além da permissão impor quem pode enviar intents para um BroadcastReceiver registrado, como descrito acima, também é possível especificar uma permissão exigida ao enviar uma transmissão. Ao chamar Context.sendBroadcast() com uma string de permissão, você exige que um aplicativo de receptor retenha essa permissão para receber a transmissão.

Observe que tanto um receptor quanto um transmissor pode exigir uma permissão. Quando isso corre, as duas verificações de permissão devem passar pela intent para serem entregues ao destino associado.

Outras imposições de permissão

Permissões otimizadas arbitrariamente podem ser impostas a qualquer chamada ao serviço. Isto é realizado com o método Context.checkCallingPermission(). Realize uma chamada com uma string de permissão desejada e ela retornará um inteiro indicando se essa permissão foi concedida ao processo de chamada atual. Observe que só se pode usar isso ao realizar uma chamada vindo de outro processo, geralmente por uma interface IDL publicada por um serviço ou de alguma outra forma, dependendo do processo.

Há várias outras formas úteis de verificar permissões. Se tiver o pid de outro processo, é possível usar o método de contexto Context.checkPermission(String, int, int) para verificar uma permissão nesse pid. Se tiver o nome do pacote de outro aplicativo, é possível usar o método direto PackageManager PackageManager.checkPermission(String, String) para descobrir se esse pacote foi concedido a uma permissão específica.

Permissões URI

O sistema de permissão padrão descrito até agora não é o suficiente quando usado com provedores de conteúdo. Um provedor de conteúdo pode querer proteger-se com permissões de leitura e gravação, enquanto que clientes diretos também precisam usar URIs específicos e outros aplicativos para que possam operar. Um exemplo típico são os anexos em um aplicativo de e-mail. O acesso ao e-mail deve ser protegido pelas permissões, já que os dados de usuário são confidenciais. No entanto, se um URI para um anexo de imagem for concedido a um visualizador de imagens, esse visualizador não terá a permissão para abrir o anexo pois não há motivo para reter uma permissão para acessar todos os e-mails.

A solução para este problema são permissões por URI: ao iniciar uma atividade ou retornar um resultado para uma atividade, o autor da chamada pode definir Intent.FLAG_GRANT_READ_URI_PERMISSION e/ou Intent.FLAG_GRANT_WRITE_URI_PERMISSION. Isso concede à permissão de atividade recebida o acesso a um URI de dados específicos na intent, independentemente se ele tem ou não a permissão para acessar os dados no provedor de conteúdo correspondente à intent.

Esse mecanismo permite um modelo de estilo de capacidade onde a interação do usuário (abrir um anexo, selecionar um contato da lista etc.) conduz os privilégios ad-hoc de permissão otimizadas. Essa pode ser um recurso fundamental para reduzir as permissões necessárias a aplicativos somente às diretamente relacionadas ao comportamento.

Para conceder permissões URI otimizadas, no entanto, é preciso certa cooperação com o provedor de conteúdos que retém esses URIs. Recomenda-se que os provedores de conteúdos implementem essa unidade e declarem que são compatíveis com ela pelo atributo android:grantUriPermissions ou pela tag <grant-uri-permissions>.

Mais informações podem ser encontradas nos métodos Context.grantUriPermission(), Context.revokeUriPermission() e Context.checkUriPermission().

Mais leitura sobre o assunto:

Permissões que sugerem requisitos de recurso
Informações sobre como solicitar algumas permissões restringirá implicitamente seu aplicativo a dispositivos que incluem o recurso de software ou hardware correspondente.
<uses-permission>
Referência da API para a tag do manifesto que declara as permissões de sistema necessárias do seu aplicativo.
Manifest.permission
Referência da API para todas as permissões de sistema.

Você também pode se interessar por:

Compatibilidade do dispositivo
Informações sobre como o Android funciona em diferentes tipos de dispositivo e uma introdução a como otimizar o aplicativo para cada dispositivo ou restringir a disponibilidade a diferentes dispositivos.
Visão geral da segurança do Android
Uma discussão detalhada sobre o modelo de segurança da plataforma Android.