1

Uma pesquisa não se torna anônima só porque você removeu o campo nome

Quando alguém fala em pesquisa anônima dentro de uma empresa, a primeira implementação costuma parecer óbvia:

não pedir nome
não pedir e-mail
salvar respostas
mostrar resultado agregado

Pronto.

Pesquisa anônima.

Só que não necessariamente.

Dependendo da arquitetura, você pode remover o nome da interface e ainda ter informações suficientes para descobrir — ou inferir com bastante segurança — quem respondeu.

E isso começa a ficar especialmente interessante quando o produto precisa equilibrar duas coisas que entram em conflito:

quanto mais segmentado o resultado, mais útil ele fica para a empresa.

quanto mais segmentado o resultado, maior pode ser o risco de identificar quem respondeu.

O formulário pode ser anônimo e a infraestrutura não

Imagine uma página que pergunta apenas:

De 1 a 5, como você avalia sua liderança?

Nenhum nome.

Nenhum e-mail.

Nenhum campo pessoal.

Mas a aplicação registra:

ip_address
session_id
user_agent
analytics_id
timestamp

O formulário não perguntou quem é a pessoa.

O sistema talvez saiba bastante coisa sobre ela mesmo assim.

Em ambientes autenticados, fica ainda mais evidente:

employee_id
↓
survey_token
↓
response

Mesmo que o dashboard nunca mostre o nome, existe tecnicamente uma relação entre usuário e resposta.

Nesse caso, talvez o termo correto seja confidencial, não necessariamente anônimo.

Isso parece semântico, mas não é.

Para quem responde, existe uma diferença enorme entre:

ninguém consegue saber que fui eu

e:

o sistema sabe, mas meu gestor não consegue acessar essa informação

São modelos de confiança diferentes.

Links individuais são muito úteis.

Você consegue saber:

  • quem já respondeu;
  • quem ainda não respondeu;
  • impedir múltiplas respostas;
  • enviar lembretes;
  • medir taxa de participação.

Algo como:

/survey/a8f92d81c...

Só que agora aparece uma pergunta:

esse token identifica a pessoa?

Se sim, como impedir que a resposta seja correlacionada com ele?

Uma arquitetura possível seria separar participação de conteúdo.

Por exemplo:

ParticipationToken
------------------
employee_id
token_hash
responded_at

e, em outro contexto:

SurveyResponse
--------------
response_id
survey_id
answers
created_at

Sem uma chave direta entre os dois.

O token comprova apenas:

esta pessoa tinha direito de responder e já respondeu.

Depois da submissão, o vínculo necessário para controlar participação pode ser descartado ou isolado da resposta.

Claro que a implementação real depende do produto e das necessidades do cliente.

Mas o ponto é:

anonimato começa no modelo de dados, não no checkbox "não coletar nome".

O maior risco talvez apareça no dashboard

Agora suponha que a coleta esteja perfeita.

Nenhum IP.

Nenhum login associado.

Nenhuma relação entre token e resposta.

Ainda assim podemos identificar pessoas pelo resultado.

Imagine uma empresa com uma equipe de três pessoas.

O dashboard permite:

Departamento: Engenharia
Localização: São Paulo
Cargo: Tech Lead

Resultado:

1 resposta

Acabou o anonimato.

Você pode nunca mostrar o nome da pessoa.

O próprio conjunto de filtros identificou quem respondeu.

Esse problema fica mais interessante porque cada filtro isolado pode parecer seguro.

Por exemplo:

departamento = 20 pessoas
localização = 50 pessoas
cargo = 8 pessoas

Mas:

departamento
+
localização
+
cargo
+
tempo_de_empresa

pode resultar em:

1 pessoa

A privacidade não depende apenas do tamanho original do grupo.

Depende do resultado da interseção dos filtros.

Threshold mínimo ajuda, mas não resolve tudo

Uma solução comum é:

if respondents < 5:
    hide_results()

