· Fundacja Reborn

Jak Reborn Apps chroni Twoje dane - przegląd bezpieczeństwa

Architektura Zero Knowledge, szyfrowanie end-to-end i świadome kompromisy - szczegółowy przegląd tego, jak Reborn Apps chroni Twoje dane.

bezpieczeństwo zero-knowledge szyfrowanie prywatność
Read in English →

Reborn Apps to zestaw aplikacji produktywności (zarządzanie zadaniami i notatki) zbudowanych na architekturze True Zero Knowledge end-to-end encryption. W tym wpisie opisujemy model bezpieczeństwa, projekt kryptograficzny i stosowane mechanizmy ochrony.

Architektura Zero Knowledge

Reborn Apps kieruje się ścisłą zasadą Zero Knowledge: serwer nigdy nie ma dostępu do danych użytkownika w postaci jawnej. Całe szyfrowanie i deszyfrowanie odbywa się wyłącznie na urządzeniu użytkownika.

Co serwer zna

DaneWidocznośćUzasadnienie
Nazwa użytkownikaJawnaWymagana do uwierzytelniania i unikalności
Hash hasłaArgon2idSerwer weryfikuje dane logowania; nigdy nie widzi hasła
Zaszyfrowany klucz głównySzyfrogramPrzechowywany dla dostępu między urządzeniami
Sól kryptograficznaJawnaWymagana do derywacji klucza po stronie klienta
ID rekordów i klucze obceUUIDWymagane dla integralności relacyjnej i synchronizacji
Znaczniki czasuJawneWymagane dla synchronizacji delta i rozwiązywania konfliktów

Czego serwer nigdy nie widzi

  • Wszelkie treści użytkownika: tytuły zadań, opisy, treść notatek, nazwy list/folderów/tagów - przechowywane jako pola *_encrypted (szyfrogram AES-GCM)
  • Metadane behawioralne: status ukończenia, flagi gwiazdki/przypięcia, terminy, przypomnienia, powiązania tagów - spakowane w jedno pole metadata_encrypted na rekord
  • Informacje o urządzeniu: szczegóły sesji są szyfrowane po stronie klienta (device_info_encrypted)
  • Żadnych danych PII poza nazwą użytkownika - brak e-maila, telefonu, danych osobowych

Świadome kompromisy prywatności

Serwer widzi graf strukturalny (które zadania należą do której listy, które notatki do którego folderu), ponieważ potrzebuje tego do operacji kaskadowych, synchronizacji i autoryzacji. Jednak:

  • Powiązania tagów są w pełni ukryte. Relacje N-do-M ujawniałyby graf korelacji, który mógłby odwzorować zachowania użytkownika. ID tagów są szyfrowane wewnątrz metadata_encrypted - na serwerze nie istnieje żadna tabela łącząca.
  • Filtrowanie po tagach działa wyłącznie po stronie klienta, na odszyfrowanym indeksie w pamięci.

Kryptografia

CelAlgorytmSzczegóły
Haszowanie hasłaArgon2id (hash-wasm)m=19456, t=3, p=1
Derywacja kluczaPBKDF2 (Web Crypto API)600 000 iteracji, SHA-256
Szyfrowanie danychAES-GCMKlucze 256-bit, unikalny IV na każdą operację
Owijanie klucza głównegoAES-GCM przez klucz PBKDF2Klucz główny generowany lokalnie, nigdy transmitowany jawnie
Kody odzyskiwaniaSHA-2568 jednorazowych kodów (XXXXX-XXXXX), haszowane przed zapisem
Podpisywanie tokenówHMAC-SHA256 (JWT)Ze wsparciem rotacji sekretu przez podwójną weryfikację

