---
title: "Supabase exposed schemas: cosa apre l'elenco"
description: "Cosa significa Exposed schemas in Supabase, come il mio checker valuta gli schemi extra e una query SQL che trova al loro interno le tabelle senza RLS."
url: "https://madsalt.tech/it/notes/supabase-exposed-schemas/"
author: "Denys Zaichenko"
language: "it"
published: 2026-10-22
---

# Supabase exposed schemas: cosa apre l'elenco

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](https://madsalt.tech/it/tools/supabase-security-check/) 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](https://supabase.com/docs/guides/api/using-custom-schemas) di Supabase dice che `public` è esposto di default. Una richiesta a uno schema fuori dall'elenco viene rifiutata, e [PostgREST](https://docs.postgrest.org/en/stable/references/api/schemas.html) 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](https://supabase.com/docs/guides/database/postgres/row-level-security) 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.](https://madsalt.tech/charts/it/supabase-exposed-schemas.svg)

*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](https://supabase.com/docs/guides/api/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](https://supabase.com/docs/guides/api/using-custom-schemas) 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`](https://supabase.com/changelog/45329-breaking-change-tables-not-exposed-to-data-and-graphql-api-automatically). È 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:

```sql
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:

```text
 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](https://madsalt.tech/it/blog/lovable-app-security-checklist/), mentre [come testo la Supabase RLS](https://madsalt.tech/it/blog/how-to-test-supabase-rls/) mostra come dimostrare che le policy funzionano.
