Testowanie granic zaufania między funkcjami systemu

Sprawdź współdziałanie funkcji: testuj udostępnione podglądy, dokumentuj przekroczenia uprawnień, oceniaj zgłoszenia i weryfikuj pełną poprawkę.

Ernest Bursa

Ernest Bursa

Founder · · 8 min czytania
A security engineer and two colleagues comparing a paper test matrix with connected feature cards on a whiteboard in a sunlit garage workspace

Testowanie granic zaufania między funkcjami polega na sprawdzeniu, czy możliwość bezpieczna w jednej części systemu staje się zagrożeniem, gdy uzyska do niej dostęp inna funkcja. Zacznij od tego, co kontroluje atakujący. Prześledź każde przejście do kontekstu z szerszymi uprawnieniami i przetestuj kombinacje, które je umożliwiają. Pozytywny wynik testów bezpieczeństwa pojedynczej funkcji to tylko część potrzebnych dowodów.

Niewielki zespół bezpieczeństwa potrzebuje konkretnego wyniku: krótkiej macierzy stanów funkcji, zgłoszenia pokazującego, jaka operacja stała się dostępna, oraz ponownego testu obejmującego wdrożone warianty. Na początek wystarczy jeden udostępniany obiekt i komponenty, które odbierają jego komunikaty lub renderują dla niego treści.

Izolacja podglądu nie wystarczy, jeśli odbiorca ufa mu za bardzo

W publikacji z 28 października Parameter opisał łańcuch ataku na ChatGPT łączący udostępnioną rozmowę, wykres i HTML Preview. Według badaczy wykres ładował MathLive w głównym dokumencie strony. Podgląd mógł następnie wysyłać komunikaty do odbiornika, który przyjmował kod HTML układu klawiatury bez dostatecznej weryfikacji nadawcy. Ten sposób renderowania tworzył ramkę bez izolacji w sandboxie, a dozwolony zewnętrzny adres skryptu umożliwiał obejście CSP.

Parameter zademonstrował dostęp do danych prywatnych rozmów przez sesję zalogowanego użytkownika. Najbardziej powtarzalne odtworzenie wymagało otwarcia udostępnionej rozmowy i kliknięcia Preview. Badacze opisali też trzy przypadki, w których podgląd otworzył się automatycznie. Według Parameter OpenAI potwierdziło 26 października, że obie wersje interfejsu webowego odrzucały zgłoszone komunikaty.

Opisujemy ustalenia badaczy, a nie testy wykonane przez nas. Dyskusja na Hacker News wyjaśnia kontekst tej publikacji. Praktyczny wniosek: trzeba sprawdzać, jak osobne funkcje przekazują sobie uprawnienia, także przez ścieżki publikowania i udostępniania.

To inne zadanie niż sprawdzanie, czy złośliwy tekst potrafi zmienić działanie agenta. Prompt injection przy pobieraniu treści przez agenta rekrutacyjnego dotyczy wpływu pobranych materiałów na asystenta korzystającego z narzędzi. Odbiornik w przeglądarce może przyjąć nieuprawnioną instrukcję bez jakiegokolwiek przekonywania modelu. Osobnym zagadnieniem jest też izolacja danych klientów u dostawcy AI, czyli to, czy dalsze przetwarzanie prawidłowo rozdziela dane klientów.

Ustal, gdzie dane zaczynają decydować o uprawnieniach

Mapa granic zaufania powinna wskazywać zarówno niezaufane dane wejściowe, jak i uprzywilejowaną operację, na którą mogą wpłynąć. Zdanie „podgląd działa w sandboxie” opisuje jeden komponent. Nie mówi, co zrobi reszta systemu po otrzymaniu komunikatu z tego podglądu.

Opisz kolejne etapy prostymi słowami:

  1. Osoba spoza konta ofiary kontroluje udostępniony obiekt.
  2. Otwarcie obiektu ładuje komponent na stronie zalogowanego użytkownika.
  3. Inny komponent przyjmuje instrukcję z tego obiektu.
  4. Instrukcja wpływa na renderowanie, żądanie lub operację na koncie.

Przy każdym przejściu wskaż odbiorcę i powód przyjęcia danych. Czy sprawdza dokładną wartość origin? Konkretne okno? Typ komunikatu? Decyzję serwera o przyznaniu dostępu? Jeśli jedynym warunkiem jest oczekiwana struktura komunikatu, masz założenie wymagające sprawdzenia.

