Ruoli e permessi in un SaaS: evitare che un utente veda i dati degli altri 🔐🏢

Ruoli e permessi in un SaaS

In un gestionale SaaS, il login è solo il primo livello di sicurezza. Il vero problema arriva dopo: che cosa può leggere o modificare ciascun utente? 🔐

Un amministratore del negozio deve poter gestire i propri collaboratori, ma non quelli di un altro negozio. Un operatore può consultare gli appuntamenti che gli competono, ma non necessariamente esportare tutti i dati dei clienti. E il super amministratore della piattaforma ha responsabilità diverse da quelle di un normale account.

Autenticazione e autorizzazione non sono la stessa cosa

L’autenticazione risponde alla domanda «chi sei?». L’autorizzazione risponde a «puoi eseguire questa operazione su questa risorsa?». Confonderle è una delle cause più comuni delle vulnerabilità nei gestionali.

Nascondere un pulsante nell’interfaccia non equivale a proteggere un’azione. Un utente può inviare richieste HTTP direttamente all’endpoint, anche se non vede il pulsante.

RBAC: partire dai ruoli, senza fermarsi ai ruoli

Il modello Role-Based Access Control (RBAC) associa i permessi a ruoli come proprietario, amministratore, collaboratore e cliente. È un buon punto di partenza perché rende le regole comprensibili e verificabili.

Ma sapere che un utente ha il ruolo di «collaboratore» non basta. Bisogna controllare anche a quale organizzazione appartiene e se la risorsa richiesta è davvero nel suo ambito.

Il controllo del tenant è indispensabile

Supponiamo che l’applicazione esponga /api/clienti/125. Se il backend controlla solo che l’utente sia autenticato, potrebbe restituire il cliente 125 anche quando appartiene a un’altra organizzazione. È un caso tipico di autorizzazione a livello di oggetto non corretta, spesso indicato come BOLA o IDOR.

La query deve restringere il risultato all’organizzazione autorizzata. In un’architettura con database condiviso, il filtro sul tenant_id va applicato sistematicamente, anche per aggiornamenti, cancellazioni, esportazioni e operazioni batch.

Un esempio pratico con PHP e MariaDB 🧩

Un controllo robusto combina permesso e proprietà della risorsa. La logica può essere espressa così:

$tenantId = $currentUser['tenant_id'];
$clientId = (int) $request['client_id'];

if (!can($currentUser, 'clients.view')) {
    http_response_code(403);
    exit;
}

$stmt = $pdo->prepare(
    'SELECT id, name FROM clients WHERE id = ? AND tenant_id = ?'
);
$stmt->execute([$clientId, $tenantId]);
$client = $stmt->fetch(PDO::FETCH_ASSOC);

if (!$client) {
    http_response_code(404);
    exit;
}

Questo esempio è volutamente essenziale: in un progetto reale servono anche gestione centralizzata delle eccezioni, logging appropriato e controlli specifici sulle azioni. La parte importante è che l’identificativo del tenant non venga preso ciecamente dalla richiesta del browser, ma dal contesto autenticato e autorizzato.

Separare i permessi dalle schermate

È utile definire permessi espliciti come appointments.read, appointments.manage, clients.export e billing.manage. In questo modo lo stesso controllo può essere riutilizzato nell’interfaccia, nelle API e nelle automazioni, senza duplicare logiche fragili.

Un super admin merita un percorso separato, con privilegi elevati tracciati e usati solo quando necessario. Non dovrebbe diventare una scorciatoia per bypassare indiscriminatamente ogni controllo.

Test che non dovrebbero mancare

  • Un utente del tenant A prova a leggere un record del tenant B.
  • Un collaboratore prova a eseguire un’azione riservata all’amministratore.
  • Un utente cambia manualmente un ID nella URL o nel corpo JSON.
  • Un’esportazione massiva include soltanto i record autorizzati.
  • Un job asincrono conserva il contesto del tenant corretto.
  • Un account rimosso dall’organizzazione perde subito l’accesso alle risorse.

Audit e principio del minimo privilegio

Le operazioni sensibili dovrebbero lasciare tracce utili: chi ha eseguito l’azione, quando e su quale risorsa. Evita però di registrare password, token o dati personali non necessari. Il principio guida resta il minimo privilegio: ogni ruolo ottiene solo ciò che serve davvero.

Per un riferimento tecnico, consulta l’OWASP API Security Top 10: Broken Object Level Authorization.

FAQ

Controllare il ruolo nell’interfaccia è sufficiente?

No. Ogni operazione sensibile deve essere autorizzata sul server.

Un tenant_id nel database risolve il problema?

Da solo no: serve applicarlo correttamente a ogni percorso di accesso ai dati.

È meglio creare tanti ruoli?

Non necessariamente. Conviene partire da pochi ruoli chiari e permessi granulari, evitando combinazioni impossibili da mantenere.

Vuoi aggiungere qualcosa?

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *