Pular para o conteúdo
Fale conosco

play-integrity · android · attestation

Play Integrity na prática: vereditos, risco de acesso ao app e a cota de 10.000 requisições por dia

Um guia prático para usar a Play Integrity API em um backend real: o que cada veredito significa, como ler o sinal de risco de acesso ao app, como desenhar uma política por operação e como pedir mais do que a cota diária padrão.

Por Equipe Moatgator7 min de leituraRead this article in English

Ilustração: um celular envia um token de integridade ao servidor, que lê um veredito formado por grupos de campos empilhados e o aprova.

A Play Integrity API permite que o seu servidor faça ao Google uma pergunta estreita: esta requisição vem do meu app genuíno, instalado pelo Google Play, em um aparelho Android genuíno e não comprometido? A resposta chega como um token assinado que o seu backend decodifica. Quando está bem ligada, ela transforma uma categoria inteira de bugs do tipo "confiar no cliente" em decisões que o servidor pode tomar. Quando é ligada sem cuidado, dá uma falsa sensação de segurança e uma quantidade surpreendente de incidentes em produção.

Este artigo cobre o que vem no veredito, como tomar uma decisão a partir dele, como o sinal de risco de acesso ao app ajuda contra fraude por acesso remoto e como funciona a cota padrão. Os fatos sobre campos do veredito e cota vêm da documentação do Google, listada no fim, e vale conferi-los lá, porque a API evolui.

O formato de um veredito

Você não lê o token no app. O app pede um token à biblioteca dos serviços do Play, envia ao seu servidor junto com a requisição que ele protege, e o servidor o decodifica pela API do Google. O veredito decodificado tem alguns grupos de campos.

Diagrama: o app pede um token vinculado ao hash da requisição, o servidor o decodifica pela API do Google e uma política decide por operação; ele lista os cinco grupos de campos do veredito e três operações de exemplo.
Os grupos de campos do veredito e uma política por operação, como descrito abaixo.
  • requestDetails informa qual pacote pediu, a qual hash de requisição (ou nonce, nas requisições clássicas, mais antigas) ele foi vinculado e quando. Leia isto primeiro, antes de qualquer outra coisa.
  • appIntegrity informa se o binário e o certificado de assinatura correspondem ao que o Google Play distribuiu. Os valores são PLAY_RECOGNIZED, UNRECOGNIZED_VERSION e UNEVALUATED.
  • deviceIntegrity é uma lista de rótulos. MEETS_DEVICE_INTEGRITY significa um aparelho genuíno e certificado. Os rótulos opcionais MEETS_BASIC_INTEGRITY e MEETS_STRONG_INTEGRITY precisam ser habilitados, e o MEETS_STRONG_INTEGRITY é mais rígido, exigindo atualizações de segurança recentes nas versões mais novas do Android. Uma lista vazia também é uma resposta: ela aponta sinais de comprometimento ou algo que não é um aparelho físico.
  • accountDetails informa se o app tinha licença, isto é, se foi instalado ou atualizado pelo Google Play por aquele usuário.
  • environmentDetails é opcional (opt-in). Traz o veredito de risco de acesso ao app e o veredito do Play Protect.

Duas consequências práticas. Primeiro, um campo pode estar ausente por bons motivos: quando o aparelho não é confiável o bastante, vários outros campos vêm como UNEVALUATED, então o seu código precisa tratar "não avaliado" como "sem informação", e não como "tudo certo". Segundo, o veredito descreve um instante, então você precisa conferir a sua atualidade.

Vincule o token à requisição

O erro mais comum é verificar que o token é válido e parar por aí. Um token válido prova muito pouco se um atacante consegue capturar um de uma sessão legítima e reutilizá-lo. A API padrão resolve isso com um hash da requisição: o app calcula um hash da operação que vai fazer (o valor, o destinatário, um nonce do servidor) e o envia ao pedir o token. O seu servidor recalcula o mesmo hash e o compara com o do veredito.

Faça três verificações antes de olhar qualquer outro campo: o nome do pacote é o seu, o hash da requisição é o esperado para esta operação e o carimbo de tempo é recente. A documentação do Google recomenda exatamente essa ordem e avisa que a ordem dos campos no payload não é garantida, então não dependa de posição.

Abaixo está uma pequena função de decisão, autocontida, em JavaScript. Ela não chama o Google: recebe um veredito já decodificado e uma política e devolve permitir ou negar com um motivo, que é a parte fácil de errar e fácil de testar.

js
// Decide o que fazer com um veredito do Play Integrity já decodificado.// `expected` vem do seu próprio servidor: pacote, hash da requisição e janela de validade.function decide(verdict, expected, policy, nowMillis) {  const req = verdict.requestDetails ?? {};  if (req.requestPackageName !== expected.packageName) return deny("wrong-package");  if (req.requestHash !== expected.requestHash) return deny("request-hash-mismatch");  if (!(nowMillis - Number(req.timestampMillis) <= expected.maxAgeMillis)) return deny("stale-token");  const labels = verdict.deviceIntegrity?.deviceRecognitionVerdict ?? [];  if (policy.device === "strong" && !labels.includes("MEETS_STRONG_INTEGRITY")) return deny("device-not-strong");  if (policy.device === "device" && !labels.includes("MEETS_DEVICE_INTEGRITY")) return deny("device-not-certified");  if (policy.requireRecognizedApp && verdict.appIntegrity?.appRecognitionVerdict !== "PLAY_RECOGNIZED") return deny("app-not-recognized");  const apps = verdict.environmentDetails?.appAccessRiskVerdict?.appsDetected ?? [];  const risky = apps.filter((a) => a.endsWith("_CAPTURING") || a.endsWith("_CONTROLLING") || a.endsWith("_OVERLAYS"));  if (policy.blockOnAccessRisk && risky.length > 0) return deny("app-access-risk");  return { allow: true, reason: "ok" };}function deny(reason) {  return { allow: false, reason };}