Dokumentacja MDN dotycząca postMessage zaleca sprawdzanie tożsamości nadawcy i walidację odebranych danych. Przy wysyłaniu komunikatów zaleca też podawanie dokładnego docelowego origin. Znany format komunikatu nie potwierdza prawa do korzystania z możliwości odbiorcy.

Na mapie rozdziel uprawnienia przeglądarki od uprawnień serwera. Serwer może poprawnie autoryzować żądanie jako pochodzące od zalogowanego użytkownika, choć kod kontrolowany przez atakującego uzyskał możliwość jego wysłania. Wtedy trzeba ustalić, jak ten kod trafił do uwierzytelnionego kontekstu.

Zbuduj małą macierz kombinacji funkcji

Wybierz najmniejszy zestaw kombinacji pozwalający ustalić, gdzie zmienia się granica zaufania. Najpierw sprawdź każdy komponent osobno, potem je połącz. Uwzględnij ścieżkę, którą inna osoba faktycznie otwiera udostępniony obiekt.

Poniższa macierz to przykład planu dla systemu z udostępnianymi podglądami. Nie przedstawia wyników testów ChatGPT ani Kit.

Stan testowy Pytanie Dowody do zachowania
Udostępniony obiekt, podgląd wyłączony Czy wyświetlenie obiektu ładuje uprzywilejowanego odbiorcę? Załadowane komponenty i rejestracja odbiornika
Podgląd włączony, brak funkcji towarzyszącej Czy sam podgląd może dotrzeć do odbiorcy? Kontekst nadawcy i zaobserwowane odrzucenie lub obsługa
Funkcja towarzysząca i podgląd włączone Czy ich połączenie zmienia dozwoloną ścieżkę komunikatów? Decyzja odbiorcy i udostępniona w jej wyniku możliwość
Ta sama kombinacja przez publiczny link Czy udostępnienie zachowuje komponenty potrzebne do przekroczenia granicy? Ścieżka, stan konta i dokładna sekwencja interakcji
Ta sama kombinacja po pełnym przeładowaniu strony Czy kolejność inicjalizacji zmienia wynik? Czasy, kolejność ładowania i powtarzalność
Ta sama kombinacja we wdrożonych wariantach Czy wszystkie aktywne wersje egzekwują tę samą granicę? Identyfikator wersji i wynik dla każdego wariantu

Przed wykonaniem testu zapisz oczekiwane zachowanie. Na przykład: „Okno nadrzędne odrzuca komunikat o ustawieniach z tego podglądu, ponieważ nadawca nie ma prawa zmienić tego ustawienia”. Sama nieudana próba wykorzystania podatności nie rozstrzyga sprawy. Odbiorca mógł ją odrzucić, ale mógł też w ogóle się nie załadować.

Korzystaj z kont, na których masz zgodę na testy, i nieszkodliwych znaczników. Badając dostęp do prywatnych danych, utwórz rekord testowy z jednoznacznie rozpoznawalną sztuczną wartością. Zbieraj dowody wystarczające do potwierdzenia przekroczenia granicy. Pobieranie prawdziwych rekordów użytkowników zwiększa narażenie danych, nie pomagając wyjaśnić mechanizmu.

Gdy komponenty inicjalizują się niezależnie, celowo zmieniaj odstępy między działaniami. Zapisuj, czy operacja działa dopiero po załadowaniu innej funkcji, czy przeładowanie zmienia wynik i czy zwykły interfejs wymaga dodatkowego kliknięcia. Te warunki powinny znaleźć się w zgłoszeniu: wpływają na powtarzalność i na to, kiedy użytkownik może zetknąć się z problemem.

Pokaż w triażu dostępną operację, nie sam alert

Przydatne zgłoszenie pokazuje, co stało się możliwe w danym kontekście. Zrzut ekranu z alertem pomaga ustalić, gdzie wykonał się JavaScript. Nie odpowiada jednak na pytanie, do jakich danych lub operacji ten kod miał dostęp.

Przygotuj zgłoszenie tak, by inny inżynier mógł odtworzyć wynik bez zgadywania:

  • Co kontroluje atakujący: obiekt, pole, plik lub komunikat, który może dostarczyć zgłaszający.
  • Warunki po stronie ofiary: stan konta, rola, włączone funkcje i wymagane interakcje.
  • Przekroczona granica: kontekst nadawcy, odbiorca i przyjęta przez niego operacja.
  • Minimalne odtworzenie: dokładna ścieżka i sekwencja działań ze sztucznymi danymi testowymi.
  • Zachowanie oczekiwane i zaobserwowane: co powinno zostać odrzucone i co wydarzyło się zamiast tego.
  • Wykazany wpływ: konkretny prywatny rekord testowy lub operacja objęta ograniczeniami, do których uzyskano dostęp.
  • Ograniczenia: niestabilne zależności czasowe, niesprawdzone role, niedostępne warianty i hipotetyczne rozszerzenia ataku.

