Pitch: Anonimato de verdade: por que fugimos de CDN e apostamos no Tor via Arti
Estamos construindo o Zero Note, um app de notas criptografadas de ponta a ponta e sem cadastro pessoal (sem e-mail, sem telefone, sem nome). Um dos princípios do projeto é que o servidor é burro: ele guarda blobs cifrados e não consegue ler nada. Mas criptografia no conteúdo resolve só metade do problema. A outra metade é metadado de conexão e é sobre isso que quero falar aqui: a decisão de tirar o servidor de trás de qualquer CDN de terceiros e expor um endereço .onion usando Arti, a implementação do Tor em Rust.
O problema que criptografia não resolve
Cifrar o conteúdo da nota é a parte "fácil". O problema chato é que, mesmo com tudo cifrado, alguém no meio do caminho ainda enxerga:
- o IP de quem conectou;
- quando e com que frequência essa conta sincroniza;
- o tamanho aproximado de cada objeto trafegado.
Nenhuma dessas coisas é "conteúdo", mas juntas elas já dizem bastante sobre quem é a pessoa e o que ela está fazendo. Um adversário não precisa ler a nota se consegue correlacionar IP + horário + padrão de uso.
Por que isso descarta CDN gerenciado
A tentação óbvia seria colocar um CDN/proxy gerenciado na frente (Cloudflare e afins) por causa de TLS fácil, proteção contra DDoS e performance. O problema: esse tipo de serviço vê e normalmente registra o IP de cada conexão na própria borda da rede, antes de qualquer linha de código nosso rodar. Não importa o quão cuidadoso o nosso backend, ou seja, o vazamento já aconteceu uma camada antes.
Por isso a decisão foi: servidor próprio, em VPS, sem CDN de terceiros. A pilha ficou:
| Camada | Escolha | Motivo |
|---|---|---|
| Aplicação | Rust (axum) | Reaproveita o mesmo núcleo de criptografia do cliente |
| Metadados | PostgreSQL | Login, autenticação OPAQUE, sessões |
| Blobs | MinIO (S3-compatible) | Nunca exposto direto ao cliente, tudo passa pela aplicação |
| Borda | Caddy/nginx no próprio VPS | TLS, com logs de acesso desligados (sem IP, sem user agent completo) |
| Camada anônima | Tor via Arti | Endereço .onion nativo, sem IP de origem visível |
Arti: Tor, mas em Rust
A parte que mais vale comentar é o Tor. A decisão não foi "vamos adicionar Tor como feature exótica depois" é desde o início, com o .onion sempre disponível em paralelo ao acesso clearnet normal (que continua existindo porque Tor tem latência maior, pode ser bloqueado por operadoras, e nem toda loja de app aceita dependência exclusiva de Tor).
A escolha de implementação foi Arti em vez do daemon tor tradicional em C, por três razões práticas:
- É mantido pelo próprio Tor Project não é um fork de terceiros nem uma reimplementação não-oficial;
- É a reescrita oficial em Rust, e o próprio Tor Project pretende substituir o daemon C por ele a médio prazo;
- Evita misturar duas linguagens/stacks no servidor, já que a aplicação inteira é Rust (axum).
No app, vai existir nas Configurações "Conexão anônima (Tor)" ligada por padrão. Quando equanto ligada, o tráfego passa pelo .onion, escondendo o IP tanto do operador do servidor quanto de qualquer observador de rede no meio do caminho. Resolvemos deixar como opcional isso devido ao aumento de consumo de bateria que tem.
É importante ser honesto sobre o que isso resolve e o que não resolve:
- Resolve: o operador do servidor e um observador de rede deixam de ver o IP de origem de quem usa o
.onion. - Não resolve: o conteúdo. Esse já estava protegido antes, por criptografia ponta a ponta independente do Tor. Tor protege o metadado de conexão, não o conteúdo.
Antes de ir para produção, ainda temos umas validações pendentes: desempenho do serviço onion sob carga esperada, estabilidade do processo por período longo (dias) e compatibilidade com a versão do axum escolhida. Se algo falhar de forma grave nesses testes, a decisão é revisitada, mas a intenção declarada é não precisar rodar o daemon tor em paralelo como plano B.
Dois anonimatos diferentes, para um entendimento maior das escolhas
Um ponto que gerou confusão interna no início do projeto, e vale deixar explícito: existem dois anonimatos separados, e é fácil misturá-los por engano.
- Anonimato de quem usa o app: vem do Tor, da ausência de IP em logs e da criptografia ponta a ponta. Não depende de qual empresa hospeda o servidor.
- Anonimato de quem opera o serviço: é sobre o provedor de VPS saber (ou não) quem é a empresa por trás do servidor. Isso é segurança operacional do negócio, não da pessoa que escreve a nota.
Separar essas duas coisas destrava a escolha de provedor: dá pra priorizar custo-benefício e estabilidade de infraestrutura sem comprometer a privacidade de quem usa o produto. No caso do Zero Note, e da zerox1b, a decisão foi Hetzner (Alemanha, sob RGPD), mesmo exigindo KYC da empresa, porque esse KYC é sobre quem opera o negócio, não sobre quem escreve as notas. Quem precisa de distância entre a infraestrutura e o registro público (ex.: Njalla) ou de um provedor já alinhado com o discurso de privacidade (ex.: 1984 Hosting, na Islândia) está resolvendo o segundo problema, não o primeiro. Como a nosso plano é apenas fornecer anonimato para o usuário, optamos pela Hetzner.
Resumindo
Se o objetivo é anonimato de verdade para quem usa o produto, dá para listar três decisões de infraestrutura que, juntas, fecham boa parte do buraco que a criptografia sozinha não fecha:
- Nenhum CDN de terceiros na frente: ele vê o IP antes do seu código rodar.
.oniondesde o início, via Arti, não como feature tardia.- Separar anonimato do usuário de anonimato do operador: são problemas diferentes, com soluções diferentes, e misturá-los trava decisões que não precisam travar.
Esse é um corte do que estamos decidindo no Zero Note. Pretendo trazer mais artigos conforme o projeto avança, próximo na fila deve ser a hierarquia de chaves.