Repare que a função nunca devolve "permitir" só porque um campo está ausente. Ausente significa desconhecido, e desconhecido em uma operação sensível deve levar a outra verificação, e não passar.

Desenhe uma política por operação

Uma regra global única ("bloqueie tudo que não for forte") é rígida demais e frouxa demais ao mesmo tempo. Rígida demais porque uma parte dos seus usuários reais usa aparelhos mais antigos ou incomuns, e bloqueá-los de ver o saldo vira problema de suporte. Frouxa demais porque a mesma regra vale para movimentar dinheiro.

Defina a política por operação. Ler conteúdo público pode não exigir veredito. Entrar na conta pode exigir MEETS_DEVICE_INTEGRITY e um app reconhecido. Uma ação de alto valor pode exigir o rótulo mais rígido e uma lista de risco de acesso vazia, além de uma etapa extra (confirmação biométrica, um atraso, uma revisão manual) quando o veredito estiver ausente ou fraco.

Comece em modo monitor. Registre o veredito e a sua decisão hipotética em cada requisição durante algumas semanas antes de impor qualquer coisa. Você vai descobrir quais dos seus usuários reais teriam sido bloqueados e vai achar os bugs de integração (um nome de pacote errado em uma variante de debug, um hash de requisição calculado de forma diferente no cliente e no servidor) enquanto eles custam apenas linhas de log.

Risco de acesso ao app e fraude por acesso remoto

O veredito de risco de acesso ao app é o sinal mais relevante para fraude por acesso remoto e por sobreposição de tela. Ele é opcional e você o habilita no Play Console. Lista categorias de outros apps no aparelho que poderiam ver a tela, controlar o aparelho ou desenhar por cima do seu app, separadas em apps conhecidos (instalados pelo Google Play ou pré-instalados) e desconhecidos. Serviços de acessibilidade verificados ficam fora da lista.

O uso depende da operação. Bloquear todo usuário que tem um leitor de tela ou um gravador de tela seria errado e discriminaria quem depende de tecnologia assistiva. Um padrão melhor é graduado: para operações de baixo risco, ignore; para uma operação sensível, exija confirmação extra quando houver um app desconhecido que capture ou controle o aparelho; para a operação de maior risco, recuse e explique em linguagem simples que outro app pode estar vendo ou controlando a tela.

Lembre o que esse sinal é: uma pista produzida pelo Google sobre o que está instalado, e não prova de fraude. Combine-o com evidências do lado do servidor, como um aparelho novo, uma mudança repentina de comportamento ou um destino incomum.

A cota padrão e como aumentá-la

O Play Integrity não é ilimitado. Segundo a documentação do Google, o padrão é de 10.000 requisições por dia por app, vinculado ao projeto de nuvem associado ao app. Pedidos de token, clássicos ou padrão, entram nesse número, e as decodificações no servidor também. Se o seu app tem mais usuários ativos por dia do que isso, ou se você pede um token a cada tela, você vai bater no teto e a sua verificação vai começar a falhar no meio do dia.

Duas regras de desenho reduzem a pressão sobre a cota antes de você pedir mais. Peça um token só para as operações que precisam de um, e não na abertura do app. E trate os erros de cota com uma estratégia de nova tentativa com espera crescente e com uma política de contingência segura: para uma operação sensível, falhe fechado ou exija etapa extra; para uma de baixo risco, permita e registre.

Quando precisar de mais, o processo é vincular o seu projeto do Google Cloud ao app no Play Console, garantir que a integração esteja correta (incluindo o comportamento de nova tentativa recomendado) e enviar o formulário de pedido de cota. A documentação diz que o app precisa estar disponível no Google Play e que um aumento pode levar até cerca de uma semana, então peça bem antes de um lançamento ou de uma campanha, e não no dia. Configure alertas de cota no console da nuvem para ver a curva se aproximando do limite.

O que ele não faz

O Play Integrity não sabe se o seu usuário é o dono legítimo da conta. Ele não detecta um golpe de engenharia social em que uma pessoa real, em um aparelho real, é enganada para aprovar um pagamento. Ele não cobre o iOS, onde o App Attest faz um papel parecido. E pode ser mais lento ou indisponível em aparelhos sem os serviços do Google Play, o que em alguns mercados é uma parcela relevante dos usuários.

Trate-o como um sinal forte dentro de um desenho em camadas, com uma política clara, uma contingência segura e um plano para a cota, e ele vai merecer o seu lugar. Trate-o como um interruptor que faz a fraude desaparecer e ele vai decepcionar.

Fontes

Cada afirmação acima pode ser conferida aqui. Se um link mudou, avise e corrigimos o artigo.

  1. Android developers: Play Integrity API overview
  2. Android developers: Integrity verdicts
  3. Android developers: Set up the Play Integrity API (quota and Cloud project)
  4. Google Play Console help: Request a Play Integrity API quota increase

Todos os artigos

Confira o seu app

O Scan gratuito lê um APK, AAB ou IPA e dá uma nota às verificações de resiliência descritas aqui. Ele nunca executa o seu app.