Permissões personalizadas

Categoria do OWASP: MASVS-CODE - Qualidade do código (link em inglês)

Visão geral

Os riscos associados às permissões personalizadas surgem quando a definição das permissões personalizadas está ausente ou incorreta, ou quando o atributo android:protectionLevel correspondente é usado indevidamente no manifesto.

Por exemplo, esses riscos podem ser explorados criando uma permissão personalizada com o mesmo nome, mas definida por um app malicioso e com diferentes níveis de proteção aplicados.

As permissões personalizadas são projetadas para permitir o compartilhamento de recursos com outros apps. Confira alguns exemplos de uso legítimo de permissões personalizadas:

  • Como controlar a comunicação entre processos (IPC, na sigla em inglês) entre dois ou mais apps
  • Como acessar serviços de terceiros
  • Como restringir o acesso aos dados compartilhados de um app

Impacto

O impacto da exploração dessa vulnerabilidade é que um app malicioso pode ter acesso a recursos originalmente protegidos. As implicações da vulnerabilidade dependem do recurso que está sendo protegido e das permissões associadas ao serviço de aplicativo original.

Risco: erros de digitação em permissões personalizadas

Uma permissão personalizada pode ser declarada no manifesto, mas uma permissão personalizada diferente é usada para proteger os componentes do Android exportados devido a um erro de digitação. Um aplicativo malicioso pode tirar proveito de aplicativos que cometeram um erro de ortografia em uma permissão:

  • Como registrar essa permissão primeiro
  • Como prever a ortografia em aplicativos subsequentes

Isso pode permitir que um app tenha acesso não autorizado a recursos ou controle sobre o app vítima.

Por exemplo, um app vulnerável quer proteger um componente usando uma permissão READ_CONTACTS, mas digita acidentalmente a permissão como READ_CONACTS. Um app malicioso pode reivindicar READ_CONACTS, já que ele não pertence a nenhum aplicativo (ou ao sistema) e pode ter acesso ao componente protegido. Outra variante comum dessa vulnerabilidade é o android:permission=True. Valores como true e false, independentemente da capitalização, são entradas inválidas para a declaração de permissão e são tratados de maneira semelhante a outros erros de digitação de declaração de permissão personalizada. Para corrigir isso, o valor do atributo android:permission precisa ser alterado para uma string de permissão válida. Por exemplo, se o app precisar acessar os contatos do usuário, o valor do atributo android:permission precisa ser android.permission.READ_CONTACTS.

Mitigações

Verificações de lint no Android

Ao declarar permissões personalizadas, use as verificações do lint do Android para encontrar erros de digitação e outros possíveis erros no código.

Convenção de nomenclatura

Use uma convenção de nomenclatura consistente para tornar os erros de digitação mais perceptíveis. Verifique com atenção se há erros de digitação nas declarações de permissão personalizadas no manifesto do app.


Risco: permissões sem par

As permissões são usadas para proteger os recursos dos apps. Há dois locais diferentes em que um app pode declarar as permissões necessárias para acessar recursos:

No entanto, às vezes, essas permissões não são definidas por uma tag <permission> correspondente em um manifesto de um APK no dispositivo. Nesse caso, elas são chamadas de permissões órfãs. Isso pode acontecer por vários motivos, como:

  • Pode haver uma desincronização entre as atualizações no manifesto e o código com a verificação de permissão.
  • O APK com as permissões pode não ser incluído no build ou a versão incorreta pode estar incluída
  • O nome da permissão na verificação ou no manifesto pode estar grafado incorretamente

Um app malicioso pode definir e adquirir uma permissão órfã. Se isso acontecer, os aplicativos privilegiados que confiam na permissão órfã para proteger um componente poderão ser comprometidos.

Nos casos em que o app privilegiado usa a permissão para proteger ou restringir qualquer componente, isso pode conceder ao app malicioso acesso a esse componente. Exemplos incluem iniciar atividades protegidas por uma permissão, acessar um provedor de conteúdo ou transmitir para um broadcast receiver protegido pela permissão órfã.

