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
de permissões personalizadas está ausente ou com erros de ortografia 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 foram projetadas para permitir o compartilhamento de recursos e 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 componentes Android exportados devido a um erro de digitação. Um aplicativo malicioso pode aproveitar aplicativos que cometeram um erro de digitação 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 a digita incorretamente 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 do 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 cuidado as declarações de permissões personalizadas no manifesto do app para detectar erros de digitação.
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 orfã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 errada pode ser incluída.
- O nome da permissão na verificação ou no manifesto pode estar escrito 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ã.
Isso também pode criar uma situação em que o aplicativo privilegiado é enganado para acreditar que o app malicioso é legítimo e, portanto, carrega 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 possível nível de risco da permissão e indica quais procedimentos o sistema precisa seguir ao decidir se vai 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, esses protectionLevels
oferecem pouca segurança.
Usar permissões de assinatura (Android 10 ou mais recente)
Use os 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. Verifique se você está usando 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 precisa declarar 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 segmenta o 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
ganha acesso a todos os componentes protegidos por essa
permissão personalizada nos apps X
sem precisar ser assinado com o mesmo
certificado do 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 app, o segundo pode verificar se os dois apps estão assinados com o mesmo certificado antes de obedecer à solicitação.
Recursos
- Minimizar as solicitações de permissão
- Visão geral de permissões
- Descrição dos níveis de proteção
- CustomPermissionTypo Android Lint
- 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