Oddziel wykazany odczyt od przypuszczenia o możliwości zapisu. Jeśli demonstracja pobiera prywatny sztuczny rekord, opisz wprost ten wpływ na poufność. Jeśli inna operacja na koncie wydaje się dostępna, lecz nie została sprawdzona, oznacz ją jako hipotezę. Ogólne określenie „pełne przejęcie konta” nie zastąpi dowodów potrzebnych zespołowi do oceny zakresu problemu.

Gdy zgłoszenia nie da się odtworzyć, przed jego odrzuceniem ustal, którego warunku brakuje. Różnicę może wyjaśniać funkcja towarzysząca, inna wersja interfejsu lub druga interakcja. Poproś wprost o ten szczegół, a następnie dodaj go do macierzy, by kolejna próba zaczynała się od tego samego stanu.

Zweryfikuj poprawkę odbiorcy na całej ścieżce

Weryfikacja poprawki powinna wyjaśniać, dlaczego pierwotne przekroczenie granicy już nie działa. Zablokowanie skryptu na dalszym etapie może zatrzymać konkretną demonstrację, mimo że nieuprawnione komunikaty nadal wpływają na renderowanie w zaufanym kontekście.

Sprawdź decyzję odbiorcy i ponów test od udostępnionego obiektu. Czy niezaufany nadawca nadal może zmienić ustawienie? Czy jego dane wciąż mogą dotrzeć do miejsca interpretującego HTML? Czy dynamicznie utworzona treść zachowuje zamierzone ograniczenia? Który mechanizm odrzuca operację i czy test pozwala zaobserwować to odrzucenie?

Wskazówki OWASP Web Security Testing Guide dotyczące komunikacji między oknami obejmują sprawdzanie origin i obsługę danych wejściowych. Nawet dane z dozwolonego origin wymagają odpowiedniej walidacji. Traktuj origin, tożsamość okna, strukturę komunikatu i dozwoloną operację jako osobne kwestie.

Ponowny test oprzyj na pierwotnej macierzy. Dodaj bliskie warianty, których sprawdzenie uzasadnia objęty poprawką kod: inną ścieżkę udostępniania, kolejny komponent korzystający z tego samego odbiorcy lub starszy interfejs nadal obsługujący ruch. Nie zamieniaj każdego zgłoszenia w audyt bez końca. Prześledź wspólny mechanizm i zapisz, gdzie kończy się przegląd.

Sprawdź również prawidłowe użycie funkcji. Uprawniony komponent powinien nadal wykonywać swoją operację po odrzuceniu niezaufanego nadawcy. W przeciwnym razie poprawka wyłączająca całą funkcję może zatrzymać odtworzenie podatności, a zarazem zepsuć proces potrzebny użytkownikom.

Oddziel rozwiązanie problemu od weryfikacji

Zapisuj usunięcie podatności i potwierdzające je dowody jako osobne kroki. Wdrożona zmiana potwierdza, że ktoś dostarczył poprawkę. Weryfikacja ustala, co przetestowano ponownie, na której wersji i z jakim wynikiem.

Obsługa zgłoszeń podatności w Kit ma osobne stany dla rozwiązanego problemu i zweryfikowanej poprawki. Dzięki temu zespół może śledzić przekazanie pracy do weryfikacji. Sam status nie wykonuje jednak testów z macierzy w przeglądarce ani nie dowodzi skuteczności granicy zaufania. Zgłoszenie nadal wymaga opisu odtworzenia, danych wersji i dowodów ponownego testu.

W tym tygodniu zacznij od jednego publicznego obiektu lub takiego, który można udostępnić. Wypisz uprzywilejowane komponenty, z którymi może się kontaktować. Wybierz jednego odbiorcę zmieniającego stan i przetestuj obiekt osobno oraz razem z funkcją ładującą tego odbiorcę. Wynik powinien wskazać, gdzie sprawdzane są uprawnienia, i dać kolejnemu inżynierowi dość dowodów, by zweryfikował tę samą granicę.

Powiązane artykuły

Wypróbuj Kit przez 30 dni.

Rekrutacja, zgłoszenia podatności i szkolenia w jednym koncie, dla zespołów, w których nikt nie robi tego na pełny etat. Kartę podajesz na starcie; zrezygnuj przed końcem okresu próbnego, a nic nie zapłacisz.

Zacznij za darmo