---
term: 'Sicurezza a livello di riga (RLS)'
seoTitle: 'Sicurezza a livello di riga (RLS): policy, limiti e insidie'
headline: 'Che cos''è la sicurezza a livello di riga (RLS)?'
slug: sicurezza-a-livello-di-riga-rls
category: database
shortDefinition: 'La sicurezza a livello di riga è un meccanismo del database in cui delle policy filtrano, a ogni query, le righe che ciascuno può vedere o modificare.'
relatedTerms:
  - access-control-lists-acl
  - class-level-permissions-clp
  - role-based-access-control-rbac
  - tenant-isolation
  - data-layer-vs-application-layer-security
contrastsWith:
  - class-level-permissions-clp
faq:
  - question: 'Che cos''è la sicurezza a livello di riga in parole semplici?'
    answer: 'Una clausola WHERE invisibile e obbligatoria. Si attaccano delle policy a una tabella e il database applica automaticamente le loro condizioni a ogni query: ciascun utente vede e modifica solo le righe che la policy consente, qualunque query scriva e qualunque strumento usi. Il filtro vive nel database, quindi nessun percorso di codice applicativo può dimenticarlo.'
  - question: 'Come funziona la sicurezza a livello di riga?'
    answer: 'Si abilita RLS su una tabella e si creano policy con predicati booleani – di solito confrontano la colonna del proprietario o del tenant di una riga con l''utente corrente o con una variabile di sessione. In esecuzione il motore valuta il predicato riga per riga prima delle condizioni scritte da chi interroga, filtrando le letture e bloccando le scritture non consentite. Una volta abilitato RLS senza nessuna policy, il comportamento predefinito è negare tutto.'
  - question: 'Qual è la differenza tra USING e WITH CHECK?'
    answer: 'La direzione. USING filtra ciò che esiste: le righe visibili a SELECT e quelle eleggibili per UPDATE o DELETE. WITH CHECK valida ciò che viene scritto: le righe inserite e i nuovi valori dopo un aggiornamento. Omettendo WITH CHECK il predicato di USING vale per entrambi – ma le tabelle dove si legge in modo ampio e si scrive in modo ristretto hanno bisogno di entrambi, definiti in modo diverso.'
  - question: 'Chi può aggirare la sicurezza a livello di riga?'
    answer: 'In PostgreSQL: i superutenti, i ruoli con BYPASSRLS e – quello che tutti dimenticano – il proprietario della tabella, a meno che non si imposti FORCE ROW LEVEL SECURITY. Verificare quella matrice di aggiramento fa parte del deployment di RLS; una policy perfetta non protegge nulla se l''applicazione si connette come proprietario della tabella.'
  - question: 'La sicurezza a livello di riga peggiora le prestazioni?'
    answer: 'Può farlo: il predicato della policy viene valutato sulle righe candidate a ogni query. Le contromisure sono le stesse in ogni esperienza di produzione: indicizzare le colonne a cui le policy fanno riferimento, tenere i predicati senza join (meglio delle funzioni o dei controlli di ruolo) e avvolgere le funzioni per richiesta perché vengano valutate una volta per query e non una volta per riga. Una policy su una colonna non indicizzata è una scansione completa con un distintivo di sicurezza.'
  - question: 'Qual è la differenza tra RLS e il filtraggio a livello applicativo?'
    answer: 'Dove si trova il confine. Il filtraggio applicativo restringe le query nel codice: flessibile, ma duplicato su ogni percorso di codice e aggirato da qualsiasi cosa parli direttamente con il database. RLS lo fa rispettare nel motore, coprendo ogni percorso di accesso, strumenti di amministrazione e altri servizi compresi. Il consenso è la difesa in profondità: restringere nell''applicazione per chiarezza, far rispettare nel database per sicurezza.'
  - question: 'Come si comporta RLS con il pooling delle connessioni?'
    answer: 'Con cautela. Le applicazioni che usano un pool si connettono con un solo utente del database, quindi le policy si appoggiano a una variabile di sessione per richiesta invece che all''identità della connessione: impostata al prelievo, letta dalla policy, azzerata alla restituzione. Con i pooler in modalità transazione l''impostazione deve avere portata di transazione, altrimenti il contesto di un tenant può trapelare nella richiesta successiva sulla stessa connessione. Questa interazione è il bug RLS più comune in produzione.'
  - question: 'Come si testano le policy di sicurezza a livello di riga?'
    answer: 'Impersonando ogni ruolo ed eseguendo tutte e quattro le operazioni – select, insert, update, delete – con la verifica sia di ciò che appare sia di ciò che viene rifiutato. Vanno aggiunti i due casi che si dimenticano: il contesto non impostato (nessuna variabile di tenant deve significare nessuna riga, non tutte le righe) e la matrice di aggiramento (proprietario, superutente, percorsi di replica). RLS si guadagna la fiducia con test avversariali, non perché la policy si legge bene.'
codeLanguages: [javascript, dart, swift, kotlin]
externalAuthorities:
  - name: 'PostgreSQL Row Security Policies'
    url: 'https://www.postgresql.org/docs/current/ddl-rowsecurity.html'
  - name: 'PostgreSQL CREATE POLICY reference'
    url: 'https://www.postgresql.org/docs/current/sql-createpolicy.html'
  - name: 'Row-Level Security and Multi-Tenancy on MongoDB (Back4app Engineering)'
    url: 'https://www.back4app.com/multi-tenant-mongodb-row-level-security'
  - name: 'Backend security documentation'
    url: 'https://docs.parseplatform.org/parse-server/guide/#security'
cta:
  title: 'Aggiungi la sicurezza a livello di riga al tuo MongoDB'
  text: 'Back4app applica l''accesso riga per riga su un database documentale senza configurazione: ogni oggetto porta una ACL, i ruoli raggruppano gli utenti e la piattaforma controlla entrambi a ogni richiesta – ogni SDK, ogni API, anche la dashboard. Nessuna policy da scrivere a mano, nessuna clausola WHERE da dimenticare.'
  linkText: 'Inizia gratis'
  linkUrl: 'https://www.back4app.com/signup'
author: 'Back4app Engineering'
publishedDate: '2026-10-09'
translationKey: row-level-security
---

**La sicurezza a livello di riga è un meccanismo del database in cui delle policy filtrano, a ogni query, le righe che ciascuno può vedere o modificare.** Il modello mentale è quello di una *clausola WHERE invisibile e obbligatoria*: la condizione che altrimenti andrebbe ricordata in ogni query diventa una proprietà della tabella stessa – applicata dal motore, su ogni percorso di accesso, compresi quelli che il codice applicativo non vede mai.

## Punti chiave

| Domanda | Risposta |
| --- | --- |
| Che cos'è | Controllo degli accessi riga per riga, applicato dal motore del database stesso |
| Il modello mentale | Una clausola WHERE impossibile da dimenticare |
| Il caso d'uso principale | L'isolamento multi-tenant e i dati per utente, nel livello che una violazione non può saltare |
| Le clausole in piccolo | Ruoli di aggiramento, rifiuto predefinito, contesto di pooling – le insidie sono operative |
| Il guasto che previene | Un filtro dimenticato nel codice applicativo = violazione fra tenant |

## RLS in dieci righe di SQL

```sql
CREATE TABLE invoices (
  tenant_id uuid NOT NULL,
  total     numeric(10,2)
);

ALTER TABLE invoices ENABLE ROW LEVEL SECURITY;   -- da qui: rifiuto predefinito

CREATE POLICY tenant_isolation ON invoices
  USING      (tenant_id = current_setting('app.tenant')::uuid)   -- ciò che si può leggere
  WITH CHECK (tenant_id = current_setting('app.tenant')::uuid);  -- ciò che si può scrivere

-- Ogni query ora si comporta come se finisse con WHERE tenant_id = <il proprio>.
-- Una query che dimentica il filtro non restituisce nulla – non tutto.
```

La stessa garanzia esiste nei database documentali come *controllo degli accessi portato dalla riga stessa* – ogni oggetto porta la propria ACL, e la piattaforma la fa rispettare a ogni richiesta:

**JavaScript:**

```javascript
// JavaScript / Node.js — Back4app JS SDK
// Row-level security as data: this row is readable by its owner, period
const note = new Parse.Object('Note');
note.set('text', 'Q3 salary planning');
note.setACL(new Parse.ACL(Parse.User.current())); // owner-only, on the row itself
await note.save();

// Later, any query by any user — the row exists only for its owner
const notes = await new Parse.Query('Note').find(); // others never see it
```

**Flutter:**

```dart
// Flutter / Dart — Back4app Flutter SDK
// Row-level security as data: this row is readable by its owner, period
final user = await ParseUser.currentUser() as ParseUser;
final acl = ParseACL(owner: user); // owner-only, on the row itself

final note = ParseObject('Note')
  ..set('text', 'Q3 salary planning')
  ..setACL(acl);
await note.save(); // other users' queries never return this row
```

**Swift:**

```swift
// iOS / Swift — Back4app Swift SDK
// Row-level security as data: this row is readable by its owner, period
var note = Note()
note.text = "Q3 salary planning"
note.ACL = try ParseACL.defaultACL() // owner-only, on the row itself
note.save { result in
  if case .success = result {
    print("saved — other users' queries never return this row")
  }
}
```

**Kotlin:**

```kotlin
// Android / Kotlin — Back4app Android SDK
// Row-level security as data: this row is readable by its owner, period
val note = ParseObject("Note").apply {
  put("text", "Q3 salary planning")
  acl = ParseACL(ParseUser.getCurrentUser()) // owner-only, on the row itself
}
note.saveInBackground { e ->
  if (e == null) Log.d("Notes", "saved — invisible to every other user")
}
```

## Che cosa fa il motore con una query

```mermaid
flowchart LR
  accTitle: Come la sicurezza a livello di riga filtra una query
  accDescr: Due utenti diversi eseguono la stessa query sulla stessa tabella; il motore applica il predicato della policy di sicurezza riga per riga prima delle condizioni dell'utente, così ciascuno riceve solo le righe che la propria policy consente.
  Q["SELECT * FROM invoices<br/>(stessa query, qualunque utente)"] --> P["Predicato della policy<br/>applicato per riga, per primo"]
  P --> A["Il tenant A vede<br/>solo le righe del tenant A"]
  P --> B["Il tenant B vede<br/>solo le righe del tenant B"]
```

## USING vs. WITH CHECK, policy permissive vs. restrittive

| Concetto | Che cosa regola | Regola pratica |
| --- | --- | --- |
| `USING` | Ciò che esiste: le letture e le righe eleggibili per update/delete | "Lo posso vedere?" |
| `WITH CHECK` | Ciò che si può scrivere: gli insert e i valori dopo un update | "Lo posso creare così?" |
| Policy permissive (predefinito) | Combinate in OR – basta una corrispondenza per concedere | Concedere l'accesso |
| Policy restrittive | Aggiunte in AND – devono passare tutte | Imporre limiti obbligatori |