Cykl życia klucza

  1. Rejestracja - losowy klucz główny jest generowany na kliencie, owijany kluczem derywowanym z hasła (PBKDF2 600K), a szyfrogram wysyłany na serwer razem z hashem Argon2id.
  2. Logowanie - serwer zwraca zaszyfrowany klucz główny. Klient derywuje klucz owijający z hasła i odszyfrowuje klucz główny lokalnie.
  3. Sesja - odszyfrowany klucz główny jest przechowywany w IndexedDB (przetrwa restart przeglądarki/PWA) i automatycznie przywracany przy starcie aplikacji. Klucz jest usuwany wyłącznie przy jawnym wylogowaniu. Jest to zgodne z praktyką branżową (Standard Notes, Bitwarden, Proton Mail) - w architekturze Zero Knowledge ochrona przed lokalnym dostępem do urządzenia jest poza zakresem; ZK chroni przed atakami po stronie serwera.
  4. Operacje na danych - wszystkie operacje szyfrowania/deszyfrowania używają klucza głównego przez AES-GCM. Klucz nigdy nie opuszcza urządzenia.

Uwierzytelnianie i bezpieczeństwo sesji

Przepływ uwierzytelniania

  • Uwierzytelnianie nazwą użytkownika i hasłem z weryfikacją Argon2id po stronie serwera
  • Opcjonalne uwierzytelnianie dwuskładnikowe (TOTP)
  • Odzyskiwanie konta przez jednorazowe kody odzyskiwania (celowy brak odzyskiwania przez e-mail/telefon)

Zarządzanie tokenami

  • Krótkotrwałe tokeny dostępu (JWT) z blacklistą JTI przy wylogowaniu
  • Refresh tokeny dostarczane wyłącznie przez ciasteczka httpOnly - nigdy nie udostępniane w treści odpowiedzi ani dostępne z poziomu JavaScript, co eliminuje kradzież tokenów przez XSS
  • Rotacja refresh tokenów z śledzeniem rodzin - ponowne użycie refresh tokenu (wskazujące na kradzież) powoduje unieważnienie całej rodziny
  • Podwójna obsługa sekretów JWT dla rotacji bez przestoju (JWT_SECRET + JWT_SECRET_PREVIOUS)

Ochrona przed brute-force

  • Blokada po nazwie użytkownika: 5 nieudanych prób uruchamia 15-minutową blokadę, obejmującą logowanie i endpointy 2FA
  • Blokada per użytkownik na operacjach wrażliwych: zmiana hasła, wyłączenie 2FA i usunięcie konta wymuszają limity prób z automatyczną blokadą
  • 4-warstwowa ochrona anty-bot przy rejestracji:
    1. Honeypot - ukryte pole odrzucane jeśli wypełnione
    2. Kontrola czasu - zbyt szybkie zgłoszenia są odrzucane
    3. Proof-of-Work (PoW) - klient musi rozwiązać wyzwanie HMAC-SHA256 wydane przez serwer (brak zewnętrznego CAPTCHA, zgodne z zasadą Zero Knowledge - brak śledzenia zewnętrznego)
    4. Weryfikacja sygnatury po stronie serwera - wyzwanie PoW jest podpisane i weryfikowane przed sprawdzeniem rozwiązania
  • Odpowiedzi o stałym czasie przy logowaniu i rejestracji - zapobiegają enumeracji nazw użytkowników przez kanały boczne
  • Walidacja łańcucha proxy: parsowanie X-Forwarded-For od prawej do lewej z konfigurowalnymi zaufanymi proxy (RFC 1918) - ochrona przed IP spoofingiem

Transport i Content Security

Nagłówki bezpieczeństwa HTTP

  • HSTS: Strict-Transport-Security: max-age=31536000; includeSubDomains (tylko produkcja)
  • Content Security Policy: tryb nonce (mode: 'nonce') - eliminuje unsafe-inline z script-src. Źródła skryptów ograniczone do 'self', 'nonce-…' i 'wasm-unsafe-eval' (wymagane dla Argon2id WASM). Dodatkowe dyrektywy: base-uri: 'self', form-action: 'self', object-src: 'none'
  • X-Frame-Options: DENY - zapobiega clickjackingowi
  • X-Content-Type-Options: nosniff - zapobiega sniffingowi typów MIME
  • Ukrywanie tożsamości serwera: server_tokens off w nginx - zapobiega ujawnieniu wersji
  • Limit rozmiaru żądania: maksymalnie 1 MB treści (egzekwowany na poziomie nginx i aplikacji)

