---
title: "Supabase RLS: kāpēc divu org. lietotājs redz svešus datus"
description: "Politika, kas pārbauda dalību org., ir patiesa abās org. lietotājam, kurš pieder divām. Ko atrada mana zonde, kā to labot un divu minūšu pārbaude."
url: "https://madsalt.tech/lv/notes/supabase-rls-user-in-two-organizations/"
author: "Denys Zaichenko"
language: "lv"
published: 2026-10-18
---

# Supabase RLS: kāpēc divu org. lietotājs redz svešus datus

Īsumā

Politika kā `auth_in_org(organization_id)` jautā: "vai izsaucējs ir tās organizācijas (org.) dalībnieks, kurai pieder šī rinda?". Lietotājam, kas pieder org. A un org. B, atbilde abās ir "jā". Manā zondē ar RLS vien šādam lietotājam bija lasīšanas un rakstīšanas piekļuve otras org. dokumentam. Kad vaicājumam pievienoja pieprasījuma org., atgriezās 0 rindu.

To atradu, nostiprinot [būvniecības dokumentu platformu](https://madsalt.tech/lv/work/construction-document-platform/), vairāku nomnieku Supabase lietotni. Visām nomnieku tabulām row level security bija ieslēgts un piespiests, tāpēc likās, ka viss gatavs.

## Kas šķita drošs?

Visām politikām bija viena forma: rindas `organization_id` jābūt org., kuras dalībnieks ir izsaucējs. Tāpēc dažas servera darbības meklēja dokumentu tikai pēc id. Pamatojums bija "RLS to tāpat nofiltrēs".

```ts
const { data } = await supabase
  .from('documents')
  .select('*')
  .eq('document_id', id)
  .single()
```

Lietotājam ar vienu dalību tas strādā, un tests ar tādu lietotāju iziet cauri.

## Kāpēc RLS ielaiž otru org.?

Politika ir dalības tests. Postgres to novērtē katrai rindai, kā apraksta [row security dokumentācija](https://www.postgresql.org/docs/current/ddl-rowsecurity.html), un tā nezina, kuras organizācijas vārdā pieprasījums darbojas, jo tas dzīvo lietotnē: URL, sīkdatnē vai org. pārslēdzējā. Lietotājam, kas ir abu org. dalībnieks, iziet cauri visas abu org. rindas.

![Politikā nav norādes, kurai org. pieder pieprasījums. Viens lietotājs, org. A un org. B dalībnieks, strādā org. A. Tikai RLS politika: Pieprasījums org. A → Rindas org. biedrs? → Jā, A vai B → Org. B rinda; RLS plus šī pieprasījuma org.: Pieprasījums org. A → Rindas org. biedrs? → Rinda org. A? → 0 rindu no org. B.](https://madsalt.tech/charts/lv/supabase-rls-user-in-two-organizations.svg)

*Mana zonde ar iesētu lietotāju divās org., 2026. gada septembris: ar RLS vien bija lasīšana un rakstīšana org. B dokumentam; pievienojot pieprasījuma org., atgriezās 0 rindu.*

Tātad lietotnes `organization_id` filtrs nav otrs slānis virs RLS. Šim lietotājam tā ir vienīgā kontrole.

Kamēr esat pie šīm palīgfunkcijām, pārbaudiet, vai tās skatās uz `organizations.is_active`. Dalības palīgfunkcijas bieži neskatās, un tad deaktivizēta org. RLS līmenī saglabā lasīšanas un rakstīšanas piekļuvi. Ja vienīgā `is_active` pārbaude atrodas lietotnes nomnieka noteicējā, jebkurš vaicājums, kas to apiet, apiet arī deaktivizēšanu.

## Kas to izlaboja?

Pieprasījuma org. kļuva par obligātu argumentu katrā servisa funkcijā, kas lasa vai raksta nomnieka datus. Izsaukuma vietā to aizmirst nevar, jo bez tā funkcija nekompilējas.

```ts
export async function getDocument(orgId: string, id: string) {
  return supabase
    .from('documents')
    .select('*')
    .eq('organization_id', orgId)
    .eq('document_id', id)
    .single()
}
```

No pārskata nāca vēl divi noteikumi:

- Nekad neņemiet org. no rindas, ko tūlīt rakstīsit. `update ... where id = $1 and organization_id = <that row's own organization_id>` vienmēr ir patiess, tāpēc tas neko nesargā.
- Saliktā ārējā atslēga uz `(id, organization_id)` liek datubāzei atteikt saiti starp dažādu org. rindām. Pārbaudiet katru pakārtoto tabulu: to ir viegli pievienot trim un aizmirst ceturto.

## Kā pārbaudīt savu lietotni?

Izveidojiet vienu lietotāju ar aktīvu dalību divās org. Pēc tam lokālas vai staging kopijas SQL redaktorā darbojieties kā šis lietotājs un pieprasiet otras org. rindu:

```sql
begin;
set local role authenticated;
set local request.jwt.claims = '{"sub": "<user id>", "role": "authenticated"}';

-- RLS alone: returns the org B document
select document_id from documents where document_id = '<org B document id>';

-- with the org of the request: 0 rows
select document_id from documents
where document_id = '<org B document id>'
  and organization_id = '<org A id>';
rollback;
```

Atkārtojiet ar `update` un vēlreiz pēc otras org. deaktivizēšanas. Ja pirmais vaicājums atgriež rindu, pārbaudiet katru vietu, kur nomnieka dati tiek vaicāti tikai pēc id.

## Cik tas ir nopietni?

Novērtējiet godīgi. Uzbrucējam vajadzīga īsta dalība abās org., tāpēc tas ir par integritāti un audita pēdām: kāds ar piekļuvi diviem klientiem izmaina nepareizo klientu, un žurnāls saka, ka tas bija atļauts. Tas nav veids, kā svešinieks varētu izlasīt visus nomniekus.

Vispārīgā mācība ir tā pati, kas rakstā [kā es testēju Supabase RLS](https://madsalt.tech/lv/blog/how-to-test-supabase-rls/): testējiet to, ko var īsts lietotājs, ar īstām datu formām, nevis tikai to, ko saka katra politika. Trīs saistītas piezīmes: [loma, kas ņemta no reģistrācijas metadatiem](https://madsalt.tech/lv/notes/supabase-raw-user-meta-data-role/), [NULL, kas izlaida atļaujas pārbaudi](https://madsalt.tech/lv/notes/plpgsql-if-not-null-fails-open/) un [kuras shēmas sniedz Data API](https://madsalt.tech/lv/notes/supabase-exposed-schemas/). Divu uzņēmumu tests ir mana [Lovable lietotnes drošības kontrolsaraksta](https://madsalt.tech/lv/blog/lovable-app-security-checklist/) pirmais punkts. Politikām, tiesībām un iestatījumiem ap to bezmaksas [Supabase drošības pārbaude](https://madsalt.tech/lv/tools/supabase-security-check/) palaiž 46 OWASP Top 10:2025 noteikumus; vai politika ielaiž divu org. lietotāju, ir datu formas jautājums, uz ko atbild tikai iepriekšējais vaicājums.
