Categoria do OWASP: MASVS-CODE - Qualidade do código (link em inglês)
Visão geral
Usar PendingIntent.getCreator*()
ou PendingIntent.getTarget*()
para determinar se o remetente de um PendingIntent é confiável cria um
risco de exploração.
PendingIntent.getCreator*()
ou
PendingIntent.getTarget*()
retorna o criador do
PendingIntent, que nem sempre corresponde ao remetente. O criador pode ser confiável, mas
o remetente nunca deve ser confiável, já que ele pode ser um app malicioso
que adquiriu o PendingIntent de outro app usando vários mecanismos, por
exemplo:
- de
NotificationListenerService
- casos de uso legítimos que fazem parte do app vulnerável.
Um exemplo de uso legítimo de PendingIntent.getCreator*()
ou PendingIntent.getTarget*()
seria mostrar
o ícone do app que será iniciado pela PendingIntent.
Impacto
Confiar no remetente de uma PendingIntent porque você consultou (e confia) no criador pode levar a vulnerabilidades. Se um app confiar no remetente do PendingIntent com base no criador dele e compartilhar a lógica de autenticação ou autorização, sempre que o remetente do PendingIntent for um app malicioso, isso vai levar a uma violação de autenticação ou até mesmo à execução remota de código com base em entradas inválidas e não confiáveis, dependendo da implementação do código do aplicativo vulnerável.
Mitigações
Distinguir entre remetente e criador
Qualquer tipo de lógica de autenticação ou autorização realizada ao receber um
PendingIntent não pode se basear em pressupostos sobre o
criador do PendingIntent identificado usando PendingIntent.getCreator*()
ou PendingIntent.getTarget*()
.
Usar outras formas de validar autores de chamadas
Se você precisar autenticar o autor da chamada, em vez de usar PendingIntent, use um Service ou ContentProvider. Ambos permitem buscar o UID do autor da chamada com Binder.getCallingUid() quando você estiver no contexto de envio de um IPC de entrada. O UID pode ser consultado mais tarde usando PackageManager.getPackagesForUid().
Outra abordagem, disponível a partir do nível 34 da API, seria usar BroadcastReceiver.getSentFromUid() ou BroadcastReceiver.getSentFromPackage() se o remetente tiver ativado o compartilhamento de identidade durante a transmissão usando BroadcastOptions.isShareIdentityEnabled().
Sempre verifique se o pacote de chamada tem a assinatura esperada, já que pacotes transferidos por sideload podem ter nomes de pacotes que se sobrepõem aos da Play Store.