Autoryzacja i walidacja danych wejściowych

  • Weryfikacja własności na każdym endpoincie danych - wszystkie operacje CRUD filtrują po user_id z uwierzytelnionego JWT; żaden endpoint nie polega na ID użytkownika dostarczonym przez klienta (IDOR-safe by design, zweryfikowane na wszystkich 47 endpointach API)
  • Middleware uwierzytelniania w hookach serwerowych obu aplikacji waliduje JWT przy każdym chronionym żądaniu
  • Scentralizowana walidacja żądań przez schematy Zod (validateBody()) na wszystkich endpointach danych (zadania, notatki, foldery, tagi, podzadania, subskrypcje push)
  • Sanityzacja HTML z renderowania Markdown przez DOMPurify z ograniczonymi schematami URI

Integralność synchronizacji

  • Middleware idempotentności na endpointach zapisu zapobiega duplikatom podczas ponownych prób synchronizacji offline

Bezpieczeństwo po stronie klienta

Model przechowywania offline-first

  • IndexedDB jest źródłem prawdy - aplikacja działa w pełni offline, synchronizując w tle gdy jest połączenie
  • Osobne bazy IndexedDB na aplikację (Reborn_task_DB, Reborn_notes_DB) - zapobiega korupcji danych między aplikacjami
  • Brak optymistycznych aktualizacji UI - interfejs odzwierciedla dane dopiero po potwierdzonym zapisie
  • Indeksy cieni (odszyfrowane kopie pól sortowania/filtrowania jak is_completed, due_date) istnieją wyłącznie w lokalnym IndexedDB - są usuwane przed synchronizacją z serwerem

Strażnik szyfrowania (Encryption Guard)

Wszystkie dane opuszczające klienta przechodzą przez 3-warstwowy potok walidacji szyfrowania:

  1. Post-encrypt: walidacja formatu szyfrogramu (iv:ciphertext) natychmiast po zaszyfrowaniu
  2. Pre-save: walidacja przed zapisem do IndexedDB
  3. Pre-sync: walidacja przed wysłaniem na serwer

To podejście obrony w głąb gwarantuje, że dane jawne nie mogą zostać przypadkowo zapisane lub przesłane z powodu błędu szyfrowania.

Cross-app SSO

  • Single sign-on między aplikacjami używa współdzielonego localStorage na tym samym originie (za reverse proxy), nie IndexedDB - zachowując izolację baz danych

Łańcuch dostaw i bezpieczeństwo repozytorium

Build i zależności

  • Automatyczne audyty zależności - pnpm audit (skaner podatności w zainstalowanych bibliotekach) uruchamiany na każdym buildzie CI
  • Automatyczne aktualizacje zależności przez Renovate - bot otwierający pull requesty z aktualizacjami bibliotek, obejmujące zarówno rutynowe wersje, jak i łatki bezpieczeństwa (funkcja version-updates w Dependabocie jest celowo wyłączona, by nie generować zduplikowanych PR-ów od dwóch botów)
  • Granice modułów monorepo egzekwowane przez Nx i ESLint - aplikacje mogą importować wyłącznie z pakietów, które jawnie deklarują jako zależności, co zapobiega przypadkowemu sprzęganiu aplikacji ze sobą
  • TypeScript strict mode w całym kodzie
  • Hartowanie produkcyjne Docker: kontenery non-root (su-exec node), brak odsłoniętych portów bazy danych (baza dostępna wyłącznie z wewnętrznej sieci Docker)

Mechanizmy bezpieczeństwa repozytorium GitHub

Ostatnia weryfikacja: 2026-05-12

