---
title: "Supabase security definer view: därför kringgår den RLS"
description: "Varför en Supabase-vy returnerar rader som RLS döljer på tabellen, vad Advisor-varningen security_definer_view betyder och inställningen som fixar det."
url: "https://madsalt.tech/sv/notes/supabase-security-definer-view/"
author: "Denys Zaichenko"
author_url: "https://madsalt.tech/sv/about/"
language: "sv"
published: 2026-11-02
---

# Supabase security definer view: därför kringgår den RLS

Kort sagt

En Postgres-vy körs med sin ägares rättigheter om den inte skapas med `security_invoker = true`. I Supabase är ägaren oftast `postgres`, som kringgår RLS, så en vy över en skyddad tabell returnerar rader som tabellen själv döljer. På min lokala stack fick den publika nyckeln 0 rader från tabellen och alla 3 av 3 från en vanlig vy över den; med `security_invoker = true` returnerade vyn också 0. På Postgres 15 och senare: sätt det på varje vy i ett exponerat schema.

Min gratis [Supabase-säkerhetskontroll](https://madsalt.tech/sv/tools/supabase-security-check/) har en regel som heter "Vyer som kringgår RLS", och Supabases Security Advisor rapporterar samma sak som `security_definer_view`. Det är lätt att missa, eftersom tabellen den läcker från ser skyddad ut.

## Varför kringgår en Supabase-vy RLS?

En vy är en lagrad fråga. Som standard kontrollerar Postgres behörigheter och RLS på tabellerna i den som vyns ägare, inte som den som anropar den. Supabases [RLS-guide](https://supabase.com/docs/guides/database/postgres/row-level-security) säger det rakt ut: vyer kringgår RLS som standard eftersom de oftast skapas med användaren `postgres`, och en vy över en skyddad tabell delar ut varje rad som dess policyer var avsedda att hålla tillbaka.

Data API:et serverar vyer som tabeller. Om vyn ligger i ett exponerat schema och `anon` eller `authenticated` kan göra `select` på den, läser den publika nyckeln den.

## Vad returnerade vyn i mitt test?

På en lokal Supabase-stack (CLI 2.109.1, Postgres 17.6, PostgREST 14.14) skapade jag en tabell `orders` med tre falska kunder, slog på RLS utan policy och la en vy `order_summary` över den med `select`-behörighet för `anon`. Sedan anropade jag båda med publishable key:

![Samma tabell, tre sätt att läsa den. Lokal Supabase, RLS på utan policy, publishable key. Själva tabellen: Publishable key → orders, RLS på → 0 rader; En vanlig vy över den: Publishable key → order_summary-vyn → 3 av 3 rader; Vyn med security_invoker: Publishable key → security_invoker-vy → 0 rader.](https://madsalt.tech/charts/sv/supabase-security-definer-view.svg)

*Min reproduktion på en lokal Supabase-stack, 23 oktober 2026.*

| Förfrågan med publishable key                                | Resultat                          |
| ------------------------------------------------------------ | --------------------------------- |
| `GET /rest/v1/orders` (RLS på, ingen policy)                 | `[]`                              |
| `GET /rest/v1/order_summary` (vanlig vy)                     | alla 3 rader, med namn och e-post |
| `GET /rest/v1/order_summary` efter `security_invoker = true` | `[]`                              |

Samma tabell, samma nyckel. Bara vyns inställning ändrade vad som kom tillbaka.

## Hur fixar du det?

På Postgres 15 och senare, som alla nuvarande Supabase-projekt kör, låter du vyn kontrollera RLS som den som anropar:

```sql
alter view public.order_summary set (security_invoker = true);
```

För en ny vy lägger du det i definitionen:

```sql
create view public.order_summary
with (security_invoker = true)
as select customer, email, total from public.orders;
```

Den som anropar behöver då också `select` på den underliggande tabellen, och tabellens policyer avgör raderna. Om en vy måste aggregera data som den som anropar inte kan se rad för rad, till exempel ett publikt antal, håll den utanför det exponerade schemat och servera den i stället via en funktion med ett snävt resultat.

Så listar du vyerna i `public` som fortfarande körs som sin ägare:

```sql
select c.relname as view
from pg_class c join pg_namespace n on n.oid = c.relnamespace
where n.nspname = 'public' and c.relkind = 'v'
  and not coalesce(
    (select bool_or(option = 'security_invoker=true' or option = 'security_invoker=on')
     from unnest(c.reloptions) as option), false);
```

På min stack, med en vanlig vy och två med `security_invoker = true`, returnerade den bara den vanliga.

Materialiserade vyer stöder inte RLS alls, så kontrollen flaggar dem i API:t separat, under "Materialiserade vyer eller främmande tabeller i API:t". Vad mer som går förbi policyerna, från secret key till `SECURITY DEFINER`-funktioner, finns i min [säkerhetschecklista för Lovable-appar](https://madsalt.tech/sv/blog/lovable-app-security-checklist/), och hur du bevisar själva policyerna finns i [hur du testar Supabase RLS](https://madsalt.tech/sv/blog/how-to-test-supabase-rls/). En policy som slår upp team via en hjälpfunktion, utan rekursion, finns i [Supabase RLS policy-exempel, testade via API:t](https://madsalt.tech/sv/blog/supabase-rls-policy-examples/). En security definer-funktion behöver ytterligare en inställning, en fast `search_path`; varför `search_path = public` inte räckte i mitt test finns i [Supabase Function Search Path Mutable: vad det betyder](https://madsalt.tech/sv/notes/supabase-function-search-path-mutable/).
