Vai al contenuto

Supabase e RLS policy: cosa dimentica l'AI e come controllarlo

Nelle app fatte con l'AI su Supabase la sicurezza dei dati dipende dalle RLS policy e da come gestisci i ruoli: gli errori più comuni e come controllarli.

Autore

G. Tempesta

Pubblicato

Lettura

5 min

Aggiornato

Scritto con l'aiuto dell'AI, rivisto da Giovanni Tempesta

Supabase e RLS policy: cosa dimentica l'AI e come controllarlo

Quasi tutte le app che leggo, nate con Lovable, Bolt o Cursor, usano Supabase come database. È una buona scelta, con una conseguenza che molti non conoscono: la sicurezza dei tuoi dati dipende quasi tutta dalle RLS policy del database. E sono proprio la parte che l'AI dimentica, o scrive troppo larga.

Perché in un'app Supabase la sicurezza dipende dalle RLS policy

In un'app Supabase il browser parla direttamente con il database, attraverso le API generate da Supabase e la chiave pubblica (anon, o la nuova chiave publishable). È pubblica per davvero: chiunque apra il sito la può vedere. Va bene così, perché a decidere cosa si può leggere e scrivere non è la chiave, ma la Row Level Security (RLS) di Postgres.

Come funziona, in breve:

  • ogni richiesta arriva al database con un ruolo Postgres: anon se l'utente non ha fatto l'accesso, authenticated se l'ha fatto. Il ruolo service_role invece salta la RLS;
  • su ogni tabella si attiva la RLS e si scrivono le policy: una condizione per ogni comando (SELECT, INSERT, UPDATE, DELETE) e per ogni ruolo;
  • la clausola USING decide quali righe si possono leggere, modificare o cancellare; la clausola WITH CHECK decide quali righe si possono scrivere;
  • dentro la policy si usa auth.uid(), l'utente che ha fatto l'accesso, per esempio user_id = auth.uid().

Se la RLS è disattivata, la tabella non ha protezione; se le policy sono sbagliate, la protezione è sbagliata. Con la RLS attiva e nessuna policy, invece, non passa niente.

Gli errori nelle RLS policy che trovo più spesso

1. Tabelle con la RLS disattivata

L'AI crea una tabella nuova per una funzione nuova e si dimentica di attivare la RLS. Quella tabella è aperta a chiunque abbia la chiave pubblica.

2. Policy «vero per tutti»

Le policy ci sono, ma dicono USING (true): tutti quelli a cui si applica la policy leggono tutto; se vale per anon, anche chi non ha fatto l'accesso. Di solito è un rimedio messo quando qualcosa non funzionava, e poi rimasto lì.

3. Policy per leggere, non per modificare

L'utente vede solo i suoi dati, bene. Ma può modificare quelli degli altri, perché le policy di UPDATE e DELETE mancano o sono diverse. Oppure la WITH CHECK è più larga della USING, per esempio WITH CHECK (true): l'utente modifica una sua riga e la intesta a qualcun altro. Lo stesso vale per INSERT: con WITH CHECK (true) si possono creare righe a nome di altri.

4. Ruoli nel posto sbagliato: l'RBAC fatto male

Quasi ogni app ha dei ruoli (admin, operatore, utente) e dei piani (gratis, Pro): è un controllo degli accessi basato sui ruoli, l'RBAC. L'errore tipico è tenere il ruolo o il piano in una colonna del profilo che l'utente può modificare: con una chiamata diretta si promuove da solo.

Un RBAC fatto bene su Supabase:

  • i ruoli stanno in una tabella separata (per esempio user_roles) che l'utente può leggere ma non scrivere;
  • in alternativa, il ruolo viaggia nel token di accesso come custom claim, aggiunto da Supabase Auth con un Custom Access Token Hook (un ruolo tolto resta valido finché il token non si rinnova);
  • mai il ruolo nei user_metadata del profilo: si leggono anch'essi con auth.jwt(), ma l'utente li può cambiare da solo. Se proprio serve, va negli app_metadata, che scrive solo il server;
  • le policy leggono il ruolo da lì, con auth.jwt() o con una funzione di controllo, e non si fidano di quello che manda il browser;
  • il piano a pagamento lo scrive solo il server, quando arriva la conferma del pagamento.

5. Viste e funzioni che scavalcano la RLS

In Postgres una vista gira con i permessi di chi l'ha creata, e quindi ignora le policy della tabella, a meno che non sia creata con security_invoker = true. Lo stesso vale per le funzioni SECURITY DEFINER: utili dentro le policy, pericolose se chiunque può chiamarle dall'API. Supabase segnala nel Security Advisor le viste che scavalcano la RLS; per le funzioni, controlla chi può eseguirle.

6. I file

Anche i contenitori di file (Storage) hanno le loro policy. Un contenitore pubblico con documenti privati è una delle falle più comuni.

7. La chiave di servizio nel posto sbagliato

La chiave service_role (o una delle nuove chiavi secret) salta tutte le policy. Può stare solo in codice che gira sul server. Se la trovi nel frontend o nel repository, è la prima cosa da sistemare.

Come controllare, senza essere uno sviluppatore esperto

  1. Apri il Security Advisor di Supabase e leggi gli avvisi. Sono in inglese, ma sono chiari.
  2. Controlla l'elenco delle tabelle: ognuna deve avere la RLS attiva e almeno una policy per ogni operazione che serve.
  3. Fai la prova dei due utenti: crea due account, A e B. Entra come B e prova a vedere o modificare qualcosa di A (un ordine, un documento, un profilo). Se ci riesci, hai trovato un problema.
  4. Prova a cambiarti il ruolo: con un utente normale, prova a modificare la colonna del ruolo o del piano. Se ci riesci, l'RBAC va rifatto.
  5. Guarda i contenitori di file: quali sono pubblici, e cosa c'è dentro.

Cosa queste verifiche non trovano

Queste verifiche trovano i problemi più grossi, non tutti. Le policy di un'app vera possono essere molte e intrecciate, e l'errore spesso sta nel dettaglio: una condizione mancante, un ruolo dimenticato, un caso che nessuno ha provato. Prima di aprire l'app a utenti veri, o prima di aggiungere pagamenti e dati personali, conviene farle rileggere da qualcuno che non le ha scritte.

Con il Check-up Codice AI controllo le RLS policy e i ruoli della tua app Supabase, insieme a tutto il resto, e ti dico cosa sistemare prima. Il prezzo è fisso. Prima di vedere il codice, firmiamo insieme un accordo di riservatezza, e leggo il codice senza modificarlo. La pagina del Check-up Codice AI

  • Vibe Coding
  • Lovable
  • Supabase
  • Sicurezza