Remetente de intents pendentes

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:

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.

Recursos