Para equipes de segurança da informação e revisores de apps

Segurança no Peel

A versão curta: o conteúdo do quadro é cifrado no navegador com uma chave que vive no fragmento do link, por isso os nossos servidores guardam e retransmitem texto cifrado que não conseguem ler. Aqui está exatamente como, e onde ficam os limites.

Resumo

  • O texto dos cartões, os nomes, os títulos dos quadros, os votos e os stickers são cifrados com AES-256-GCM sob uma chave de quadro gerada no navegador. A chave viaja no fragmento da URL (#k=) e nunca é enviada a um servidor.
  • As ações do facilitador, o cabeçalho do quadro e os snapshots são assinados com a chave Ed25519 do facilitador. O ID do quadro é derivado dessa chave, por isso os clientes notam qualquer troca de chave.
  • Os cartões ocultos ficam selados para o facilitador (sealed box X25519) até a revelação, e vinculados por compromissos com sal para que o texto revelado não possa ser trocado.
  • Anonimato por padrão: as operações não levam ID de autor; votos e reações usam um ID aleatório por quadro.
  • Os participantes nunca se autenticam. Sem SDKs de analytics, sem anúncios, sem scripts de terceiros, exceto o Paddle.js na página de checkout.
  • Só Cloudflare. Quadros não reivindicados são apagados 60 dias após a última visita.

Como os dados circulam

O fragmento de uma URL (tudo o que vem depois do #) é tratado pelo navegador e não faz parte do pedido HTTP. É aí que o Peel coloca a chave do quadro.

Fluxo de dados: a chave é lida localmente a partir do link; só o texto cifrado e metadados mínimos atravessam a rede.

Modelo de ameaças

Projetamos tudo para que um servidor totalmente comprometido ou curioso, incluindo nós, saiba o mínimo possível sobre o que uma equipe diz.

O que protegemos

  • O texto dos cartões, os GIFs escolhidos e, no modo com nome, o nome de quem escreveu.
  • Os nomes e avatares dos participantes, o nome do quadro e os títulos de modelos personalizados.
  • Quem votou ou reagiu a quê, e quem escreveu cada cartão.
  • A integridade da retro: etapas, revelações e decisões do facilitador não podem ser forjadas.

Adversários que consideramos

  • Os nossos próprios servidores, alguém de dentro com más intenções ou quem invada o nosso armazenamento: obtêm texto cifrado e metadados.
  • Um atacante na rede: TLS em todo o tráfego; a chave nunca atravessa a rede.
  • Um servidor que troca chaves: o ID do quadro é derivado da chave pública do facilitador, e os clientes verificam o cabeçalho assinado.
  • Um participante que quer espiar ou forjar: os cartões ocultos ficam selados para o facilitador; as operações do facilitador exigem a assinatura dele; editar um cartão exige a chave desse cartão.
  • Um facilitador que republica por um autor offline: os compromissos o impedem de mudar o texto.

Fora do âmbito, com honestidade

  • Quem tiver o link de participante pode ler o quadro. É o link que dá acesso. Compartilhe-o com o mesmo cuidado que o próprio quadro.
  • Um dispositivo comprometido, uma extensão de navegador maliciosa ou alguém que olha por cima do seu ombro.
  • Análise de tráfego: o servidor vê horários, tamanhos e contagens (veja o mapa de dados).
  • Negação de serviço pelo servidor: ele pode descartar ou atrasar mensagens, mas não lê-las nem forjá-las.

Criptografia

Todas as primitivas vêm da API WebCrypto do navegador. Sem criptografia caseira, sem bibliotecas criptográficas de terceiros.

ChaveAlgoritmoUsada para
K_boardAES-256-GCM, IV aleatório de 96 bitsCifra cada operação, snapshot e atualização de presença. Os dados adicionais vinculam o ID do quadro, o tipo e o ID da operação, para que o texto cifrado não possa ser reaproveitado noutro quadro ou noutra posição. Vive apenas no fragmento do link #k=.
K_ownerEd25519A autoridade do facilitador. Assina as operações do facilitador (etapa, temporizador, destaque, modelo, configurações, abertura dos votos, ocultar um cartão), o cabeçalho do quadro e os snapshots. Um contador estritamente crescente bloqueia repetições. Só no link de facilitador (&o=).
ID do quadroSHA-256, primeiros 80 bits, base32Derivado da chave pública do facilitador, por isso o próprio ID prova a que chave o quadro pertence. Os clientes rejeitam um cabeçalho cuja chave não gere esse ID.
K_facSealed box X25519: X25519 temporária + HKDF-SHA256 + AES-256-GCMOs cartões ocultos são selados com a chave pública do facilitador enquanto as pessoas escrevem. Só o link de facilitador (&f=) consegue abri-los.
Chaves de cartãoEd25519, uma chave por cartãoSó o autor a tem. As edições e a revelação são assinadas com ela: autenticidade sem identidade.
CompromissosHMAC-SHA256 com sal aleatório de 128 bitsUm cartão oculto publica um compromisso sobre o seu conteúdo. Na revelação, o conteúdo e o sal são publicados e cada cliente os verifica, por isso ninguém consegue trocar o texto.
PresençaAES-256-GCM com K_boardNomes, avatares e indicadores de escrita são cifrados como todo o resto.
Pacote de chavesHKDF-SHA256 a partir do PRF da passkey ou do código de recuperação, AES-256-GCMFacilitadores com conta podem sincronizar as chaves dos quadros entre dispositivos. O pacote é cifrado no dispositivo; o servidor guarda apenas texto cifrado e chaves encapsuladas.

As mensagens assinadas são separadas por domínio (por exemplo peel/sig/v1, peel/header/v1, peel/snap/v1) para que uma assinatura feita para um fim não possa ser reutilizada para outro.

Cartões ocultos e a revelação

  1. Durante a escrita, o navegador do autor sela o cartão com a chave X25519 do facilitador e publica um compromisso com sal. O texto em claro fica no dispositivo do autor.
  2. Os outros participantes veem um cartão oculto: não conseguem decifrá-lo, e o servidor também não.
  3. O navegador do facilitador consegue abrir os cartões selados (a pré-visualização “👁 só você”).
  4. Na revelação, cada autor republica o seu cartão cifrado com K_board, assinado com a chave do cartão, junto com o sal.
  5. Se um autor estiver offline, o facilitador republica por ele. Cada cliente verifica o compromisso, por isso o texto tem de corresponder ao que o autor escreveu.

Como o facilitador pode tecnicamente pré-visualizar, cada quadro mostra a todos o aviso “o facilitador pode pré-visualizar” enquanto houver cartões ocultos. Não é uma configuração que se possa esconder.

Anonimato

  • As operações não levam ID de autor. O servidor não consegue ligar um cartão a uma pessoa e, por padrão, o facilitador também não.
  • Votos e reações ficam associados a um ID aleatório por quadro, sem ligação a nenhum nome.
  • Os indicadores de escrita mostram que alguém escreve, nunca o quê.
  • O modo com nome é uma configuração explícita do quadro; nesse caso, o nome do autor viaja dentro do cartão cifrado.
  • Os participantes nunca entram numa conta, por isso não há conta para cruzar.

Mapa de dados

Tudo o que guardamos, onde fica, quem pode ler e por quanto tempo.

DadosOndeQuem pode lerRetenção
Cartões, votos, reações, stickers, ações, nome do quadro, títulos de modelos personalizadosArmazenamento do Durable Object, como texto cifradoQuem tem o link do quadroAté o quadro ser apagado
Envelope da operação: tipo, sequência e hora do servidor, tamanho, contador do facilitadorArmazenamento do Durable ObjectPeelAté o quadro ser apagado
Nomes e avatares dos participantes, indicador de escritaRetransmitidos como texto cifrado; em memória durante a conexãoQuem tem o link do quadroDurante a conexão
Estado do quadro: etapa, número de participantes e de cartões, ID do modelo do catálogo, indicador de bloqueio, datas de criação e de expiraçãoDurable Object, D1; mensagens do Slack/Teams, se instaladoPeel; o seu canal do Slack/TeamsDuração do quadro
Conta de facilitador: ID do provedor, nome, e-mail se compartilhado, provedores ligados, data de criação, sessãoD1PeelAté você apagar a conta
Pacote de chaves e chaves encapsuladasD1, como texto cifradoSó você (passkey ou código de recuperação)Até você apagar a conta
Plano, estado da assinatura, IDs de cliente e de assinatura da PaddleD1; PaddlePeel, PaddleConforme exigido pela lei fiscal
IDs de workspace, canal e mensagem do Slack/Teams; token do bot (cifrado com AES-GCM)D1PeelAté a desinstalação
Endereço IPEdge da Cloudflare, de forma transitória (entrega, limites de taxa)Cloudflare, o limitador de taxa do PeelNão guardado nas nossas bases de dados
Contadores diários (quadros criados, etapas alcançadas)D1PeelApenas agregados, sem identificadores

O que o nosso servidor pode e não pode fazer

Pode

  • Ver tipos de operação, tamanhos, horários, a etapa, o número de participantes e de cartões, o ID do modelo do catálogo e o indicador de bloqueio.
  • Descartar, atrasar ou recusar entregar operações (negação de serviço).
  • Ver endereços IP na borda da rede.
  • Contar quadros e etapas alcançadas, de forma agregada.
  • Apagar um quadro (expiração, denúncias de abuso).

Não pode

  • Ler o texto dos cartões, nomes, títulos de quadros, títulos de modelos personalizados, votos ou stickers.
  • Ler cartões ocultos antes da revelação (nem depois).
  • Forjar ações do facilitador: elas exigem a assinatura dele.
  • Enfiar as suas próprias chaves: o ID do quadro denunciaria a troca.
  • Mudar o texto revelado de um cartão: os compromissos e as assinaturas dos cartões denunciariam a troca.
  • Saber quem escreveu cada cartão.

Como em qualquer app web, você confia no código que servimos. Mantemos essa superfície pequena: uma Content Security Policy rigorosa, script-src limitado à nossa própria origem, nenhum script de terceiros, e o protocolo fica aberto a revisão mediante pedido.

Slack e Microsoft Teams

  • As mensagens levam o link do quadro e metadados (título, etapa, contagens). O texto dos cartões só é enviado quando o facilitador publica um resumo e confirma.
  • O cartão de entrada contém o link de participante, que inclui a chave. Quem consegue ler esse canal pode entrar, tal como se o link tivesse sido colado lá.
  • As pré-visualizações de links mostram só a etapa e as contagens, nunca conteúdo.
  • Permissões do Slack (scopes): commands, chat:write, links:read, links:write; users:read só quando uma equipe ativa as menções.
  • Os tokens de bot são cifrados em repouso (AES-GCM, com a chave guardada como segredo do Worker). As assinaturas dos pedidos do Slack e os tokens do Bot Framework são verificados em cada pedido.
  • Desinstalar a integração interrompe todas as publicações e apaga os tokens dela.

Web e infraestrutura

  • Só Cloudflare: Pages, Workers, Durable Objects, D1, R2 e KV na conta da 1801 Labs. Nenhum outro servidor.
  • TLS em todo o tráfego, HSTS e uma Content Security Policy rigorosa.
  • Sem SDKs de analytics, sem anúncios, sem scripts de terceiros. A única exceção é o Paddle.js, carregado apenas na página de checkout.
  • Um único cookie, só para facilitadores com conta: peel_session, httpOnly, Secure, SameSite=Lax.
  • A pesquisa e o carregamento de GIFs e imagens passam pela nossa API, por isso os endereços IP dos participantes nunca chegam ao GIPHY.
  • Fontes e recursos hospedados por nós. Sem fontes de CDN, sem pixels de rastreamento.
  • Limites de taxa por IP e por quadro; denúncias de abuso e bloqueio pelo facilitador.

Contas e retenção

  • Os participantes nunca se autenticam. Os facilitadores entram com Google (ou Entra ID através do Teams) apenas para guardar quadros ou usar funções pagas.
  • Uma conta guarda um ID, o nome e o e-mail do provedor e um pacote de chaves cifrado, desbloqueado por uma passkey (WebAuthn PRF) ou por um código de recuperação. Entrar na conta dá a posse, não acesso ao conteúdo.
  • Reivindicar um quadro prova a posse com uma assinatura do facilitador. As chaves dos quadros nunca são enviadas.
  • Quadros sem conta são apagados 60 dias após a última visita; cada visita reinicia o prazo. Os alarmes do Durable Object apagam o armazenamento.
  • Apagar a conta apaga as sessões, o pacote de chaves e a biblioteca, e devolve aos quadros a expiração de 60 dias.

Divulgação responsável

Encontrou alguma coisa? Avise-nos primeiro e trabalharemos juntos. Confirmamos que recebemos cada relato no prazo de três dias úteis.

[email protected]

  • Dê-nos um prazo razoável (o nosso objetivo é 90 dias) para corrigir antes de divulgar.
  • Teste com os seus próprios quadros e contas. Não tente obter dados de outras pessoas nem degrade o serviço.
  • Não tomaremos medidas legais contra pesquisa de boa-fé que siga estas regras.
  • Endereço legível por máquina: /.well-known/security.txt.

Os clientes do plano Empresa recebem um pacote de avaliação de segurança (respostas a questionários, subprocessadores, fluxos de dados). DPA · Privacidade