É um bom começo.

Mas imagine seis pessoas em uma equipe.

Cinco responderam.

Uma delas é a única pessoa de determinado cargo.

Se o dashboard permitir filtrar por cargo:

respondents = 1

Então o threshold precisa ser aplicado depois de cada segmentação, não apenas no resultado inicial.

Algo mais próximo de:

def can_show_segment(segment):
    return segment.respondent_count >= MIN_THRESHOLD

Só que ainda existe outro problema.

Imagine que o dashboard mostre:

Todos: 6 respostas
Sem gerentes: 5 respostas

Talvez seja possível inferir a resposta do gerente pela diferença entre os dois resultados.

Esse tipo de ataque por diferença é fácil de esquecer quando estamos pensando apenas em:

nenhum segmento abaixo de cinco pessoas.

Ou seja:

proteger cada consulta isoladamente não garante que várias consultas juntas sejam seguras.

O dashboard vira parte do modelo de ameaça

Normalmente pensamos em dashboard como visualização.

Nesse tipo de produto, ele também é parte da superfície de privacidade.

Recursos que parecem inocentes começam a merecer atenção:

  • filtros combináveis;
  • exportação para CSV;
  • comparação entre períodos;
  • comentários individuais;
  • resultados por departamento;
  • resultados por gestor;
  • busca;
  • drill-down;
  • filtros demográficos.

Quanto mais flexível o analytics, maior a capacidade do usuário de fazer perguntas específicas sobre subconjuntos pequenos.

Então aparece uma tensão interessante de produto:

flexibilidade do dashboard
        VS
proteção contra reidentificação

O cliente geralmente quer mais filtros.

O sistema precisa saber quando dizer não.

Comentário aberto é quase dado pessoal por acidente

Perguntas abertas são extremamente úteis.

O número diz:

Reconhecimento: 3.1

O comentário explica:

O projeto que liderei desde janeiro foi entregue, mas meu gestor apresentou o resultado como trabalho dele.

Agora você entende melhor o problema.

Só que provavelmente também ficou muito mais fácil descobrir quem escreveu.

Comentários podem revelar:

  • projeto;
  • gestor;
  • data;
  • cliente;
  • função;
  • estilo de escrita;
  • situações muito específicas.

Então mesmo em uma pesquisa tecnicamente anônima, o próprio usuário pode se identificar sem perceber.

Isso cria algumas decisões de produto.

Você mostra comentários de grupos pequenos?

Permite filtrar comentários?

Permite busca?

Agrupa tudo?

Oculta comentários até existir determinado volume?

Remove metadados?

Mais uma vez, não existe uma resposta única.

Mas o risco precisa fazer parte da modelagem.

Analytics também merece desconfiança

Outra armadilha simples:

Você remove IP do backend da pesquisa.

Ótimo.

Mas coloca Google Analytics, Hotjar ou outra ferramenta na página.

Agora o fluxo pode acabar envolvendo:

analytics_cookie
session_id
page_view
device_data
timestamp

O sistema principal não identifica o funcionário.

Um serviço terceiro talvez consiga correlacionar aquela navegação.

Isso não significa que analytics seja automaticamente incompatível com uma pesquisa privada.

Significa que:

se anonimato é requisito do produto, scripts de terceiros também fazem parte do threat model.

A pergunta deixa de ser:

Nosso banco salva IP?

e passa a ser:

Alguma parte da stack recebe informação que possa identificar quem está respondendo?

Até o timestamp pode ajudar a identificar alguém

Imagine uma pesquisa respondida às:

14:03:41

E o sistema corporativo registra que apenas uma pessoa entrou na página naquele horário.

Separadamente, cada dado parece inofensivo.

Juntos, podem ser suficientes.

Isso é importante porque reidentificação normalmente não depende de um único campo mágico.

Ela acontece pela combinação de informações.

timestamp
+
departamento
+
cargo
+
comentário
+
atividade em outro sistema

