Podczas testów penetracyjnych platformy B2B SaaS (model multi-tenant) wykryliśmy podatność typu IDOR/BOLA w GraphQL, która pozwalała użytkownikowi z firmy A pobrać wybrane dane firmy B przez podmianę identyfikatora w zapytaniu. Backend poprawnie uwierzytelniał użytkownika, ale w części resolverów brakowało twardej kontroli „czy ten obiekt należy do tego tenant’a”. Naprawa objęła centralne egzekwowanie tenant scoping, walidację na poziomie resolverów oraz testy regresji, które wyłapują podobne błędy zanim trafią na produkcję.
Kontekst: SaaS, wielu klientów i jeden wspólny backend
Klient to firma oferująca platformę SaaS dla działów operacyjnych i finansowych (typowe B2B: wiele organizacji, role, uprawnienia, integracje, exporty). Produkt działał w modelu multi-tenant, czyli jedna aplikacja obsługiwała wielu klientów, a izolacja danych była krytyczna jak tlen.
Nowy moduł raportowy został oparty o GraphQL, bo to wygodne: frontend może pobrać dokładnie to, czego potrzebuje, bez pięciu osobnych endpointów. W praktyce GraphQL często przyspiesza rozwój, ale też lubi „uczyć pokory” w autoryzacji, bo jedna mutacja lub query potrafi sięgnąć w głąb systemu.
Testy miały odpowiedzieć na jedno pytanie, które zawsze brzmi niewinnie: czy użytkownik widzi tylko swoje dane… zawsze?
Problem: uwierzytelnienie było OK, izolacja tenantów już nie wszędzie
W systemie były role, sesje, tokeny, wszystko wyglądało dojrzale. Problem nie polegał na tym, że ktoś „wchodził bez logowania”.
Problem polegał na tym, że część zapytań GraphQL przyjmowała identyfikator obiektu (np. orgId, reportId, invoiceId) i zwracała dane, jeśli obiekt istniał, ale nie zawsze sprawdzała, czy obiekt należy do organizacji użytkownika.
To jest klasyk z kategorii IDOR/BOLA, tylko w wersji „bardziej eleganckiej”, bo opakowanej w GraphQL.
Jak pracowaliśmy: testy multi-tenant bez magii, za to metodycznie
Zaczęliśmy od mapowania schemy GraphQL (query, mutation, typy, powiązania) i identyfikacji miejsc, gdzie pojawia się parametr wskazujący obiekt lub tenant. Potem sprawdzaliśmy scenariusze przekrojowe: ten sam użytkownik, różne role, różne organizacje, różne ścieżki UI.
Kluczowy etap to testy „tenant switching”, czyli celowe próby pobrania obiektu spoza własnej organizacji. To nie są testy na chybił-trafił. To jest kontrolowany eksperyment: bierzemy obiekt należący do tenant B (z kont testowych) i sprawdzamy, czy tenant A ma jakikolwiek sposób, żeby go „dotknąć”.
Odkrycie: podatny resolver w module raportowym
W jednym z resolverów raportowych znaleźliśmy ścieżkę, gdzie autoryzacja była zrobiona na poziomie „czy użytkownik ma dostęp do modułu”, ale brakowało kontroli „czy ten raport należy do jego organizacji”.
Proof-of-concept (sam mechanizm)
Zapytanie prawidłowe (tenant A pobiera swój raport):
query Report($reportId: ID!) {
report(id: $reportId) {
id
title
summary
exportUrl
}
}
Zmiana tylko identyfikatora na należący do tenant B (a backend nadal odpowiada):
query Report($reportId: ID!) {
report(id: "RPT_983271_B") {
id
title
summary
exportUrl
}
}
Nie chodziło o „pełne przejęcie systemu”. To było bardziej niebezpieczne w realnym świecie, bo wyglądało jak normalna funkcja, tylko z błędnym zasięgiem danych. A takie rzeczy potrafią żyć miesiącami, bo monitoring zwykle patrzy na błędy, a tu błędu nie ma.
Ryzyko biznesowe: dlaczego multi-tenant IDOR to czerwony alarm
W B2B SaaS izolacja tenantów jest jednym z fundamentów zaufania. Jeśli dojdzie do ekspozycji danych pomiędzy klientami, konsekwencje idą szeroko: prawne, reputacyjne, kontraktowe.
W tym przypadku ryzyko obejmowało m.in. wgląd w podsumowania raportów oraz możliwość pobrania pliku eksportu, jeśli ktoś znał lub potrafił odgadnąć identyfikator. Nawet jeśli dane były „tylko częściowe”, to już jest naruszenie separacji klientów. A to w SaaS jest jak pęknięcie w akwarium (woda jeszcze się trzyma, ale wiesz, że to nie jest stan stabilny).
Remediacja: jak to naprawiliśmy, żeby nie było „łatki na jeden resolver”
Naprawę zaprojektowaliśmy tak, żeby wyeliminować cały wzorzec błędu, nie tylko jedną dziurę.
Pierwszy krok to tenant scoping jako zasada systemowa: każdy odczyt obiektu musi być wykonywany przez zapytanie, które zawiera tenant_id z kontekstu sesji i weryfikuje, że obiekt należy do tego tenant’a. Nie „czasem”, nie „w większości przypadków”, tylko zawsze.
Drugi krok to ujednolicenie autoryzacji w GraphQL: resolver nie może opierać się wyłącznie na tym, że „frontend i tak nie pokaże tego przycisku”. Frontend to nie granica bezpieczeństwa, to tylko UI.
Trzeci krok, który ratuje przyszłość: testy regresji na izolację tenantów. Dodaliśmy scenariusze negatywne, które w CI sprawdzają, że tenant A nie jest w stanie pobrać obiektów tenant B, nawet jeśli zna identyfikator.
Efekt: po retestach izolacja była twarda i przewidywalna
Po wdrożeniu zmian wykonaliśmy retesty i potwierdziliśmy, że próby „przeskoczenia” między tenantami kończą się odmową dostępu (bez przecieków metadanych typu „obiekt istnieje”). Najważniejsze było to, że klient dostał nie tylko poprawkę, ale też wzorzec architektoniczny, który da się powielić w kolejnych modułach GraphQL.
To jest różnica między „zrobiliśmy fix” a „zbudowaliśmy odporność”.
Jak Pentestica może pomóc
Jeśli masz SaaS w modelu multi-tenant, testy penetracyjne powinny obejmować izolację tenantów jako osobny, priorytetowy strumień testów (bo to jest miejsce, gdzie logika aplikacji robi największą krzywdę, gdy się pomyli).
W Pentestica robimy pentesty aplikacji web, mobilnych i API, a w projektach B2B szczególnie mocno dociskamy tematy autoryzacji, GraphQL i separacji danych. Tak, żebyś nie dowiedział się o problemie od klienta, który „zobaczył coś dziwnego w raporcie”.

Redakcja Pentestica.pl zespół ekspertów ds. cyberbezpieczeństwa, którzy dzielą się swoją wiedzą i praktycznym doświadczeniem w zakresie testów penetracyjnych, audytów it, regulacji NIS2, MiCA, DORA i nowych technologii. Nasi autorzy to doświadczeni pentesterzy, specjaliści bezpieczeństwa IT oraz konsultanci, którzy z pasją tworzą profesjonalne artykuły, aby przybliżyć Państwu tematykę cyberbezpieczeństwa w praktyce. Znajdą tu Państwo dogłębne analizy zagrożeń, omówienia technik ataków, porady dotyczące ochrony systemów oraz praktyczne wskazówki z zakresu testów penetracyjnych i wdrożeń regulacji. Naszym celem jest dostarczanie rzetelnej i aktualnej wiedzy, która pomoże Państwu lepiej zrozumieć świat cyberbezpieczeństwa i skutecznie chronić swoje zasoby cyfrowe.