> ## 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.

# Gestione dei Segreti e Crittografia

> Come Switchbord memorizza i segreti dei tenant in Supabase Vault, applica header di sicurezza e protegge i dati in transito e a riposo.

## Supabase Vault per i Segreti dei Tenant

Tutti i segreti dei tenant sono memorizzati in [Supabase Vault](https://supabase.com/docs/guides/database/vault), un'estensione di Postgres che cripta i segreti a livello di database. I segreti hanno ambito per workspace e non vengono mai memorizzati in tabelle dello schema pubblico.

### Tipi di Segreto

Ogni workspace può memorizzare i seguenti tipi di segreto in Vault:

| Tipo di Segreto          | Finalità                                                                      |
| ------------------------ | ----------------------------------------------------------------------------- |
| `meta-access-token`      | Token di accesso Meta (WhatsApp Business API) per l'invio dei messaggi        |
| `webhook-signing-secret` | Segreto di firma del payload dei webhook Meta per la verifica delle richieste |
| `meta-verify-token`      | Token di verifica del webhook Meta                                            |
| `openai-api-key`         | Chiave API OpenAI per la generazione di bozze AI                              |
| `anthropic-api-key`      | Chiave API Anthropic per la generazione AI basata su Claude                   |
| `openrouter-api-key`     | Chiave API OpenRouter per il routing AI multi-modello                         |

### Pattern di Accesso a Vault

I segreti vengono letti da Vault solo al momento dell'utilizzo, con ambito limitato al workspace richiedente:

```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;
}
```

I segreti del workspace A sono strutturalmente inaccessibili al workspace B — la funzione di lettura del vault è parametrizzata dall'ID del workspace, che viene sempre derivato dalla sessione autenticata.

## Nessun Fallback su Variabili d'Ambiente in Produzione

I fallback tramite variabili d'ambiente per i segreti sono **consentiti solo in ambienti non di produzione**:

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

  if (vaultSecret) return vaultSecret;

  // Fallback consentito solo fuori dalla produzione
  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');
}
```

Ciò garantisce che un deployment di produzione configurato in modo errato fallisca in modo evidente, piuttosto che ricadere silenziosamente su una credenziale condivisa.

<Warning>
  In produzione, se Vault non restituisce alcun segreto per un workspace, l'operazione fallisce con un errore. Non esiste alcuna credenziale di fallback globale che potrebbe essere inavvertitamente utilizzata da più tenant.
</Warning>

## Memorizzazione delle API Key

Le API key non vengono mai memorizzate in chiaro. Lo schema di memorizzazione:

1. **Generazione:** viene generato un token crittograficamente casuale
2. **Hashing:** il token viene sottoposto a hashing con SHA-256 prima della memorizzazione nel database
3. **Prefisso:** i primi 8 caratteri del token in chiaro vengono memorizzati separatamente per l'identificazione visuale
4. **Visualizzazione:** il token completo in chiaro viene mostrato all'utente esattamente una volta al momento della creazione

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

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

### Validazione Timing-Safe

La validazione delle chiavi utilizza `crypto.timingSafeEqual` per prevenire attacchi 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');

  // Il controllo della lunghezza non deve creare uno short-circuit prima di timingSafeEqual
  if (a.length !== b.length) return false;
  return timingSafeEqual(a, b);
}
```

## Header di Sicurezza

Tutte le risposte HTTP dell'applicazione Switchbord includono i seguenti header di sicurezza:

