Kolekcja 600+ ciekawych linków z newslettera? Znajdziesz ją tutaj

Jak można było pobrać bazę użytkowników Stoop (i nie tylko)

Stworzone przez człowieka

04.06.2026 13:35 | 7 min czytania

Tagi: Bezpieczeństwo Narzędzia Prywatność RODO

O usłudze Stoop pisałem już w pierwszym artykule na tym blogu. Jednak to, że wtedy z niej już nie korzystałem, wcale nie oznacza, że skończyłem z nią na zawsze. Z racji że nie tak dawno temu oficjalnie pożegnała się ona ze wszystkimi swoimi użytkownikami, zdecydowałem się pokazać to, o czym wspomniani mogli nie wiedzieć. A wiedzieć mógł każdy, kto tylko chciał i wiedział jak…

Zrzut ekranu strony Stoop

Zacznijmy jednak od początku. Stoop domyślnie działał jako aplikacja mobilna. Z czasem pojawił się dodatkowo interfejs webowy (beta.stoopinbox.com — na marginesie: do końca istnienia narzędzia była to subdomena „beta”). Było to bardzo wygodne rozwiązanie, ponieważ można było czytać te same treści (i widzieć ten sam feed) zarówno na telefonie, jak i komputerze. Aktualnie korzystam tak samo równolegle z mojego klienta RSS i bardzo cenię sobie tę równoległość — dla porównania platformy typu Facebook/Instagram pokazują nieco inny feed przy każdym otwarciu strony/aplikacji i jest to uciążliwe.

Aplikacja webowa w porównaniu z mobilną jest dużo łatwiejsza w analizie. Nie trzeba działać na dwóch urządzeniach, uruchamiać maszyny wirtualnej ani konfigurować proxy. Po prostu otwieramy narzędzia deweloperskie przeglądarki i widzimy wszystko, co dzieje się w aplikacji. Ta łatwość w połączeniu z ciekawością doprowadziła mnie do odkrycia, że za backend aplikacji webowej (i zapewne także mobilnej) Stoop odpowiadało Firebase.

Firebase to usługa od Google ułatwiająca tworzenie aplikacji z backendem. Niektórzy mówią, że jest to rozwiązanie backendowe dla programistów frontendowych i mają w tym trochę racji. Działanie usługi polega bowiem na tym, że z gotowymi narzędziami takimi jak bazy danych (Real-time database i Cloud Firestore), moduł uwierzytelniania i rejestracji użytkowników (w tym obsługa wielu dostawców OAuth2 a więc logowanie przez konto GitHub, Google itp.) czy powiadomienia push, łączymy się przez dostarczone przez Google biblioteki i SDK działające po stronie klienta (na urządzeniu użytkownika).

W efekcie większość logiki jest zdefiniowana w warstwie frontendu aplikacji, a Firebase obsługuje głównie operacje CRUD na serwerze. Żeby było to jakkolwiek bezpieczne, w ramach usługi działają tzw. reguły bezpieczeństwa, dzięki którym możemy ograniczyć dostęp do API zależnie od różnych parametrów i uprawnień.

Była to moja największa bolączka, gdy uczyłem się tworzyć aplikacje z Firebase. Zaraz po odkryciu, że większość błędów na tworzonej stronie wynika z blokowania bibliotek Firebase przez uBlock Origin (wtedy wczytywałem je bezpośrednio z CDN), musiałem zmierzyć się z regułami bezpieczeństwa.

Reguły bezpieczeństwa dla Realtime Database (z niej wtedy korzystałem) definiuje się w postaci JSON. Głównym problemem jest fakt, że trzeba zadbać o poprawne uwierzytelnienie i autoryzację tak samo jak w „normalnym” API, ale jest to dużo mniej intuicyjne — a przynajmniej tak jest na początku.

Przykładowe reguły (na podstawie dokumentacji):

{
    "rules": {
        "foo": {
            ".read": true,
            ".write": false
        },
        "$uid": {
            ".write": "$uid === auth.uid"
        }
    }
}

Brak poprawnej konfiguracji reguł nie musi dawać się we znaki, bo wszystko działa i aplikacja nie zwraca błędów. Skutkiem ubocznym jest fakt, że każdy ma dostęp do wszystkich danych, o ile wykona odpowiednie zapytanie do API. Z kolei źle skonfigurowane reguły mogą spowodować, że normalne żądanie ze strony użytkownika zwróci brak dostępu i nasza aplikacja nie zadziała. Innymi słowy — łatwiej jest po prostu udzielić dostępu wszystkim i nie bawić się w konfigurację.

