> ## Documentation Index
> Fetch the complete documentation index at: https://docs.switchbord.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Gestão de Segredos e Criptografia

> Como a Switchbord armazena segredos de tenants no Supabase Vault, aplica cabeçalhos de segurança e protege os dados em trânsito e em repouso.

## Supabase Vault para Segredos de Tenants

Todos os segredos de tenants são armazenados no [Supabase Vault](https://supabase.com/docs/guides/database/vault), uma extensão do Postgres que criptografa segredos no nível do banco de dados. Os segredos são escopados por workspace e nunca armazenados em tabelas do schema público.

### Tipos de Segredo

Cada workspace pode armazenar os seguintes tipos de segredo no Vault:

| Tipo de Segredo          | Finalidade                                                                         |
| ------------------------ | ---------------------------------------------------------------------------------- |
| `meta-access-token`      | Token de acesso da Meta (WhatsApp Business API) para envio de mensagens            |
| `webhook-signing-secret` | Segredo de assinatura de payload de webhook da Meta para verificação de requisição |
| `meta-verify-token`      | Token de verificação de webhook da Meta                                            |
| `openai-api-key`         | Chave de API da OpenAI para geração de rascunhos por IA                            |
| `anthropic-api-key`      | Chave de API da Anthropic para geração de IA baseada em Claude                     |
| `openrouter-api-key`     | Chave de API da OpenRouter para roteamento de IA multi-modelo                      |

### Padrão de Acesso ao Vault

Os segredos são lidos do Vault apenas no momento do uso, escopados ao workspace requisitante:

```typescript theme={null}
async function getWorkspaceSecret(
  workspaceId: string,
  kind: SecretKind
): Promise<string> {
  const { data, error } = await supabase.rpc('vault_read_secret', {
    p_workspace_id: workspaceId,
    p_kind: kind,
  });

  if (error || !data) throw new SecretNotFoundError(kind);
  return data.secret_value;
}
```

Os segredos do workspace A são estruturalmente inacessíveis ao workspace B — a função de leitura do vault é parametrizada pelo ID do workspace, que é sempre derivado da sessão autenticada.

## Sem Fallback de Variável de Ambiente em Produção

Os fallbacks de variáveis de ambiente para segredos ficam **restritos exclusivamente a ambientes não produtivos**:

```typescript theme={null}
async function resolveMetaToken(workspaceId: string): Promise<string> {
  // Sempre tenta o Vault primeiro
  const vaultSecret = await getWorkspaceSecret(workspaceId, 'meta-access-token')
    .catch(() => null);

  if (vaultSecret) return vaultSecret;

  // Fallback permitido apenas fora de produção
  if (process.env.NODE_ENV !== 'production' && process.env.META_ACCESS_TOKEN) {
    return process.env.META_ACCESS_TOKEN;
  }

  throw new ConfigurationError('No Meta access token configured for this workspace');
}
```

Isso garante que uma implantação de produção mal configurada falhará de forma explícita, em vez de recorrer silenciosamente a uma credencial compartilhada.

<Warning>
  Em produção, se o Vault não retornar nenhum segredo para um workspace, a operação falha com um erro. Não existe credencial de fallback global que possa ser inadvertidamente usada por múltiplos tenants.
</Warning>

## Armazenamento de Chaves de API

As chaves de API nunca são armazenadas em texto puro. O esquema de armazenamento:

1. **Geração:** É gerado um token criptograficamente aleatório
2. **Hashing:** O token é hasheado com SHA-256 antes do armazenamento no banco de dados
3. **Prefixo:** Os primeiros 8 caracteres do token bruto são armazenados separadamente para identificação de exibição
4. **Exibição:** O token bruto completo é exibido ao usuário exatamente uma vez, no momento da criação

```typescript theme={null}
import { createHash, randomBytes } from 'crypto';

function generateApiKey() {
  const raw = randomBytes(32).toString('hex'); // string hexadecimal de 64 caracteres
  const hash = createHash('sha256').update(raw).digest('hex');
  const prefix = raw.slice(0, 8);
  return { raw, hash, prefix };
}
```

### Validação com Timing Seguro

A validação de chaves usa `crypto.timingSafeEqual` para evitar ataques de oráculo de temporização (timing oracle):

```typescript theme={null}
import { timingSafeEqual, createHash } from 'crypto';

function isValidApiKey(providedRaw: string, storedHash: string): boolean {
  const providedHash = createHash('sha256').update(providedRaw).digest('hex');
  const a = Buffer.from(providedHash, 'hex');
  const b = Buffer.from(storedHash, 'hex');

  // A verificação de comprimento não deve interromper antes do timingSafeEqual
  if (a.length !== b.length) return false;
  return timingSafeEqual(a, b);
}
```

## Cabeçalhos de Segurança

Todas as respostas HTTP da aplicação Switchbord incluem os seguintes cabeçalhos de segurança:

### Política de Segurança de Conteúdo (Content Security Policy)

```
Content-Security-Policy: default-src 'self';
  script-src 'self' 'nonce-{nonce}';
  style-src 'self' 'unsafe-inline';
  img-src 'self' data: https:;
  connect-src 'self' https://*.supabase.co wss://*.supabase.co;
  frame-ancestors 'none';
```

### HTTP Strict Transport Security

```
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
```

A diretiva `preload` submete o domínio às listas de pré-carregamento HSTS dos navegadores, garantindo conexões somente HTTPS mesmo na primeira visita.

### Cabeçalhos Adicionais

| Cabeçalho                | Valor                                      | Finalidade                                  |
| ------------------------ | ------------------------------------------ | ------------------------------------------- |
| `X-Frame-Options`        | `DENY`                                     | Previne ataques de clickjacking             |
| `X-Content-Type-Options` | `nosniff`                                  | Previne detecção indevida de tipo MIME      |
| `Referrer-Policy`        | `strict-origin-when-cross-origin`          | Controla as informações de referrer         |
| `Permissions-Policy`     | `camera=(), microphone=(), geolocation=()` | Desabilita APIs de navegador desnecessárias |

## Política de CORS

O CORS é restrito a uma allowlist explícita de origens conhecidas:

```typescript theme={null}
const ALLOWED_ORIGINS = [
  'https://app.switchbord.ai',
  ...(process.env.NODE_ENV !== 'production' ? ['http://localhost:3000'] : []),
];

function corsMiddleware(req: Request): Response | null {
  const origin = req.headers.get('Origin');
  if (origin && !ALLOWED_ORIGINS.includes(origin)) {
    return new Response('Forbidden', { status: 403 });
  }
  return null; // segue em frente
}
```

<Warning>
  As restrições de CORS impedem requisições cross-origin baseadas em navegador de domínios não autorizados. Elas não impedem chamadas diretas de API (por exemplo, via curl ou servidor a servidor). A autenticação de API é o principal controle de acesso.
</Warning>

## Criptografia em Repouso

O Supabase fornece criptografia de disco transparente para todos os dados armazenados em suas instâncias PostgreSQL gerenciadas. Isso abrange as tabelas `contacts`, `messages`, `workspace_members`, `audit_logs` e todas as demais tabelas.

**Melhoria planejada (BORD-171):** Criptografia em nível de coluna para campos de PII (números de telefone, nomes, corpos de mensagens) usando a extensão pgsodium do Supabase. Isso forneceria criptografia em nível de aplicação além da criptografia em nível de disco, protegendo contra cenários em que as credenciais do banco de dados sejam comprometidas.

## TLS em Trânsito

Todas as conexões de e para os componentes da Switchbord são criptografadas usando TLS:

* **Vercel (web/API):** TLS 1.2+ aplicado pela rede de edge da Vercel
* **Supabase:** TLS obrigatório para todas as conexões de banco de dados e API
* **Railway (worker):** TLS aplicado para todas as chamadas HTTP de saída
* **Meta Cloud API:** Todas as chamadas da API do WhatsApp feitas via HTTPS
* **Providers de IA:** Todas as chamadas de API para OpenAI, Anthropic, OpenRouter feitas via HTTPS

## Proteção contra Redirecionamento Aberto

O endpoint de callback de autenticação valida o parâmetro de redirecionamento `next` para prevenir ataques de redirecionamento aberto (open redirect):

```typescript theme={null}
function isSafeRedirect(url: string): boolean {
  // Permite caminhos relativos
  if (url.startsWith('/') && !url.startsWith('//')) return true;

  // Permite origens conhecidas
  const allowedOrigins = ['https://app.switchbord.ai'];
  try {
    const parsed = new URL(url);
    return allowedOrigins.some(origin => parsed.origin === origin);
  } catch {
    return false;
  }
}

// No callback de autenticação
const next = searchParams.get('next') ?? '/';
const redirectTo = isSafeRedirect(next) ? next : '/';
```

## Validação de Entrada

Todos os corpos das principais requisições de API são validados com schemas Zod antes do processamento:

```typescript theme={null}
const CreateContactSchema = z.object({
  phoneNumber: z.string().regex(/^\+[1-9]\d{1,14}$/),
  name: z.string().min(1).max(255).optional(),
  customFields: z.record(z.string()).optional(),
});

export async function POST(req: Request) {
  const body = await req.json();
  const parsed = CreateContactSchema.safeParse(body);

  if (!parsed.success) {
    return Response.json({ error: 'Invalid request' }, { status: 400 });
    // Erros do Zod são registrados no servidor, mas não retornados aos clientes
  }
  // ...
}
```

As respostas de erro são higienizadas — erros brutos do Supabase ou do banco de dados nunca são retornados aos clientes.

## Mapeamento de Conformidade

| Padrão    | Controle                                            | Implementação                                                           |
| --------- | --------------------------------------------------- | ----------------------------------------------------------------------- |
| ISO 27001 | A.10.1 — Controles criptográficos                   | Hash SHA-256 de chaves de API, TLS em trânsito, criptografia do Vault   |
| ISO 27001 | A.13.1 — Gestão de segurança de rede                | Allowlist de CORS, cabeçalhos de segurança                              |
| ISO 27001 | A.13.2 — Transferência de informação                | TLS aplicado em todas as conexões                                       |
| ISO 27001 | A.14.2 — Segurança no desenvolvimento               | Validação de entrada (Zod), higienização de saída                       |
| GDPR      | Art.32 — Segurança do tratamento                    | Criptografia em repouso e em trânsito, controles de acesso              |
| HIPAA     | §164.312(a)(2)(iv) — Criptografia e descriptografia | TLS em trânsito, criptografia do Vault em repouso                       |
| HIPAA     | §164.312(e)(2)(ii) — Criptografia em trânsito       | TLS aplicado em todas as conexões externas                              |
| SOC 2     | CC6.1 — Controles de acesso lógico                  | Hash de chave de API, comparação com timing seguro                      |
| SOC 2     | CC6.7 — Dados em trânsito e em repouso              | TLS + criptografia de disco + criptografia em nível de coluna planejada |

<Tip>
  Para o mapeamento completo de controles de conformidade, veja a [Matriz de Conformidade](/pt-BR/security/compliance-matrix).
</Tip>