### 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
```

La direttiva `preload` invia il dominio alle liste di preload HSTS dei browser, garantendo connessioni solo HTTPS anche alla prima visita.

### Header Aggiuntivi

| Header                   | Valore                                     | Finalità                                    |
| ------------------------ | ------------------------------------------ | ------------------------------------------- |
| `X-Frame-Options`        | `DENY`                                     | Previene attacchi di clickjacking           |
| `X-Content-Type-Options` | `nosniff`                                  | Previene il MIME-type sniffing              |
| `Referrer-Policy`        | `strict-origin-when-cross-origin`          | Controlla le informazioni sul referrer      |
| `Permissions-Policy`     | `camera=(), microphone=(), geolocation=()` | Disattiva le API del browser non necessarie |

## Politica CORS

Il CORS è limitato a una allowlist esplicita di origini note:

```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; // procede
}
```

<Warning>
  Le restrizioni CORS impediscono le richieste cross-origin basate su browser da domini non autorizzati. Non impediscono le chiamate API dirette (ad es. da curl o server-to-server). L'autenticazione API è il controllo di accesso primario.
</Warning>

## Crittografia a Riposo

Supabase fornisce crittografia trasparente del disco per tutti i dati memorizzati nelle sue istanze PostgreSQL gestite. Questo copre le tabelle `contacts`, `messages`, `workspace_members`, `audit_logs` e tutte le altre.

**Miglioramento pianificato (BORD-171):** crittografia a livello di colonna per i campi PII (numeri di telefono, nomi, corpi dei messaggi) utilizzando l'estensione pgsodium di Supabase. Questo fornirebbe una crittografia a livello applicativo in aggiunta alla crittografia a livello di disco, proteggendo contro scenari in cui le credenziali del database vengono compromesse.

## TLS in Transito

Tutte le connessioni verso e da i componenti Switchbord sono crittografate utilizzando TLS:

* **Vercel (web/API):** TLS 1.2+ applicato dalla rete edge di Vercel
* **Supabase:** TLS richiesto per tutte le connessioni al database e all'API
* **Railway (worker):** TLS applicato per tutte le chiamate HTTP in uscita
* **Meta Cloud API:** tutte le chiamate all'API WhatsApp effettuate su HTTPS
* **Provider AI:** tutte le chiamate API a OpenAI, Anthropic, OpenRouter effettuate su HTTPS

## Protezione da Open Redirect

L'endpoint di callback dell'autenticazione valida il parametro di redirect `next` per prevenire attacchi di open redirect:

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

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

// Nel callback di autenticazione
const next = searchParams.get('next') ?? '/';
const redirectTo = isSafeRedirect(next) ? next : '/';
```

## Validazione degli Input

Tutti i corpi delle richieste API principali vengono validati con schemi Zod prima dell'elaborazione:

```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 });
    // Gli errori Zod vengono registrati lato server ma non restituiti ai client
  }
  // ...
}
```

Le risposte di errore sono sanificate — gli errori grezzi di Supabase o del database non vengono mai restituiti ai client.

## Mappatura della Conformità

| Standard  | Controllo                                          | Implementazione                                                              |
| --------- | -------------------------------------------------- | ---------------------------------------------------------------------------- |
| ISO 27001 | A.10.1 — Controlli crittografici                   | Hashing SHA-256 delle API key, TLS in transito, crittografia Vault           |
| ISO 27001 | A.13.1 — Gestione della sicurezza della rete       | Allowlist CORS, header di sicurezza                                          |
| ISO 27001 | A.13.2 — Trasferimento delle informazioni          | TLS applicato su tutte le connessioni                                        |
| ISO 27001 | A.14.2 — Sicurezza nello sviluppo                  | Validazione degli input (Zod), sanificazione dell'output                     |
| GDPR      | Art.32 — Sicurezza del trattamento                 | Crittografia a riposo e in transito, controlli di accesso                    |
| HIPAA     | §164.312(a)(2)(iv) — Crittografia e decrittografia | TLS in transito, crittografia Vault a riposo                                 |
| HIPAA     | §164.312(e)(2)(ii) — Crittografia in transito      | TLS applicato su tutte le connessioni esterne                                |
| SOC 2     | CC6.1 — Controlli di accesso logico                | Hashing delle API key, confronto timing-safe                                 |
| SOC 2     | CC6.7 — Dati in transito e a riposo                | TLS + crittografia del disco + crittografia a livello di colonna pianificata |

<Tip>
  Per la mappatura completa dei controlli di conformità, vedi la [Matrice di Conformità](/it/security/compliance-matrix).
</Tip>