Poza kodem, który piszemy sami, samo repozytorium na GitHubie jest skonfigurowane tak, że każdy commit i każdy pull request przechodzi przez kilka automatycznych kontroli, zanim będzie można go zmergować. Te zabezpieczenia działają niezależnie od tego, kto otwiera pull request:

  • Statyczna analiza kodu (CodeQL) - narzędzie skanujące kod źródłowy pod kątem znanych wzorców podatności. Uruchamiana przy każdym pushu i pull requeście oraz dodatkowo cyklicznie. Wykrycia o powadze High lub wyższej powodują niepowodzenie testu mergowania - pull request nie może zostać zmergowany dopóki problem nie zostanie rozwiązany. Copilot Autofix (asystent AI proponujący poprawki) jest włączony i sugeruje łatki na wykryte problemy.
  • Alerty Dependabota o podatnościach - powiadomienia o znanych podatnościach (CVE) dla każdej biblioteki śledzonej przez nasze manifesty, ze skonfigurowanym presetem reguł filtrujących szum alertów
  • Alerty Dependabota o malware - osobny kanał dla pakietów oznaczonych jako złośliwe, niezależny od kanału CVE
  • Skanowanie sekretów z ochroną push (push protection) - GitHub skanuje każdy commit pod kątem znanych wzorców wyciekniętych poświadczeń (klucze API, tokeny, hasła) i odrzuca push w momencie wysyłki, a nie tylko flaguje po fakcie
  • Wykrywanie problemów jakościowych kodu - standardowa analiza jakości GitHuba działa równolegle z CodeQL
  • Prywatne zgłaszanie podatności - zewnętrzni badacze mogą zgłaszać znaleziska prywatnym kanałem; zob. SECURITY.md
  • Security advisories - kiedy ma to znaczenie, publikowane są zalecenia bezpieczeństwa, by konsumenci downstream mogli zareagować
  • Ślad audytowy odrzuconych alertów - znaleziska nie mogą być po cichu zamknięte; odrzucenie wymaga zgłoszenia wniosku, który zostaje w logu audytowym

Znane ograniczenia i transparentność

W duchu transparentności - oto świadome kompromisy w obecnej architekturze:

ObszarStatusUwagi
style-src: 'unsafe-inline'ZaakceptowanyWymagany przez generowanie inline stylów SvelteKit. Eksfiltracja przez CSS jest znacznie trudniejsza niż wstrzyknięcie skryptu.
img-src: 'https:' w NotatkachZaakceptowanyWymagany dla zewnętrznych obrazów osadzonych w notatkach Markdown. Aplikacja zadań ogranicza do 'self' data:.
Algorytm JWTHMAC-SHA256Podpisywanie asymetryczne (ES256) planowane, ale jeszcze nie wdrożone. Akceptowalne dla wdrożenia na jednym serwerze.
Blacklista tokenówW pamięciBlacklista tokenów dostępu nie jest trwała między restartami serwera. Ryzyko niskie dzięki krótkiemu czasowi życia tokenu (15 minut). Trwałość oparta na Redis planowana dla wdrożeń wieloinstancyjnych.
Brak odzyskiwania przez e-mailCelowyTo funkcja, nie ograniczenie - zapewnia, że serwer nie przechowuje żadnych danych PII poza nazwą użytkownika. Użytkownicy są odpowiedzialni za bezpieczne przechowywanie kodów odzyskiwania.

Zgłaszanie problemów bezpieczeństwa

Jeśli odkryjesz podatność, prosimy o odpowiedzialne zgłoszenie. Szczegóły znajdziesz w pliku SECURITY.md w repozytorium lub otwórz prywatne zgłoszenie bezpieczeństwa przez GitHub.


Ten wpis opisuje stan bezpieczeństwa na kwiecień 2026. Pełna dokumentacja techniczna jest dostępna w repozytorium projektu.

Aktualizacja 2026-05-12 - dodano sekcję o mechanizmach bezpieczeństwa repozytorium GitHub (statyczna analiza CodeQL, alerty Dependabota, skanowanie sekretów z push protection). Te zabezpieczenia były już aktywne w momencie pierwotnej publikacji, ale nie były tutaj opisane.