Ler a área de transferência no app: só no gesto de colar e sem guardar o que veio
Ler o clipboard ao abrir o app captura senhas e códigos copiados para outro lugar. Veja como ler só quando a pessoa pede, validar o conteúdo e não mandá-lo para log nem analytics.
O app de pagamentos lia a área de transferência sempre que voltava ao primeiro plano, para oferecer "Detectamos um código Pix, deseja pagar?". Na semana do lançamento, o suporte recebeu prints de clientes assustados: o iPhone mostrava um aviso de que o app tinha colado de outro aplicativo, e um deles tinha acabado de copiar a senha do banco no gerenciador de senhas. O app nunca guardou nada. Mas leu, e o sistema contou.
A resposta curta: leia a área de transferência só quando a pessoa pede, num botão de colar ou no gesto de colar num campo. Valide o formato do que veio antes de usar, mantenha o conteúdo só no campo e nunca o envie para log, analytics ou servidor além do necessário para a operação. Ao copiar algo sensível do seu app, considere marcar o conteúdo como sensível com as APIs da plataforma.
Por que a área de transferência é um lugar delicado
A área de transferência é compartilhada por todos os apps. Nela passam senhas copiadas do gerenciador, códigos de verificação, chaves de API, endereços, números de cartão. A pessoa copia pensando no próximo lugar onde vai colar, não no seu app.
Quando o app lê o clipboard sem um gesto, ele recebe dados que não pediu e que a pessoa não pretendia entregar. Mesmo sem má intenção, esse texto passa pela memória do app e, num descuido, por um log de depuração ou um evento de analytics. É vigilância acidental.
Os sistemas operacionais reagiram. As versões recentes do iOS mostram um aviso quando um app lê o conteúdo copiado em outro app e, em certos casos, pedem permissão para colar. O Android, a partir da versão 12, mostra um aviso quando um app acessa conteúdo copiado de outro app, e versões anteriores já restringiam a leitura por apps em segundo plano. Ou seja, a leitura automática não é só arriscada: ela fica visível e queima a confiança no seu app.
Como fazer certo, passo a passo
O exemplo é o app PagaFácil, em .NET MAUI, numa tela de pagamento por Pix copia e cola.
- Coloque um botão "Colar código" ao lado do campo, além do colar normal do teclado.
- Leia o clipboard só no clique, com
Clipboard.Default. - Valide o formato antes de aceitar. Um código Pix copia e cola começa com
000201e contém o identificadorbr.gov.bcb.pix. - Coloque o conteúdo no campo e deixe a pessoa conferir antes de prosseguir.
- Não registre o conteúdo em log, analytics ou relatório de erro; registre só o resultado da validação.
- Remova qualquer leitura em
OnAppearing, ao voltar ao primeiro plano ou por evento de mudança do clipboard.
O que não fazer
// Leitura sem gesto: dispara aviso do sistema e captura o que a pessoa copiou para outro lugar
protected override async void OnAppearing()
{
base.OnAppearing();
var texto = await Clipboard.Default.GetTextAsync();
_logger.LogInformation("Clipboard: {Texto}", texto);
}
Esse trecho junta os dois erros do caso do PagaFácil: lê sem pedido e manda o conteúdo para o log, que provavelmente vai para um serviço externo de observabilidade.
Leitura no gesto, com validação
private async void OnColarCodigoClicked(object sender, EventArgs e)
{
try
{
if (!Clipboard.Default.HasText)
{
MensagemLabel.Text = "Nada para colar. Copie o código Pix e tente de novo.";
return;
}
string? texto = (await Clipboard.Default.GetTextAsync())?.Trim();
if (string.IsNullOrEmpty(texto) || !PareceCodigoPix(texto))
{
_logger.LogInformation("Colar código Pix: conteúdo rejeitado na validação");
MensagemLabel.Text = "O texto copiado não parece um código Pix.";
return;
}
CodigoEntry.Text = texto;
MensagemLabel.Text = "Confira o código e toque em Continuar.";
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Falha ao ler a área de transferência");
MensagemLabel.Text = "Não foi possível colar. Tente colar direto no campo.";
}
}
private static bool PareceCodigoPix(string texto) =>
texto.StartsWith("000201", StringComparison.Ordinal)
&& texto.Contains("br.gov.bcb.pix", StringComparison.OrdinalIgnoreCase);
Três detalhes importam. O manipulador é async void porque é evento de botão, e por isso tudo está dentro de try: uma exceção não tratada ali derruba o app. O log registra que a validação falhou, nunca o texto. E a validação é só um filtro de formato, para não colar uma senha no campo de pagamento por engano; a validação de verdade do código acontece no servidor, que decodifica o payload e confere valor e recebedor antes de pagar.
Na web, a mesma regra
Num app web, prefira o evento paste do próprio campo, que só dispara quando a pessoa cola e entrega o texto em event.clipboardData.getData('text'). A leitura programática com navigator.clipboard.readText() exige contexto seguro e, conforme o navegador, permissão ou gesto da pessoa. Se você precisa pedir permissão para algo que o colar do teclado já resolve, o botão provavelmente não precisa existir.
Quando o seu app é quem copia
O PagaFácil também gera códigos Pix para cobrança e tem um botão "Copiar". Copiar para a área de transferência é o comportamento esperado, mas o conteúdo fica lá até a pessoa copiar outra coisa e pode aparecer na pré-visualização que o sistema mostra. Para dados mais sensíveis, como códigos de recuperação de conta, as plataformas oferecem recursos próprios: no Android 13 ou superior, marcar o conteúdo como sensível para que a pré-visualização o oculte; no iOS, opções de expiração e de não compartilhar com outros aparelhos. Esses recursos exigem código de plataforma, porque a API de clipboard do MAUI cobre só o básico de ler e escrever texto. Avalie se o dado deveria ser copiável; às vezes, mostrar na tela e pedir que a pessoa anote é o certo.
O mesmo cuidado com o que vai para o log vale para todo o app; o post log útil não carrega senha nem token traz a lista de campos a filtrar. E se o app trata dados pessoais, a leitura desnecessária de clipboard é exatamente o tipo de coleta que a adequação à LGPD pede para eliminar.
Erros comuns
- Ler o clipboard ao abrir ou ao voltar ao app. O sistema avisa a pessoa, e o app captura senhas e códigos que não lhe dizem respeito.
- Assinar o evento de mudança do clipboard sem necessidade. O app passa a receber tudo o que a pessoa copia enquanto ele está aberto.
- Logar o conteúdo lido. Senhas e códigos vão parar no serviço de observabilidade, com retenção de meses.
- Mandar o conteúdo para analytics. Dado sensível sai do aparelho para um terceiro sem base nem necessidade.
- Aceitar o texto sem validar. Uma senha copiada vira o código de pagamento, e o erro aparece no servidor com o dado junto.
- Deixar exceção escapar de
async void. Uma falha de leitura derruba o app inteiro.
Checklist
- Nenhuma leitura do clipboard acontece sem um gesto explícito da pessoa.
- Não há leitura em
OnAppearing, retomada do app ou evento de mudança. - O conteúdo lido é validado por formato antes de ir para o campo.
- Logs e analytics registram só o resultado, nunca o texto.
- O servidor faz a validação definitiva do que foi colado.
- Manipuladores
async voidde colar tratam exceções. - Conteúdo sensível copiado pelo app foi avaliado e, se preciso, marcado como sensível na plataforma.
Abra o seu app num iPhone recente, copie algo em outro aplicativo e volte: aparece o aviso de que o app colou sem você ter tocado em colar?
Referência: https://learn.microsoft.com/en-us/dotnet/maui/platform-integration/data/clipboard?view=net-maui-8.0