Definir uma permissão de app personalizada

Este documento descreve como os desenvolvedores de apps podem usar os recursos de segurança fornecidos pelo Android para definir as próprias permissões. Ao definir permissões personalizadas, um app pode compartilhar recursos e funções com outros apps. Para saber mais sobre permissões, consulte a Visão geral de permissões.

Contexto

O Android é um sistema operacional separado por privilégios, em que cada app é executado com uma identidade de sistema distinta (ID do usuário do Linux e ID do grupo). Partes do sistema também são separadas em identidades distintas. Assim, o Linux isola apps uns dos outros e do sistema.

Os apps podem expor a funcionalidade deles a outros aplicativos definindo permissões que esses outros apps podem solicitar. Eles também podem definir permissões que são disponibilizadas automaticamente para outros apps assinados com o mesmo certificado.

Assinatura de apps

Todos os APKs precisam ser assinados com um certificado cuja chave privada seja mantida pelo desenvolvedor. Esse certificado identifica o autor do app. O certificado não precisa ser assinado por uma autoridade de certificação. É perfeitamente permitido, e normal, que os apps para Android usem certificados autoassinados. O objetivo dos certificados no Android é distinguir os autores dos apps. Isso permite que o sistema conceda ou negue acesso dos apps a permissões no nível da assinatura e conceda ou negue solicitação para receber a mesma identidade do Linux de outro app.

IDs de usuário e acesso a arquivos

No momento da instalação, o Android atribui a cada pacote um ID de usuário do Linux diferente. A identidade permanece constante durante a vida útil do pacote nesse dispositivo. Em um dispositivo diferente, o mesmo pacote pode ter um UID diferente; o que importa é que cada pacote tenha um UID distinto em um determinado dispositivo.

Como a aplicação da segurança ocorre no nível do processo, o código de dois pacotes normalmente não pode ser executado no mesmo processo, porque eles precisam ser executados como usuários do Linux diferentes. Você pode usar o atributo sharedUserId na tag do manifesto do AndroidManifest.xml de cada pacote para que eles tenham o mesmo ID de usuário. Ao fazer isso, para fins de segurança, os dois pacotes são tratados como se fossem o mesmo app, com as mesmas permissões de ID de usuário e de arquivo. Para manter a segurança, apenas dois apps assinados com a mesma assinatura (e solicitando o mesmo sharedUserId) receberão o mesmo ID do usuário.

Todos os dados armazenados por um app receberão o ID do usuário desse app e normalmente não podem ser acessados por outros pacotes.

Para saber mais sobre o modelo de segurança do Android, consulte Visão geral de segurança do Android

Como definir e aplicar permissões

Para aplicar suas próprias permissões, primeiro é necessário declará-las no AndroidManifest.xml usando um ou mais elementos <permission>.

Por exemplo, um app que queira controlar quem pode iniciar uma das atividades pode 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 com o mesmo nome, a menos que todos os pacotes sejam assinados com o mesmo certificado. Se um pacote declarar uma permissão, o sistema não permitirá que o usuário instale outros pacotes com o mesmo nome de permissão, a menos que esses pacotes sejam assinados com o mesmo certificado do primeiro pacote. Para evitar conflitos na nomenclatura, recomendamos o uso de nomes no estilo de domínio inverso para permissões personalizadas, por exemplo, com.example.myapp.ENGAGE_HYPERSPACE.

O atributo protectionLevel é obrigatório, informando ao sistema como o usuário precisa ser informado sobre apps que exigem a permissão ou quem pode manter essa permissão, conforme descrito na documentação vinculada.

O atributo android:permissionGroup é opcional e usado apenas para ajudar o sistema a exibir permissões para o usuário. Na maioria dos casos, você precisa definir isso como um grupo de sistema padrão (listado em android.Manifest.permission_group), embora seja possível definir um grupo por conta própria. É preferível usar um grupo já existente, porque isso simplifica a IU de permissão exibida para o usuário.

Você precisa fornecer um rótulo e uma descrição para a permissão. Eles são recursos de string que o usuário pode ver quando está visualizando uma lista de permissões (android:label) ou detalhes sobre uma única permissão (android:description). O rótulo tem que ser curto; algumas palavras que descrevem a funcionalidade principal que a permissão está protegendo. A descrição precisa conter algumas frases descrevendo o que a permissão permite que um detentor faça. Nossa convenção é uma descrição de duas frases: a primeira sentença descreve a permissão e a segunda sentença avisa o usuário sobre o que pode dar errado se um app receber a permissão.

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

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

Criar um grupo de permissões

Como mostrado na seção anterior, você pode usar o atributo android:permissionGroup para ajudar o sistema a descrever as permissões para o usuário. Na maioria dos casos, convém definir um grupo de sistema padrão (listado em android.Manifest.permission_group), mas você também pode definir seu próprio grupo com <permission-group>.

O elemento <permission-group> define um rótulo para um conjunto de permissões, tanto aquelas declaradas no manifesto com elementos <permission> quanto aquelas declaradas em outro lugar. Isso afeta apenas a forma como as permissões são agrupadas quando apresentadas ao usuário. O elemento <permission-group> não especifica as permissões que pertencem ao grupo, mas fornece um nome ao grupo.

Você pode colocar uma permissão no grupo atribuindo o nome do grupo ao atributo permissionGroup do elemento <permission>.

O elemento <permission-tree> declara um namespace para um grupo de permissões que são definidas no código.

Recomendações de permissões personalizadas

Os apps podem definir as permissões personalizadas e solicitar permissões personalizadas de outros apps, definindo elementos <uses-permission>. No entanto, você precisa avaliar com cuidado se é necessário que seu app faça isso.

  • Se você estiver projetando um pacote de apps que expõem a funcionalidade um ao outro, tente projetar os apps de forma que cada permissão seja definida apenas uma vez. Faça isso se todos os apps não estiverem assinados com o mesmo certificado. Mesmo que os apps sejam assinados com o mesmo certificado, é uma prática recomendada definir cada permissão apenas uma vez.
  • Se a funcionalidade só estiver disponível para apps assinados com a mesma assinatura do app de fornecimento, talvez seja possível evitar a definição de permissões personalizadas usando verificações de assinatura. Quando um dos seus apps fizer uma solicitação de outro app, o segundo app poderá verificar se os dois apps estão assinados com o mesmo certificado antes de obedecer à solicitação.

Continue lendo sobre:

<uses-permission>
Referência da API para a tag de manifesto que declara as permissões necessárias do sistema do seu app.

Talvez você também tenha interesse em:

Visão geral de segurança do Android
Uma discussão detalhada sobre o modelo de segurança da plataforma Android.