
Indice dei contenuti
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.