Às vezes isso é tudo que alguém precisa.

Então devemos eliminar toda segmentação?

Provavelmente não.

Se você remover toda possibilidade de segmentação, o resultado pode ficar pouco útil.

Imagine uma empresa com 2 mil funcionários.

O dashboard diz:

Clima geral: 4.1

Ótimo.

Mas uma área pode estar em:

2.3

e o problema desaparece dentro da média.

Segmentação é necessária justamente porque decisões acontecem em grupos menores.

O desafio não é:

impedir segmentação.

É:

oferecer segmentação suficiente para gerar informação útil sem transformar o dashboard numa ferramenta de identificação.

Esse equilíbrio é provavelmente mais interessante que o formulário em si.

A pergunta que eu faria antes de criar o schema

Se estivesse desenhando uma plataforma de pesquisas internas hoje, eu tentaria responder cedo:

  • O sistema precisa saber quem respondeu?
  • Participação e resposta precisam estar na mesma tabela?
  • IP realmente precisa ser persistido?
  • Analytics é necessário nessa página?
  • Qual é o menor grupo que podemos mostrar?
  • O threshold é aplicado depois de todos os filtros?
  • Dois relatórios diferentes permitem inferir uma resposta?
  • Comentários podem ser exibidos em grupos pequenos?
  • Quem consegue exportar os dados?
  • Existe algum endpoint interno que retorna respostas individuais?
  • Administradores conseguem contornar as regras de agregação?
  • Logs de infraestrutura preservam informações que a aplicação diz não coletar?

Porque depois que o produto já foi construído supondo:

response belongs_to employee

mudar para um modelo realmente anônimo pode exigir muito mais do que remover uma coluna.

O problema não é esconder o nome

Quanto mais pensamos nesse tipo de sistema, menos útil parece a definição:

Pesquisa anônima é uma pesquisa sem nome.

Uma definição mais prática seria algo próximo de:

O sistema foi desenhado para reduzir a capacidade de relacionar uma resposta a uma pessoa específica, tanto na coleta quanto na análise posterior.

Isso inclui:

coleta
+
infraestrutura
+
armazenamento
+
autorização
+
agregação
+
filtros
+
exportações
+
comentários

O anonimato não é uma feature isolada.

É uma propriedade emergente de várias decisões arquiteturais.

E talvez a parte mais perigosa nem esteja na tela onde o funcionário responde.

Pode estar no dashboard que alguém abre depois.


Trabalho como CTO e cofundador da Sigilo, onde desenvolvemos sistemas de denúncias, pesquisas e feedback organizacional. Essa discussão surgiu justamente ao pensar em como oferecer análises úteis para empresas sem destruir a confiança de quem responde.

Uma dúvida que eu gostaria de jogar para vocês:

como vocês modelariam a proteção contra reidentificação?

Threshold simples por número de respostas?

Regras próprias na aplicação?

Algum conceito próximo de k-anonymity?

Ou limitariam deliberadamente a capacidade de combinar filtros no produto?

Carregando publicação patrocinada...
1

Separar participação de resposta sem chave entre as duas ainda deixa a ordem de inserção como ponte. Se responded_at fica na tabela de participação e created_at na de resposta, dá pra casar as duas pelo horário, e id sequencial (ou UUIDv7, que carrega o timestamp) faz a mesma coisa pela ordem. Eu guardaria só a data no created_at, ou nem guardaria, e usaria UUID aleatório.

Sobre a pergunta do fim: o ataque por diferença que você descreveu é o que os institutos de estatística tratam com supressão complementar. Quando uma célula fica abaixo do mínimo, esconde também outra da mesma linha ou coluna, pra conta de subtração não fechar. No produto eu iria pelo caminho de limitar, com segmentos fixos definidos antes da pesquisa no lugar de filtros que combinam à vontade, porque aí dá pra checar todas as combinações antes de mostrar qualquer coisa.