Due regole di composizione da ricordare dalla [documentazione di PostgreSQL](https://www.postgresql.org/docs/current/sql-createpolicy.html): omettere `WITH CHECK` riusa `USING` per le scritture, e almeno una policy permissiva deve passare prima che le restrittive vengano perfino consultate – solo policy restrittive significa che non entra nessuno.

## Dove RLS è supportata

| Famiglia di motori | Meccanismo |
| --- | --- |
| PostgreSQL (9.5+) e derivati | `CREATE POLICY` – l'implementazione di riferimento |
| SQL Server (2016+) | Policy di sicurezza su funzioni di predicato inline (filter + block) |
| SQL distribuito (CockroachDB, YugabyteDB) | Policy compatibili con PostgreSQL |
| Data warehouse cloud | Policy di accesso per riga, con la variante di ogni fornitore |
| Database documentali | Non basate su policy – ACL per oggetto applicate dal livello di piattaforma |

L'ultima riga è quella che interessa a questo glossario: sugli archivi documentali il confine a livello di riga è tipicamente un *dato portato dalla riga* (le ACL) invece di un predicato nel motore – stessa garanzia, meccanismo diverso, spiegato in dettaglio nell'[articolo di ingegneria di Back4app](https://www.back4app.com/multi-tenant-mongodb-row-level-security).

## Le insidie, finalmente in un unico posto

- **Le sorprese del rifiuto predefinito.** Abilitare RLS senza nessuna policy blocca tutti tranne il proprietario – metà delle storie "RLS ha rotto la produzione" è questa.
- **La matrice di aggiramento.** Superutenti, ruoli `BYPASSRLS` e *proprietari delle tabelle* ignorano le policy – conviene impostare `FORCE ROW LEVEL SECURITY` se il proprietario è anche l'utente dell'applicazione, e verificare chi detiene cosa.
- **Le viste si eseguono con i diritti del proprietario** per impostazione predefinita – una vista su una tabella con RLS può aggirarlo silenziosamente, a meno che non sia creata con i diritti del chiamante (`security_invoker` in PostgreSQL).
- **I vincoli tradiscono l'esistenza.** Una violazione di unicità o di chiave esterna può rivelare che esiste una riga invisibile – il canale nascosto documentato; l'unicità sui valori protetti va trattata di conseguenza.
- **Gli errori possono tradire i valori.** Espressioni costruite per fallire su dati precisi (una divisione per zero quando un valore nascosto corrisponde) esfiltrano attraverso i messaggi di errore – la classe di canali laterali descritta dalla documentazione di SQL Server.
- **Dump e pool hanno delle modalità.** Gli strumenti di backup possono richiedere la disattivazione della sicurezza per riga per esportare tutto; i pooler in modalità transazione richiedono un contesto con portata di transazione (`SET LOCAL`), altrimenti i tenant si mescolano da una richiesta all'altra.

## Prestazioni: le policy sono codice sull'hot path

Tre regole coprono quasi tutta l'esperienza di campo: **indicizzare ogni colonna a cui una policy fa riferimento** (il predicato viene eseguito prima dei filtri propri della query – senza indice è una scansione completa); **tenere i predicati senza join**, spostando le ricerche in funzioni o in controlli di ruolo; e **far valutare le funzioni per richiesta una volta per query, non una volta per riga**, avvolgendole in una sottoquery scalare. Misurata bene, RLS costa qualche punto percentuale; misurata male, è il rallentamento misterioso su ogni tabella messa in sicurezza.

## Casi d'uso tipici

- **SaaS multi-tenant.** Il caso canonico – l'isolamento dei tenant applicato sotto l'applicazione, dove un filtro dimenticato non può diventare una violazione.
- **Dati per utente.** Messaggi, documenti, cartelle cliniche: ciascuno vede le proprie righe, punto.
- **Confini fra reparti e fra regioni.** I commerciali vedono la propria regione; i revisori vedono tutto, in sola lettura – la stratificazione delle policy all'opera.
- **Regimi di conformità.** Controllo degli accessi dimostrabile al livello dei dati, che è dove piace ai revisori.
- **Accesso analitico condiviso.** Chi fa analisi interroga direttamente le repliche di produzione e vede solo ciò che il proprio ruolo consente – sicuro *perché* è il database a farlo rispettare, non la dashboard.

## Conviene applicare il controllo a livello di riga? Matrice decisionale

| Applicarlo con RLS/ACL quando… | Il filtraggio applicativo può bastare quando… |
| --- | --- |
| Più tenant o più utenti condividono le tabelle | Il database ha esattamente un chiamante fidato |
| Qualcosa oltre all'app tocca il database | Nessuno strumento di BI, nessun SQL amministrativo, nessun secondo servizio |
| Un filtro dimenticato significa violazione, non bug | Il partizionamento è una comodità, non sicurezza |
| La conformità vuole una prova al livello dei dati | I dati non sono sensibili |
| Conviene testare il confine una volta sola, in modo centralizzato | Non pesa verificare ogni query per sempre |

La sintesi onesta delle due colonne: tenere il partizionamento nell'applicazione per leggibilità – e farlo rispettare comunque nel database. La difesa in profondità è tutto il senso dell'operazione.

## Limiti e trade-off

- **Le policy sono invisibili per progetto** – il che rende il debug di "dove sono finite le mie righe?" una competenza vera e propria; conviene registrare per primo il contesto di sessione.
- **L'autorizzazione complessa esce dai predicati.** Le regole che hanno bisogno di stato di workflow o di logica fra entità appartengono ai livelli di autorizzazione applicativi, con RLS come rete di sicurezza.
- **La superficie operativa è reale.** La matrice di aggiramento, le modalità di dump e il contesto di pooling sono conoscenza operativa continua, non una configurazione una volta per tutte.
- **La valutazione riga per riga è una tassa** – modesta quando è progettata bene, illimitata quando non lo è.
- **Mette in sicurezza le righe, non le colonne.** Nascondere i campi è sicurezza a livello di colonna; combinando le due si ottiene l'effetto a livello di cella.

## La sicurezza a livello di riga su Back4app

Back4app è una piattaforma open-source di Backend as a Service (BaaS) che combina database gestito, API REST e GraphQL generate automaticamente, autenticazione, archiviazione di file e funzioni serverless con Cloud Code. Il suo modello a livello di riga è il meccanismo ACL-come-dato delle schede qui sopra: ogni oggetto porta la propria lista di accessi, i ruoli esprimono tenant e team, e [la piattaforma fa rispettare entrambi a ogni richiesta](https://docs.parseplatform.org/parse-server/guide/#security) – SDK, REST, GraphQL e dashboard compresi, con i permessi di classe come livello restrittivo al di sopra. È la garanzia della clausola WHERE obbligatoria, consegnata su un database documentale, con l'elenco di insidie qui sopra assorbito dalla piattaforma invece di essere affidato a chi sviluppa.
