Jak dane wielu banków, partnerów i urzędów są odseparowane na jednej instancji ipIII. Warstwa aplikacyjna
(scopeClause/canAccess, org-scoping) jest zaimplementowana i dowiedziona
na realnym PostgreSQL — cross-org odczyt zwraca 404, nie dane cudzej organizacji. Warstwa bazodanowa
(PostgreSQL Row-Level Security) i pełna czterowarstwowa hierarchia najmu to nadal ROADMAP P1.
Na produkcji publicznej działa dziś świadomy tryb single-tenant-demo (jedna organizacja demo).
Zgodnie z doktryną claim ≤ proof.
routes/ip3-tenancy.js: scopeClause/canAccess) jest
zaimplementowana, jest secure-by-default (scoping aktywny, jeśli nie ustawiono jawnie trybu demo) i jest
pokryta testami przechodzącymi na żywym Express + PostgreSQL. To, co nadal jest specyfikacją projektową
(szkielet), to: PostgreSQL Row-Level Security w samej bazie (warstwa 2, obrona nawet gdy aplikacja pominie filtr)
oraz pełna czterowarstwowa hierarchia tenant/org/project/engagement poniżej poziomu org. Każdy taki element jest
oznaczony ROADMAP.
Izolacja danych między klientami to warunek wejścia dla banku SIFI, partnera SaaS i urzędu.
ipIII ma dziś działającą warstwę evidence (import → incydent → evidence-package → retest → close,
z JWT/RBAC/audit na żywej PostgreSQL) oraz warstwę app-level scopingu po org_id: scope
pochodzi z tokenu sesji (nie z parametru żądania), a domyślne zachowanie (secure-by-default) to izolacja
włączona — tryb bez filtrowania wymaga jawnej bramki demo. To, czego jeszcze nie ma, to druga warstwa obrony
w samej bazie (PostgreSQL RLS) i pełna hierarchia najmu poniżej org (project, engagement jako osobne granice
scope'u).
Poniższy przebieg wykonano na realnym środowisku PostgreSQL (staging), nie na atrapie w pamięci — to uzupełnienie testów jednostkowych z sekcją poniżej, na rzeczywistej bazie danych.
2 organizacje + po jednym użytkowniku w każdej. Scoping aktywny: flag:on, scoping_active:true.
Użytkownik org A tworzy incydent. Org A widzi go (1 incydent) — org B widzi 0.
Org B próbuje pobrać incydent org A po identyfikatorze: odpowiedź 404, nie 403 — brak wycieku informacji o istnieniu cudzego zasobu.
Testy jednostkowe/integracyjne pokrywające tę ścieżkę: tests/ip3-tenant-idor.test.js (12 PASS / 0 FAIL)
i tests/ip3-tenancy.test.js (14 PASS / 0 FAIL).
single-tenant-demo — świadomie, jako jedna organizacja demo.
Czterowarstwowa struktura scopingu. Poziom 2 — Org jest dziś zaimplementowany na app-level i dowiedziony (patrz sekcja wyżej); poziom 1 (grupowanie wielu org w jeden tenant nadrzędny, klucz dla RLS) oraz poziomy 3-4 (project/engagement jako osobne granice scope'u) to nadal spec docelowa (ROADMAP).
| Poziom | Encja | Rola w izolacji | Przykład | Status |
|---|---|---|---|---|
| 1 — Tenant | tenant |
Najwyższa granica izolacji, nadrzędna wobec wielu org (np. grupa kapitałowa). Klucz scopingu docelowo używany przez RLS. | Bank A · Partner B · Urząd C | ROADMAP P1 — dziś istnieje tylko poziom org |
| 2 — Org | org |
Granica izolacji app-level, dziś realnie egzekwowana: scope z tokenu sesji (org_id), fail-closed bez org, cross-org GET = 404. |
Bank A / Pion Cyber · Bank A / Compliance | MVP — zaimplementowane i dowiedzione |
| 3 — Project | project |
Kontener pracy w ramach org (system, aplikacja, obszar audytu). Grupuje engagementy i evidence. | Bankowość internetowa · Aplikacja mobilna | ROADMAP P1 |
| 4 — Engagement | engagement |
Pojedyncze zaangażowanie (pilot, PoC, cykl retestu) w granicach RoE. Najniższy scope, do którego wiążą się findings, incydenty i evidence-package. | PoC purple-team Q3 · Retest po remediacji | ROADMAP P1 |
org_id — scope
pochodzi z tokenu sesji, nie z parametru żądania sterowanego przez klienta, co eliminuje klasę podatności,
w której użytkownik podstawia cudzy identyfikator, żeby sięgnąć po nieswoje dane (IDOR/BOLA). Docelowo
(ROADMAP) ten sam mechanizm ma zejść niżej, do project_id /
engagement_id, i wznieść się wyżej, do nadrzędnego tenant_id grupującego wiele org.
Na produkcji publicznej scoping jest dziś świadomie wyłączony trybem single-tenant-demo (jedna
organizacja demo) — nie dlatego, że kod go nie ma, tylko dlatego, że na jednej organizacji demo nie ma co
izolować.
RLS to warstwa obrony w samej bazie: nawet gdy warstwa aplikacyjna pominie filtr, baza nie zwróci wierszy spoza aktywnego tenanta. Poniższy szkielet jest ilustracją docelowej polityki (ROADMAP), nie fragmentem wdrożonego kodu.
-- SPEC / ROADMAP (nie wdrożone) — szkic polityki RLS per tenant
ALTER TABLE evidence ENABLE ROW LEVEL SECURITY;
ALTER TABLE incidents ENABLE ROW LEVEL SECURITY;
ALTER TABLE findings ENABLE ROW LEVEL SECURITY;
-- scope pochodzi z sesji (SET app.tenant_id = ... przy uwierzytelnieniu),
-- nie z parametru sterowanego przez klienta
CREATE POLICY tenant_isolation ON evidence
USING (tenant_id = current_setting('app.tenant_id')::uuid);
CREATE POLICY tenant_isolation ON incidents
USING (tenant_id = current_setting('app.tenant_id')::uuid);
-- FORCE RLS = polityka obowiązuje także właściciela tabeli
ALTER TABLE evidence FORCE ROW LEVEL SECURITY;
ALTER TABLE incidents FORCE ROW LEVEL SECURITY;
tenant_id do istniejących tabel,
backfillu danych, przepięcia ścieżki uwierzytelnienia na ustawianie app.tenant_id oraz zestawu
testów regresji. To migracja schematu produkcyjnej bazy — nie zmiana kosmetyczna. Uruchamiana wyłącznie
po ACK operatora i na planie z rollbackiem.
Sama polityka nie wystarczy — trzeba udowodnić, że działa, także w scenariuszach nadużycia. Na poziomie org (app-level) zestaw testów pozytywnych i negatywnych istnieje i przechodzi. Na poziomie DB (RLS) i pełnej hierarchii (project/engagement) zestaw jest dalej specyfikacją (ROADMAP).
Org A odczytuje wyłącznie własne evidence/incydenty. Scope z sesji zwraca komplet swoich rekordów, żaden nie ginie.
MVP — dowiedzione (real PG + 26 testów)
Org B podstawia identyfikator rekordu należącego do Org A (bezpośrednie odwołanie do obiektu). Wynik: 404, zero wierszy — bez ujawniania, że zasób istnieje.
MVP — dowiedzione
Autoryzowany użytkownik Org B próbuje operacji na obiekcie poza swoim scope (broken object-level authorization). Wynik: odmowa na poziomie canAccess, nie tylko UI.
MVP — dowiedzione
Użytkownik org próbuje sięgnąć do project/engagementu spoza swojego poddrzewa; drugorzędna obrona w bazie (RLS), gdyby aplikacja pominęła filtr. Oba elementy poza dzisiejszym zakresem app-level.
ROADMAP
Dziś audit-log nie jest jeszcze scope'owany per org (produkcja publiczna = single-tenant-demo, jedna organizacja). Docelowo (ROADMAP) każdy wpis audytu jest kotwiczony do tenant_id, a dostęp do logów jest scope'owany tak samo jak dane — administrator Tenanta A nie widzi zdarzeń Tenanta B.
Każde zdarzenie (kto, co, kiedy, na jakim rekordzie) nosi tenant_id. Log jest niereużywalny między tenantami.
ROADMAP
Widok audytu respektuje tę samą politykę RLS co dane. Brak globalnego „superwidoku" bez wyraźnej roli platformy i śladu.
ROADMAP
Wpisy audytu tylko dopisywane, z chain-of-custody. Zachowanie integralności śladu (dziś: hash + chain w DB, MVP).
MVP / ROADMAP (per-tenant)
Cykl życia danych klienta zgodny z umową powierzenia (DPA) i zasadami RODO (minimalizacja, ograniczenie przechowywania, prawo do usunięcia/przenoszenia). Spec docelowa; realizacja per tenant = ROADMAP.
| Faza | Co obejmuje | Odniesienie | Status |
|---|---|---|---|
| Retencja | Okres przechowywania danych engagementu ustalany per tenant w DPA; po jego upływie dane kwalifikują się do usunięcia. Zasada ograniczenia przechowywania. | RODO art. 5(1)(e); zapisy DPA | ROADMAP P1 |
| Purge | Trwałe usunięcie danych tenanta na żądanie lub po terminie retencji, wraz z evidence i kopiami roboczymi; potwierdzenie usunięcia w audycie (scoped do tenanta). | RODO art. 17 (prawo do usunięcia) | ROADMAP P1 |
| Eksport | Przenoszalny pakiet danych tenanta (evidence-package, incydenty, audit) w formacie strukturalnym; do migracji, offboardingu lub realizacji prawa do przenoszenia. | RODO art. 20 (przenoszalność) | ROADMAP P1 |
single-tenant-demo (jedna organizacja demo) — świadomie, nie
z powodu braku kodu. Dowody: roadmapie dev.
Powiązane: rejestr granic dojrzałości → /known-limitations · przetwarzanie danych → /data-processing · gotowość enterprise → /enterprise-readiness.