Appearance
Secrets & Criptografia
Onde ficam os secrets
Em produção (Azure Key Vault)
Todos os secrets sensíveis ficam no Azure Key Vault. O deploy.sh busca automaticamente antes de fazer build.
O backend usa DefaultAzureCredential para acessar o Key Vault em runtime — sem secrets hardcoded na imagem.
Secrets no Key Vault:
CLERK-SECRET-KEYNEXT-PUBLIC-CLERK-PUBLISHABLE-KEYDATABASE-URLMASTER-ENCRYPTION-KEYCLERK-WEBHOOK-SECRETREDIS-PASSWORD- Tokens e credenciais de integrações
Em desenvolvimento
Arquivo .env.secrets na raiz do projeto (nunca commitado). Ver /inicio-rapido/variaveis-de-ambiente para a lista completa.
Criptografia de dados sensíveis no banco
Alguns dados são criptografados antes de salvar no banco usando AES-256-GCM (Authenticated Encryption):
MASTER_ENCRYPTION_KEY (env)
→ normalizado para 32 bytes via SHA-256
→ usado para cifrar/decifrar
Formato armazenado: {iv}:{encrypted_content}:{auth_tag}
iv: 16 bytes aleatórios (hex)
encrypted: ciphertext AES-256-GCM (hex)
auth_tag: tag de integridade GCM (hex)Dados criptografados:
| Campo | Tabela |
|---|---|
pass (senha SMTP por loja) | Store email config |
pass (senha SMTP da org) | OrganizationSmtpSettings |
token (Evolution/ZAPI) | StoreWhatsappNumber |
accessToken (Meta Cloud) | StoreWhatsappNumber |
appSecret (Meta webhook) | StoreWhatsappNumber |
A API nunca retorna esses valores em texto puro. Sempre retorna '********'. O valor real é descriptografado apenas internamente para enviar mensagens.
Hashing irreversível
CPF
CPF original → normalizar (remover pontos/traços) → SHA-256 → cpfHashO CPF em texto puro nunca é armazenado. Para busca, o sistema hasheia o CPF fornecido e compara com o hash.
Display: ***.***.*XX-** (campo cpfMasked — gerado no sync).
Tokens de survey
Tokens de pesquisa de satisfação são UUIDs aleatórios. O sistema armazena apenas tokenHash = SHA-256(token) — o token real é enviado ao cliente via URL e nunca fica no banco.
Webhook verify token (Meta WhatsApp)
O webhookVerifyToken é armazenado como SHA-256. Ao verificar um webhook entrante, o sistema hasheia o token recebido e compara.
Masked output de tokens WhatsApp
Ao listar instâncias WhatsApp via API:
token: sempre'********'accessToken: sempre'********'appSecret: sempre'********'
Ao criar uma nova instância: o token real é retornado uma única vez para o usuário copiar. Depois disso, só '********'.
Ao atualizar: se o campo enviado for '********', o valor atual é mantido sem re-criptografar.
Pseudonimização nos logs HTTP
O middleware HTTP log usa:
- IP: últimos octeto/grupos mascarados (IPv4:
x.x.x.*, IPv6: primeiros 4 grupos +****) - userId:
SHA-256(userId).substring(0, 12)— rastreável internamente mas não diretamente identificável em logs externos
Rotação de secrets
| Secret | Quando rotacionar | Impacto |
|---|---|---|
MASTER_ENCRYPTION_KEY | Em caso de comprometimento | Crítico — todos os dados criptografados ficam ilegíveis. Requer re-criptografia de todo o banco |
CLERK_SECRET_KEY | Em caso de comprometimento | Todos os usuários perdem sessão ativa |
CLERK_WEBHOOK_SECRET | A cada 6 meses (boas práticas) | Webhooks do Clerk param até nova configuração |
INTERNAL_API_KEY | Em caso de comprometimento | Integrações internas (n8n) param até atualizar |
| Tokens WhatsApp | Quando Meta expirar ou comprometer | Envio de mensagens para aquela loja para até reconfigurar |