Na tym etapie warto jeszcze wyjaśnić, jak nasza aplikacja komunikuje się z Firebase. Odbywa się to przez adresy URL i klucze API zdefiniowane w… kodzie frontendu. Tak, tym samym kodzie, który można podejrzeć w narzędziach deweloperskich. Wartości te można znaleźć również analizując ruch sieciowy, więc dla aplikacji mobilnych jest to podobnie łatwo wykonalne. Jeśli więc logikę sprawdzania uprawnień użytkownika zrobimy na poziomie frontendu (co jest w pewnym sensie zasadne — bo np. chcemy wyświetlić konkretne komponenty UI tylko dla niektórych grup użytkowników), to wystarczy że użytkownik sam wykona żądania do API (bez naszego kodu) i uzyska dostęp do wielu danych. Dlatego tak ważne jest skonfigurowanie ograniczeń po stronie Firebase.

Wiedząc już, że aplikacja Stoop komunikuje się z Firebase, postanowiłem sprawdzić czy dane prezentowane w UI różnią się od tych zwracanych przez API. W skrócie: zobaczyć, czy w API nie ma więcej danych niż potrzeba.

Zacząłem od zlokalizowania danych umożliwiających połączenie z bazą — są to publiczne klucze API, które mogą być jawne (model bezpieczeństwa nie zależy od klucza, tylko od reguł dla danej bazy/zasobu). Tak jak wspomniałem, były one po prostu zapisane w kodzie aplikacji:

Fragment kodu z kluczem API i adresem URL bazy

Następnie pozostało już tylko — omijając interfejs Stoop — połączyć się z bazą danych. Wykorzystałem w tym celu narzędzie firepwn. Wystarczyło przekleić poświadczenia znalezione w kodzie i odgadnąć nazwę kolekcji (strzał w users okazał się wyjątkowo celny), aby zobaczyć to:

Widzimy po prostu całą bazę danych w formie JSON. Można więc było poznać listę prywatnych (przypisanych do konta) adresów e‑mail, subskrybowanych newsletterów oraz trochę metadanych (np. platforma, na której użytkownik zakładał konto).

Uwagę może zwracać także Auth Service w prawej części okna. Jest to moduł do logowania/rejestracji z Firebase. Bardzo często baza nie jest dostępna (reguły bezpieczeństwa) dla każdego, ale wystarczy że zalogujemy się na dowolne konto — i już mamy dostęp do wszystkich danych. Klasyczny przykład braku poprawnej autoryzacji — weryfikacja zakończyła się na poprawnym uwierzytelnieniu użytkownika, ale nie wzięto pod uwagę, że nie powinien on mieć dostępu do zasobów innych użytkowników.

No dobrze, mamy wyciek, to wypadałoby zawiadomić administratora. Pierwszą wiadomość w tej sprawie wysłałem 24 października 2024 r. i pozostała ona bez odpowiedzi. Kolejną wysłałem 8 listopada, kierując ją na kilka różnych firmowych adresów. Również bez odpowiedzi. Następnym krokiem była próba kontaktu przez LinkedIn, ale i ona została zignorowana. Nie było oficjalnego bug bounty, nie było security.txt, nie było nawet klucza PGP. I nie było też żadnej reakcji.

Wystarczyło jednak odczekać niecały rok i aplikacja zaorała się sama:

Zrzut ekranu maila informującego o zamknięciu Stoop
Czyli jednak znacie mojego maila?

W tym przypadku mówimy jedynie o możliwości podglądu danych użytkowników. Nie testowałem ich edycji (co jest teoretycznie możliwe z poziomu dostępnych w kodzie poświadczeń), ponieważ nie miałem zamiaru modyfikować danych w środowisku produkcyjnym. Niewykluczone jednak, że i dla czynności takich jak edycja czy usuwanie nie wprowadzono odpowiednich reguł bezpieczeństwa (poprawnej autoryzacji).

Nie jest to jednak jedyna aplikacja, której dotyka taki problem. Grupa badaczy bezpieczeństwa — mrbruh, xyzeva i logykkzidentyfikowała podobną „podatność” na 900 stronach. Następnie sam mrbruh ujawnił to samo w ponad 11 tysiącach aplikacji mobilnych, które również korzystały z Firebase.

Myśląc o podatnościach w aplikacjach webowych często na myśl przychodzą hasła takie jak SQL Injection, XSS, czy CSRF — a w praktyce problem może leżeć także w konfiguracji wykorzystywanych przez daną platformę usług.

Warto zaznaczyć, że przyczyna nie leży w Firebase, tylko w luźnym podejściu programistów do konfiguracji reguł bezpieczeństwa. Oczywiście tekst niniejszy powstał w celach edukacyjnych i informacyjnych, absolutnie nie zachęcam do pozyskiwania cudzych danych. Zachęcam za to do rozważnej konfiguracji reguł bezpieczeństwa w Firebase, bo to one są najważniejszym mechanizmem takiego „backendu”.

Chcesz więcej takich treści? Zapisz się na newsletter!

Udostępnij:

Dodaj komentarz