Vai al contenuto

Supabase exposed schemas: cosa apre l'elenco

Supabase

Visualizza come MarkdownApri in ClaudeApri in ChatGPTApri in Perplexity

Anche la domanda viene copiata. Se la chat si apre vuota, la incolli.

In breve

L’elenco Exposed schemas di Supabase decide quali schemi la Data API serve a chiunque abbia la sua chiave pubblica. Di default sono public e graphql_public. Ogni tabella, vista e funzione di uno schema dell’elenco deve avere i propri grant e la propria RLS, quindi ogni schema extra è altra superficie da difendere. Tenga l’elenco corto e lo controlli per primo.

Ho costruito un checker di sicurezza per Supabase gratuito, e l’elenco Exposed schemas è una delle prime cose che legge. Quando qualcuno mi chiede quanto sia sicuro un progetto Supabase, parto da questa impostazione.

Cosa significa “esposto” in Supabase?

Supabase serve il suo database via REST con PostgREST. PostgREST risponde solo per gli schemi della sua lista db_schema, che si modifica nella Dashboard in Project Settings → Data API → Exposed schemas. Nella configurazione del progetto che ho guardato il valore era public,graphql_public, e la guida agli schemi personalizzati di Supabase dice che public è esposto di default. Una richiesta a uno schema fuori dall’elenco viene rifiutata, e PostgREST non permette mai pg_catalog né information_schema al suo interno.

Perché l’elenco conta per la sicurezza di Supabase?

Tutto ciò che sta in uno schema esposto è raggiungibile con la chiave pubblica: tabelle, viste e funzioni. La guida alla RLS di Supabase è chiara: una tabella in uno schema esposto senza RLS può essere letta e scritta da qualsiasi ruolo con un grant su di essa. Uno schema che non è nell’elenco non è raggiungibile affatto tramite l’API.

Quindi uno schema extra non è una modifica neutra. Aggiunga storage o vault all’elenco e avrà messo tabelle interne alla portata della Data API. Aggiunga un suo schema e ogni tabella al suo interno richiede la stessa cura di public.

Cosa apre uno schema esposto in più. Una richiesta anon, prima e dopo aver ridotto l'elenco. Prima: uno schema extra è esposto: richiesta anon → Data API → schema extra → tabella no-RLS leggibile; Dopo: solo public e graphql_public: richiesta anon → Data API → solo schemi di default → RLS su ogni tabella.
Dalle regole del checker di sicurezza Supabase e dalla documentazione della Data API di Supabase, 22 ottobre 2026.

Come lo valuta il checker?

Il controllo si chiama extra_exposed_schemas. Tutto ciò che non è public o graphql_public conta come extra, poi:

  • Uno schema interno di Supabase nell’elenco (auth, storage, realtime, vault, extensions e simili) è un fallimento, gravità alta.
  • Solo schemi personalizzati, per esempio api, danno un avviso, gravità media.
  • Nessun extra, il controllo passa.

Lo stesso elenco guida altri controlli. Tabelle con RLS disattivata, grant di scrittura ad anon, policy sempre vere, viste senza security_invoker e funzioni SECURITY DEFINER che anon può chiamare vengono segnalate solo per gli schemi esposti, perché è lì che la chiave pubblica le raggiunge.

Come si usa uno schema personalizzato in sicurezza?

Uno schema personalizzato è un pattern legittimo: la guida Securing your API di Supabase descrive uno schema dedicato, come api, come modo per rendere la superficie esposta più facile da individuare e da verificare, con le tabelle interne in schemi non esposti. Bastano due passaggi, e la guida agli schemi personalizzati li indica entrambi: aggiungere lo schema a Exposed schemas, poi concedere usage su di esso ad anon, authenticated e service_role, più i privilegi sui suoi oggetti.

L’esempio della guida concede ALL su ogni tabella. Io non copierei quella riga così com’è. La guida Securing your API dice di dare a ogni ruolo il minimo che gli serve e di attivare la RLS su ogni tabella che si espone. I grant decidono se un ruolo può toccare una tabella, le policy decidono quali righe.

Una modifica a parte: Supabase smette di concedere automaticamente alla Data API le nuove tabelle di public. È diventato il comportamento predefinito per i nuovi progetti dal 30 maggio 2026 e verrà applicato ai progetti esistenti il 30 ottobre 2026, mentre le tabelle esistenti mantengono i loro grant. Questo è il livello dei grant. Non cambia quali schemi sono nell’elenco.

Come si controlla il proprio progetto?

Apra Project Settings → Data API e legga Exposed schemas. Se c’è più di public e graphql_public, si chieda a cosa serva ogni schema extra.

Poi elenchi le tabelle di quegli schemi che hanno la RLS disattivata e se anon può già leggerle:

select n.nspname as schema,
       c.relname as "table",
       has_table_privilege('anon', c.oid, 'select') as anon_can_select
from pg_class c
join pg_namespace n on n.oid = c.relnamespace
where n.nspname in ('public', 'api')  -- your Exposed schemas
  and c.relkind in ('r', 'p')
  and not c.relrowsecurity
order by 1, 2;

L’ho eseguita su un Postgres 17 usa e getta, con uno schema api che conteneva una tabella con RLS e una senza, più una tabella public senza RLS. Ha restituito solo le due senza:

 schema | table  | anon_can_select
--------+--------+-----------------
 api    | orders | t
 public | logs   | t

Ogni riga con anon_can_select vero è una tabella che chiunque abbia la sua chiave pubblica può leggere, finché non attiva la RLS o revoca il grant. La query copre solo le tabelle. Viste e funzioni vanno guardate a parte, ed è ciò che percorre la mia checklist di sicurezza per le app Lovable, mentre come testo la Supabase RLS mostra come dimostrare che le policy funzionano.

© 2026 Denys Zaichenko. Articolo originale: https://madsalt.tech/it/notes/supabase-exposed-schemas/