Globalne wyszukiwanie uwzględniające uprawnienia — projekt bez wycieków danych
Dowiedz się, jak zaprojektować globalne wyszukiwanie uwzględniające uprawnienia z szybkim indeksowaniem i rygorystycznymi sprawdzeniami dostępu dla każdego rekordu, aby użytkownicy otrzymywali szybkie wyniki bez wycieków.

Dlaczego globalne wyszukiwanie może powodować wycieki danych
Globalne wyszukiwanie to zwykle jedno pole, które przeszukuje całą aplikację: klienci, zgłoszenia, faktury, dokumenty, użytkownicy i wszystko inne, z czym pracują ludzie. Często napędza autouzupełnianie i szybką stronę wyników, dzięki czemu użytkownicy szybko przechodzą do rekordu.
Wyciek pojawia się, gdy wyszukiwanie zwraca coś, czego użytkownik nie powinien wiedzieć, że istnieje. Nawet jeśli nie może otworzyć rekordu, pojedyncza linia — tytuł, czyjeś imię, tag lub podświetlony fragment — może ujawnić wrażliwe informacje.
Wyszukiwanie wydaje się "tylko do odczytu", więc zespoły je bagatelizują. Tymczasem może ujawniać dane przez tytuły wyników i podglądy, sugestie autouzupełniania, liczbę wyników, filtry typu „Klienci (5)” czy nawet różnice w czasie (szybko dla niektórych zapytań, wolniej dla innych).
Zwykle problem pojawia się później, nie pierwszego dnia. Na początku zespoły wdrażają wyszukiwanie, gdy jest tylko jedna rola albo gdy wszyscy widzą wszystko w bazie testowej. W miarę rozwoju produktu pojawiają się role (support vs sprzedaż, menedżerowie vs agenci) i funkcje jak wspólne skrzynki, prywatne notatki, ograniczeni klienci czy „tylko moje konta”. Jeśli wyszukiwanie nadal opiera się na starych założeniach, zaczyna zwracać wskazówki między zespołami lub klientami.
Częstym trybem awarii jest indeksowanie „wszystkiego” dla szybkości, a potem filtrowanie wyników w aplikacji po wykonaniu zapytania. To za późno. Silnik wyszukiwania już zdecydował, co pasuje i może ujawnić zastrzeżone rekordy przez sugestie, liczniki lub częściowe pola.
Wyobraź sobie agenta wsparcia, który powinien widzieć tylko zgłoszenia swoich przypisanych klientów. Wpisuje "Acme" i autouzupełnianie pokazuje "Acme - eskalacja prawna" lub "powiadomienie o naruszeniu Acme". Nawet jeśli kliknięcie kończy się „brak dostępu”, sam tytuł jest wyciekiem danych.
Cel globalnego wyszukiwania uwzględniającego uprawnienia jest prosty do powiedzenia i trudny do wdrożenia: zwracać szybkie, trafne wyniki przy egzekwowaniu tych samych zasad dostępu, które stosujesz przy otwieraniu każdego rekordu. Każde zapytanie musi zachowywać się, jakby użytkownik widział tylko swój wycinek danych, a interfejs nie może ujawniać dodatkowych wskazówek (jak liczniki) poza tym wycinkiem.
Co indeksujesz i co musisz chronić
Globalne wyszukiwanie wydaje się proste, bo użytkownicy wpisują słowa i oczekują odpowiedzi. Pod spodem tworzysz nową powierzchnię narażenia danych. Zanim wybierzesz indeks lub funkcję bazy, wyjaśnij dwie rzeczy: jakie obiekty przeszukujesz (encje) i które części tych obiektów są wrażliwe.
Encja to każdy rekord, który ktoś może chcieć szybko znaleźć. W większości aplikacji biznesowych należą do nich klienci, zgłoszenia, faktury, zamówienia i pliki (albo metadane plików). Mogą to być też dane osobowe (użytkownicy, agenci), notatki wewnętrzne i obiekty systemowe jak integracje czy klucze API. Jeśli ma nazwę, identyfikator lub status, którego ktoś może szukać, zazwyczaj trafia do globalnego wyszukiwania.
Reguły na poziomie rekordu vs na poziomie tabeli
Reguły na poziomie tabeli są szablonowe: albo masz dostęp do całej tabeli, albo nie. Przykład: tylko dział finansów może otworzyć stronę Faktury. To łatwe do zrozumienia, ale zawodzi, gdy różni ludzie powinni widzieć różne wiersze tej samej tabeli.
Reguły na poziomie rekordu decydują o widoczności wiersz po wierszu. Przykład: agent wsparcia widzi zgłoszenia przypisane do jego zespołu, a menedżer widzi wszystkie zgłoszenia w swoim regionie. Inna popularna reguła to własność tenantów: w aplikacji multi-tenant użytkownik widzi rekordy, gdzie customer_id = their_customer_id.
To właśnie te reguły na poziomie rekordu najczęściej powodują wycieki. Jeśli indeks zwraca trafienie przed sprawdzeniem dostępu do wiersza, już ujawniłeś, że coś istnieje.
Co w praktyce znaczy „może zobaczyć"
"Może zobaczyć" rzadko jest prostym przełącznikiem tak/nie. Zwykle łączy własność (utworzone przeze mnie, przypisane do mnie), członkostwo (mój zespół, mój dział, moja rola), zakres (mój region, jednostka biznesowa, projekt), stan rekordu (opublikowany, niearchiwalny) i wyjątki (VIP, blokady prawne, zastrzeżone tagi).
Najpierw zapisz te reguły prostym językiem. Później przekształcisz je w model danych i serwerowe sprawdzenia.
Zdecyduj, co bezpiecznie pokazywać w podglądzie wyniku
Wyniki wyszukiwania często zawierają podgląd, a podglądy mogą ujawniać wrażliwe dane, nawet jeśli użytkownik nie może otworzyć rekordu.
Bezpieczny domyślny wybór to pokazywać tylko minimalne, niewrażliwe pola do momentu potwierdzenia dostępu: nazwa wyświetlana lub tytuł (czasem zamaskowany), krótki identyfikator (np. numer zamówienia), ogólny status (Otwarte, Opłacone, Wysłane), data (utworzenia lub aktualizacji) i etykieta encji (Zgłoszenie, Faktura).
Konkretny przykład: jeśli ktoś wyszukuje "Acme merger" i istnieje zastrzeżone zgłoszenie, zwrócenie "Zgłoszenie: Acme merger draft - Prawo" to już wyciek. Bezpieczniejszy wynik to "Zgłoszenie: Zastrzeżone" bez podglądu albo brak wyniku, w zależności od polityki.
Dobre zdefiniowanie tego od początku upraszcza późniejsze decyzje: co indeksować, jak filtrować i co ujawniasz.
Podstawowe wymagania dla bezpiecznego i szybkiego wyszukiwania
Ludzie używają globalnego wyszukiwania, gdy się spieszą. Jeśli zajmuje dłużej niż sekundę, przestają mu ufać i wracają do ręcznego filtrowania. Ale szybkość to tylko połowa zadania. Szybkie wyszukiwanie, które ujawnia choć jeden tytuł rekordu, nazwę klienta lub temat zgłoszenia, jest gorsze niż brak wyszukiwania.
Reguła podstawowa, bez kompromisów: egzekwuj uprawnienia w czasie zapytania, nie tylko w UI. Ukrycie wiersza po jego pobraniu jest już za późno, bo system dotknął danych, których nie powinien był zwrócić.
To samo dotyczy wszystkiego wokół wyszukiwania, nie tylko listy wyników. Sugestie, top hits, liczniki, a nawet zachowanie „brak wyników" mogą ujawniać informacje. Autouzupełnianie pokazujące "Acme Renewal Contract" osobie, która nie ma do tego dostępu, to wyciek. Faseta mówiąca "12 pasujących faktur" to wyciek, jeśli użytkownik ma prawo zobaczyć tylko 3. Nawet czas odpowiedzi może ujawniać, jeśli ograniczone dopasowania sprawiają, że zapytanie jest wolniejsze.
Bezpieczne globalne wyszukiwanie potrzebuje czterech rzeczy:
- Poprawności: każdy zwrócony element jest dozwolony dla tego użytkownika, tej dzierżawy, w tym momencie.
- Szybkości: wyniki, sugestie i liczniki pozostają konsekwentnie szybkie, nawet przy dużej skali.
- Spójności: gdy dostęp się zmienia (zmiana roli, przypisanie zgłoszenia), zachowanie wyszukiwania zmienia się szybko i przewidywalnie.
- Audytowalności: potrafisz wytłumaczyć, dlaczego element został zwrócony, i zarejestrować aktywność wyszukiwania do dochodzeń.
Przydatna zmiana myślenia: traktuj wyszukiwanie jak kolejne API danych, a nie funkcję UI. To znaczy, że te same zasady dostępu, które stosujesz na stronach list, muszą obowiązywać też przy budowie indeksu, wykonaniu zapytania i na wszystkich powiązanych endpointach (autocomplete, ostatnie wyszukiwania, popularne zapytania).
Trzy powszechne wzorce projektowe (i kiedy ich używać)
Pole wyszukiwania jest łatwe do zbudowania. Wyszukiwanie globalne uwzględniające uprawnienia jest trudniejsze, bo indeks chce szybko zwracać wyniki, a twoja aplikacja nie może nigdy ujawnić rekordów, do których użytkownik nie ma dostępu, nawet pośrednio.
Poniżej trzy wzorce używane najczęściej. Wybór zależy od złożoności reguł dostępu i poziomu ryzyka, który możesz zaakceptować.
Podejście A: indeksuj tylko „bezpieczne" pola, potem pobierz po checku uprawnień. Przechowujesz minimalny dokument w indeksie, np. ID plus nie-wrażliwą etykietę, która jest bezpieczna do pokazania każdemu, kto może dotrzeć do interfejsu wyszukiwania. Gdy użytkownik klika wynik, aplikacja ładuje pełny rekord z bazy głównej i stosuje tam rzeczywiste zasady dostępu.
To zmniejsza ryzyko wycieków, ale wyszukiwanie może być "skąpe", bo użytkownicy dostają mało kontekstu. Wymaga też przemyślanego sformułowania w UI, żeby „bezpieczna" etykieta przypadkowo nie ujawniła sekretów.
Podejście B: przechowuj atrybuty uprawnień w indeksie i filtruj tam. Do każdego dokumentu indeksu dodajesz pola jak tenant_id, team_id, owner_id, flagi ról lub project_id. Każde zapytanie dodaje filtry dopasowujące zakres użytkownika.
To daje szybkie, bogate wyniki i dobre autouzupełnianie, ale działa tylko wtedy, gdy reguły dostępu da się wyrazić jako filtry. Jeśli uprawnienia zależą od złożonej logiki (np. „przypisany LUB na dyżurze w tym tygodniu LUB część incydentu"), trudno to utrzymać poprawnie.
Podejście C: hybryda. Grubszego filtru w indeksie, finalnego sprawdzenia w bazie. Filtrujesz w indeksie używając stabilnych, szerokich atrybutów (tenant, workspace, customer), a potem ponownie sprawdzasz uprawnienia dla małego zbioru kandydatów (ID) w bazie głównej przed zwróceniem czegokolwiek.
To często najbezpieczniejsza ścieżka dla rzeczywistych aplikacji: indeks pozostaje szybki, a baza jest źródłem prawdy.
Wybór wzorca
Wybierz A, gdy chcesz najprostsze rozwiązanie i możesz się pogodzić z minimalnymi podglądami. Wybierz B, gdy masz jasne, głównie statyczne zakresy (multi-tenant, dostęp zespołowy) i potrzebujesz bardzo szybkiego autouzupełniania. Wybierz C, gdy masz wiele ról, wyjątków lub reguł specyficznych dla rekordu, które często się zmieniają. Dla danych wysokiego ryzyka (HR, finanse, medycyna) preferuj C, bo „prawie poprawne" nie jest akceptowalne.
Krok po kroku: zaprojektuj indeks respektujący reguły dostępu
Zacznij od zapisania reguł dostępu tak, jak wytłumaczyłbyś nowemu współpracownikowi. Unikaj "admin widzi wszystko", chyba że to naprawdę prawda. Wypisz powody: "Agenci wsparcia widzą zgłoszenia z ich tenantów. Liderzy zespołów widzą też zgłoszenia swojej jednostki organizacyjnej. Tylko właściciel zgłoszenia i przypisany agent widzą prywatne notatki." Jeśli nie potrafisz powiedzieć, dlaczego ktoś może zobaczyć rekord, trudno będzie to zakodować bezpiecznie.
Następnie wybierz stabilny identyfikator i zdefiniuj minimalny dokument do indeksu. Indeks nie powinien być pełną kopią wiersza z bazy. Trzymaj tylko to, co potrzebne do odnalezienia i pokazania na liście wyników, np. tytuł, status i krótki, nie-wrażliwy fragment. Wrażliwe pola trzymaj poza indeksem za drugim pobraniem, które też sprawdza uprawnienia.
Potem zdecyduj, które sygnały uprawnień możesz szybko filtrować. To atrybuty, które ograniczają dostęp i można je przechowywać w każdym dokumencie indeksu, jak tenant_id, org_unit_id oraz kilka flag zakresu. Celem jest, by każde zapytanie mogło zastosować filtry przed zwróceniem wyników, także autouzupełnianie.
Praktyczny workflow wygląda tak:
- Zdefiniuj reguły widoczności dla każdej encji (zgłoszenia, klienci, faktury) prostym językiem.
- Stwórz schemat dokumentu wyszukiwania z record_id plus tylko bezpiecznymi, przeszukiwalnymi polami.
- Dodaj do każdego dokumentu filtrowalne pola uprawnień (tenant_id, org_unit_id, visibility_level).
- Obsługuj wyjątki za pomocą jawnych przydziałów: przechowuj allowlistę (ID użytkowników) lub ID grup dla udostępnionych pozycji.
Udostępnianie i wyjątki to miejsca, gdzie projekty zawodzą. Jeśli zgłoszenie może być współdzielone między zespołami, nie dodawaj tylko booleanu. Użyj jawnych przydziałów, które można sprawdzać filtrami. Jeśli allowlista jest duża, preferuj przydziały oparte na grupach zamiast indywidualnych użytkowników.
Utrzymanie indeksu w synchronizacji bez niespodzianek
Bezpieczne doświadczenie zależy od jednej nudnej rzeczy zrobionej dobrze: indeks musi odzwierciedlać rzeczywistość. Jeśli rekord zostanie utworzony, zmieniony, usunięty lub zmienią się jego uprawnienia, wyniki wyszukiwania muszą się zmieniać szybko i przewidywalnie.
Nadążaj za tworzeniem, aktualizacją, usuwaniem
Traktuj indeksowanie jako część lifecycle danych. Przydatny model mentalny: za każdym razem, gdy źródło prawdy się zmienia, emitujesz zdarzenie, a indekser reaguje.
Typowe podejścia to triggery bazodanowe, zdarzenia aplikacji lub kolejka zadań. Najważniejsze, by zdarzenia nie ginęły. Jeśli aplikacja zapisze rekord, ale zawiedzie indeksowanie, dostaniesz mylące zachowanie typu "Wiem, że to istnieje, ale wyszukiwanie tego nie znajduje."
Zmiany uprawnień to zmiany w indeksie
Wiele wycieków zdarza się, gdy treść aktualizuje się poprawnie, ale metadane dostępu już nie. Zmiany uprawnień wynikają z aktualizacji ról, przeniesień między zespołami, transferów własności, przypisań klienta lub łączenia zgłoszeń.
Traktuj zmiany uprawnień jako zdarzenia pierwszej klasy. Jeśli twoje wyszukiwanie opiera się na filtrach typu tenant lub team, upewnij się, że dokumenty indeksu zawierają pola potrzebne do egzekwowania tego (tenant_id, team_id, owner_id, allowed_role_ids). Gdy te pola się zmienią, zreindeksuj.
Trudna część to powierzchnia rażenia. Zmiana roli może dotyczyć tysięcy rekordów. Zaplanuj drogę reindeksacji zbiorczej z postępem, retry i możliwością pauzy.
Zaplanuj spójność eventualną
Nawet z dobrymi zdarzeniami będzie okno, w którym indeks jest opóźniony. Zdecyduj, co użytkownicy mają widzieć w pierwszych sekundach po zmianie.
Dwa pomocne zasady:
- Bądź konsekwentny co do opóźnień. Jeśli indeksowanie zwykle kończy się w 2–5 sekund, ustaw takie oczekiwanie tam, gdzie to ma znaczenie.
- Wybierz brak zamiast wycieku. Bezpieczniej, jeśli nowo przyznany rekord pojawi się nieco później, niż gdy świeżo odebrany rekord nadal się pokazuje.
Dodaj bezpieczny fallback, gdy indeks jest nieświeży
Wyszukiwanie służy discoverability, ale oglądanie szczegółów to miejsce, gdzie wycieki bolą najbardziej. Wykonaj drugie sprawdzenie uprawnień przy odczycie, zanim pokażesz wrażliwe pola. Jeśli wynik przemyci się przez indeks z powodu stanu nieświeżego, strona ze szczegółami powinna nadal zablokować dostęp.
Dobry wzorzec: pokazuj minimalne podglądy w wynikach, potem ponownie sprawdzaj uprawnienia, gdy użytkownik otwiera rekord (lub rozwija podgląd). Jeśli check zawiedzie, pokaż jasny komunikat i usuń element z widocznych wyników przy następnym odświeżeniu.
Typowe błędy prowadzące do wycieków danych
Wyszukiwanie może ujawnić dane, nawet gdy strona "otwórz rekord" jest zabezpieczona. Użytkownik może nigdy nie kliknąć wyniku, a mimo to dowiedzieć się nazw, identyfikatorów klientów czy rozmiaru ukrytego projektu. Permission-aware global search musi chronić nie tylko dokumenty, ale też wskazówki o dokumentach.
Autouzupełnianie to częste źródło wycieków. Sugestie często napędzane są przez szybkie wyszukiwanie prefiksowe, które pomija pełne sprawdzenia uprawnień. UI wygląda nieszkodliwie, ale pojedyncza wpisana litera może ujawnić nazwę klienta lub czyjś e-mail. Autouzupełnianie musi uruchamiać te same filtry dostępu co pełne wyszukiwanie albo być zbudowane z wcześniej przefiltrowanego zbioru sugestii (np. per-tenant i per-roli).
Liczby w fasetach i bannery typu "Około 1 243 wyników" to kolejny cichy wyciek. Liczniki potwierdzają, że coś istnieje, nawet jeśli ukrywasz rekordy. Jeśli nie możesz bezpiecznie obliczyć liczników zgodnie z regułami dostępu, pokaż mniej szczegółów albo pomiń liczniki.
Caching to kolejny sprawca. Wspólne cache'e między użytkownikami, rolami lub tenantami mogą tworzyć "widma wyników", gdzie jeden użytkownik widzi wyniki wygenerowane dla kogoś innego. Może się to dziać na warstwie edge, w cache'ach aplikacji i w pamięci wewnątrz usługi wyszukiwania.
Pułapki warte wcześniejszego sprawdzenia:
- Autouzupełnianie i ostatnie wyszukiwania są filtrowane tymi samymi regułami co pełne wyszukiwanie.
- Liczniki i sumy faset są liczone po zastosowaniu uprawnień.
- Klucze cache zawierają tenant ID i sygnaturę uprawnień (rola, zespół, user ID).
- Logi i analityka nie przechowują surowych zapytań ani fragmentów wyników dla zastrzeżonych danych.
Na koniec uważaj na zbyt szerokie filtry. "Filtrowanie tylko po tenant" to klasyczny błąd multi-tenant, ale zdarza się też wewnątrz jednego tenanta: filtrowanie po "dziale" tam, gdzie dostęp jest na poziomie rekordu. Przykład: agent szuka "refund" i dostaje wyniki dla wszystkich klientów w tenancie, w tym VIP-ów, które powinny być widoczne tylko dla węższego zespołu. Naprawa jest prosta w zasadzie: egzekwuj reguły na poziomie wiersza w każdej ścieżce zapytania (wyszukiwanie, autouzupełnianie, fasety, eksporty), nie tylko na widoku rekordu.
Prywatność i szczegóły bezpieczeństwa, które się zapomina
Wiele projektów skupia się na "kto co może zobaczyć", ale wycieki zdarzają się też przez krawędzie: stany puste, czasy odpowiedzi i drobne wskazówki w UI. Wyszukiwanie uwzględniające uprawnienia musi być bezpieczne nawet, gdy nie zwraca nic.
Łatwy do przeoczenia wyciek to potwierdzenie przez brak: jeśli nieautoryzowany użytkownik wyszukuje konkretną nazwę klienta, ID zgłoszenia lub e-mail i dostaje specjalny komunikat "Brak dostępu" lub "Nie masz uprawnień", potwierdziłeś istnienie rekordu. Traktuj "brak wyników" jako domyślny wynik zarówno dla "nie istnieje", jak i "istnieje, ale brak dostępu". Utrzymuj spójny czas odpowiedzi i treść, żeby użytkownicy nie mogli zgadywać na podstawie szybkości.
Wrażliwe części dopasowań
Autouzupełnianie i search-as-you-type to miejsca, gdzie prywatność się wyślizguje. Częściowe dopasowania do e-maili, numerów telefonów czy numerów identyfikacyjnych mogą ujawniać więcej, niż chcesz. Zdecyduj wcześniej, jak te pola będą działać.
Praktyczny zestaw reguł:
- Wymagaj dopasowania dokładnego dla pól wysokiego ryzyka (e-mail, telefon, ID).
- Unikaj pokazywania podświetlonych fragmentów, które ujawniają ukryty tekst.
- Rozważ wyłączenie autouzupełniania dla wrażliwych pól.
Jeśli nawet jeden znak pomaga komuś odgadnąć dane, traktuj to pole jako wrażliwe.
Kontrole nadużyć, które nie tworzą nowych ryzyk
Endpointy wyszukiwania są idealne do ataków enumeracyjnych: próbowania wielu zapytań, by zmapować, co istnieje. Dodaj ograniczenia szybkości i wykrywanie anomalii, ale uważaj, co zapisujesz. Logi zawierające surowe zapytania mogą stać się drugim źródłem wycieku.
Utrzymaj to proste: limituj szybkość per użytkownik, per IP i per tenant; loguj liczby, czasy i ogólne wzorce (nie pełny tekst zapytań); alertuj przy powtarzających się "near-miss" zapytaniach (np. sekwencyjne ID); i blokuj albo wymagaj dodatkowej weryfikacji po powtarzających się nieudanych próbach.
Uczyń błędy nudnymi. Używaj tego samego komunikatu i stanu pustego dla "brak wyników", "brak uprawnień" i "nieprawidłowe filtry". Im mniej mówi UI, tym mniej przypadkowo może ujawnić.
Przykład: zespół wsparcia przeszukujący zgłoszenia klientów
Agentka wsparcia, Maya, pracuje w zespole obsługującym trzy konta klientów. Ma jedno pole wyszukiwania w nagłówku aplikacji. Produkt ma globalny indeks dla zgłoszeń, kontaktów i firm, ale każdy wynik musi przestrzegać reguł dostępu.
Maya wpisuje "Alic", bo dzwoniła osoba o imieniu Alice. Autouzupełnianie pokazuje kilka sugestii. Kliknęła "Alice Nguyen - Zgłoszenie: Reset hasła." Zanim cokolwiek otworzy, aplikacja ponownie sprawdza dostęp do tego rekordu. Jeśli zgłoszenie nadal jest przypisane do jej zespołu i jej rola na to pozwala, widzi szczegóły zgłoszenia.
Co Maya widzi na każdym etapie:
- Pole wyszukiwania: sugestie pojawiają się szybko, ale tylko dla rekordów, do których ma teraz dostęp.
- Lista wyników: temat zgłoszenia, nazwa klienta, czas ostatniej aktualizacji. Brak placeholderów typu "brak dostępu".
- Szczegóły zgłoszenia: pełny widok ładuje się dopiero po drugim serwerowym sprawdzeniu uprawnień. Jeśli dostęp się zmienił, aplikacja pokaże "Zgłoszenie nie znalezione" (nie "zabronione").
Porównaj to z Leo, nowym agentem na szkoleniu. Jego rola pozwala oglądać tylko zgłoszenia oznaczone "Public to Support" i tylko dla jednego klienta. Leo wpisuje to samo "Alic." Widzi mniej sugestii i żadne brakujące nie są zasugerowane. Nie pojawia się licznik "5 wyników", który ujawniłby istnienie innych dopasowań. UI po prostu pokazuje to, co może otworzyć.
Później menedżer przekierowuje "Alice Nguyen - Reset hasła" z zespołu Mai do zespołu eskalacyjnego. W krótkim oknie (zwykle sekundy do kilku minut, w zależności od podejścia synchronizacji) wyszukiwanie Mai przestaje zwracać to zgłoszenie. Jeśli ma otwartą stronę ze szczegółami i odświeży, aplikacja ponownie sprawdzi uprawnienia i zgłoszenie zniknie.
To jest pożądane zachowanie: szybkie wpisywanie i szybkie wyniki, bez zapachu danych przez liczniki, fragmenty czy nieświeże wpisy w indeksie.
Lista kontrolna i kolejne kroki do bezpiecznej implementacji
Wyszukiwanie globalne uwzględniające uprawnienia jest „gotowe" dopiero wtedy, gdy nudne krawędzie są bezpieczne. Wiele wycieków pojawia się w miejscach, które wydają się nieszkodliwe: autouzupełnianie, liczniki, eksporty.
Szybkie kontrole bezpieczeństwa
Zanim wdrożysz, przejdź przez te kontrole na prawdziwych danych, nie próbkach:
- Autouzupełnianie: nigdy nie sugeruj tytułu, nazwy ani ID, których użytkownik nie może otworzyć.
- Liczniki i fasety: jeśli pokazujesz sumy lub liczniki grup, obliczaj je po zastosowaniu uprawnień (lub pomiń liczniki).
- Eksporty i akcje zbiorcze: eksport "bieżącego wyszukiwania" musi ponownie sprawdzić dostęp dla każdego wiersza w czasie eksportu.
- Sortowanie i podświetlanie: nie sortuj ani nie podświetlaj według pól, których użytkownik nie ma prawa widzieć.
- "Nie znaleziono" vs "zabronione": dla wrażliwych encji rozważ tę samą strukturę odpowiedzi, aby użytkownicy nie mogli potwierdzić istnienia.
Plan testów, który możesz wykonać
Stwórz małą macierz ról (role x encje) i zestaw danych z celowo trudnymi przypadkami: rekordy współdzielone, właśnie odebrane prawa, i podobieństwa między tenantami.
Testuj w trzech etapach: (1) testy macierzy ról, gdzie weryfikujesz, że odrzucone rekordy nigdy nie pojawiają się w wynikach, sugestiach, licznikach ani eksportach; (2) testy "spróbuj to złamać", gdzie wklejasz ID, szukasz po e-mailu lub telefonie i próbujesz częściowe dopasowania, które nie powinny nic zwrócić; (3) testy czasu i cache'u, gdzie zmieniasz uprawnienia i potwierdzasz, że wyniki aktualizują się szybko bez nieświeżych sugestii.
Operacyjnie zaplanuj dzień, gdy wyniki wyszukiwania "wyglądają źle." Loguj kontekst zapytania (użytkownik, rola, tenant) i zastosowane filtry uprawnień, ale unikaj przechowywania surowych wrażliwych zapytań lub fragmentów. Dla bezpiecznego debugowania zbuduj narzędzie dostępne tylko dla administratorów, które potrafi wyjaśnić, dlaczego rekord dopasował się i dlaczego został dozwolony.
Jeśli budujesz na AppMaster (appmaster.io), praktyczne podejście to trzymać wyszukiwanie jako flow po stronie serwera: modeluj encje i relacje w Data Designer, egzekwuj reguły dostępu w Business Processes i ponownie używaj tych samych sprawdzeń uprawnień dla autouzupełniania, listy wyników i eksportów, aby mieć tylko jedno miejsce do poprawnego wdrożenia.


