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:
- AndroidManifest.xml: predefinido no arquivo AndroidManifest.xml. Se não
forem especificadas, as permissões
<application>
serão usadas. Por exemplo, permissão de provedor, permissão de receptor, permissão de atividade, permissão de serviço. - Código: registrado no código de execução, por exemplo,
registerReceiver()
.
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
- Minimizar suas solicitações de permissão
- Visão geral de permissões
- Descrição dos níveis de proteção
- CustomPermissionTypo Android Lint (link em inglês)
- Como usar um lint do Android
- Trabalho de pesquisa com explicação detalhada das permissões do Android e descobertas interessantes do teste de fuzz