Ele também pode criar uma situação em que o aplicativo com privilégios é induzido a acreditar que ele é um aplicativo legítimo e, portanto, carregando arquivos ou conteúdo.

Mitigações

Verifique se todas as permissões personalizadas que o app usa para proteger componentes também estão definidas no manifesto.

O app usa as permissões personalizadas my.app.provider.READ e my.app.provider.WRITE para proteger o acesso a um provedor de conteúdo:

XML

<provider android:name="my.app.database.CommonContentProvider" android:readPermission="my.app.provider.READ" android:writePermission="my.app.provider.WRITE" android:exported="true" android:process=":myappservice" android:authorities="my.app.database.contentprovider"/>

O app também define e usa essas permissões personalizadas, impedindo que outros apps maliciosos façam isso:

XML

<permission android:name="my.app.provider.READ"/>
<permission android:name="my.app.provider.WRITE"/>
<uses-permission android:name="my.app.provider.READ" />
<uses-permission android:name="my.app.provider.WRITE" />

Risco: uso indevido de android:protectionLevel

Esse atributo descreve o nível de risco potencial na permissão e indica quais procedimentos o sistema precisa seguir ao decidir conceder ou não a permissão.

Mitigações

Evite o nível de proteção normal ou perigoso

Usar uma protectionLevel normal ou perigosa nas suas permissões significa que a maioria dos apps pode solicitar e receber a permissão:

  • "normal" requer apenas a declaração
  • "perigosa" será aprovada por muitos usuários

Portanto, essas protectionLevels oferecem pouca segurança.

Usar permissões de assinatura (Android 10 ou mais recente)

Use níveis de proteção de assinatura sempre que possível. O uso desse recurso garante que apenas outros apps assinados com o mesmo certificado do app que criou a permissão possam acessar esses recursos protegidos. Use um certificado de assinatura dedicado (não reutilizado) e armazene-o com segurança em um keystore.

Defina uma permissão personalizada da seguinte forma no manifesto:

XML

<permission
    android:name="my.custom.permission.MY_PERMISSION"
    android:protectionLevel="signature"/>

Restringir o acesso a uma atividade, por exemplo, apenas aos apps que têm essa permissão personalizada concedida, conforme abaixo:

XML

<activity android:name=".MyActivity" android:permission="my.custom.permission.MY_PERMISSION"/>

Qualquer outro app assinado com o mesmo certificado que o app que declarou essa permissão personalizada vai receber acesso à atividade .MyActivity e precisará declará-la da seguinte maneira no manifesto:

XML

<uses-permission android:name="my.custom.permission.MY_PERMISSION" />

Cuidado com as permissões personalizadas de assinatura (Android < 10)

Se o app for destinado ao Android < 10, sempre que as permissões personalizadas forem removidas devido a desinstalações ou atualizações, apps maliciosos poderão ainda usar essas permissões personalizadas e, assim, ignorar as verificações. Isso ocorre devido a uma vulnerabilidade de elevação de privilégios (CVE-2019-2200) que foi corrigida no Android 10.

Esse é um dos motivos (junto com o risco de condições de corrida) para que as verificações de assinatura sejam recomendadas em vez de permissões personalizadas.


Risco: disputa

Se um app legítimo A definir uma permissão personalizada de assinatura usada por outros apps X, mas for desinstalado posteriormente, um app malicioso B poderá definir essa mesma permissão personalizada com um protectionLevel diferente, por exemplo, normal. Dessa forma, B tem acesso a todos os componentes protegidos por essa permissão personalizada nos apps X sem precisar ser assinado com o mesmo certificado que o app A.

O mesmo acontece se B for instalado antes de A.

Mitigações

Se você quiser disponibilizar um componente apenas para apps assinados com a mesma assinatura do app de fornecimento, talvez seja possível evitar a definição de permissões personalizadas para restringir o acesso a esse componente. Nessa situação, é possível usar verificações de assinatura. Quando um dos seus apps faz uma solicitação para outro, o segundo app pode verificar se os dois apps estão assinados com o mesmo certificado antes de obedecer à solicitação.


Recursos