Bezpieczeństwo
Szyfrowanie zero-knowledge
Dane planu są szyfrowane po stronie klienta (AES-GCM). Klucz szyfrujący wyprowadzamy z hasła użytkownika (PBKDF2), a w planie Duo udostępniamy go między domownikami przez wymianę kluczy (ECDH). Klucz nie trafia na serwer w żadnej postaci. Nie piszemy własnej kryptografii — korzystamy z natywnego Web Crypto API przeglądarki.
Skutek: nawet z pełnym dostępem do bazy nie da się odczytać danych użytkownika bez jego hasła lub kodu odzyskiwania.
Co jest na Twoim urządzeniu
Odblokowany klucz trzymamy w pamięci karty (sessionStorage) — dzięki temu
odświeżenie strony nie pyta o hasło; znika po zamknięciu karty i przy
wylogowaniu. Tam samo, i tylko do potwierdzenia „Zapisałem(am) kod", trzyma się
kod odzyskiwania nowego konta — żeby przeładowanie strony go nie zgubiło
(klucze już istnieją, a drugi raz kodu nie da się odtworzyć). Odszyfrowany plan jest zapisany lokalnie w przeglądarce
(localStorage), bo aplikacja działa też offline — tę kopię czyścimy przy
wylogowaniu i przy zmianie konta. Oznacza to, że ktoś z dostępem do Twojego
odblokowanego urządzenia widzi Twoje dane — to granica szyfrowania E2E, nie
jego luka. Chroń urządzenie tak, jak aplikację bankową.
Potwierdzanie dostępu domownika (pinning kluczy)
Klucz do planu nie jest nadawany automatycznie każdemu, kto dołączy kodem zaproszenia. Osoba, która już ma dostęp, widzi prośbę „Potwierdź dostęp" z odciskiem klucza nowej osoby (skrót SHA-256 jej klucza publicznego); ten sam odcisk nowa osoba widzi u siebie na ekranie oczekiwania. Po potwierdzeniu odcisk zostaje zapamiętany w zaszyfrowanym planie, więc nikt z dostępem do bazy nie może go podmienić ani dopisać sobie „zaufania". Jeśli klucz znanej osoby kiedyś się zmieni, aplikacja zablokuje dostęp i pokaże ostrzeżenie; bezpieczna ścieżka to odpięcie i ponowne zaproszenie. Odpięcie partnera rotuje klucz planu i kasuje zapamiętany odcisk.
Domownik sprzed wprowadzenia pinningu, który ma już zapieczętowany klucz planu, nie dostaje prośby o potwierdzenie — dostęp już ma. Jego odcisk nie jest jednak zapamiętywany automatycznie: o istnieniu takiego wiersza decyduje baza, więc „zaufanie" wywnioskowane z bazy otwierałoby drogę do ataku (operator dopisuje fałszywy wiersz, potem go kasuje, a aplikacja sama pieczętuje mu klucz). Każde nowe pieczętowanie klucza planu nadal wymaga jawnego kliknięcia.
Dodatkowo aplikacja nie przyjmie planu zapisanego jawnie po włączeniu szyfrowania i nie zacznie od zera, gdy pobranie z chmury się nie uda — w obu przypadkach zobaczysz ekran „Nie udało się pobrać planu", a lokalna kopia i klucz pozostają bez zmian.
Kontrola dostępu (Row Level Security)
W trybie chmurowym dostęp do danych egzekwuje Postgres RLS: zapytania widzą i
modyfikują wyłącznie gospodarstwo, którego jesteś członkiem. Operacje takie jak
tworzenie/dołączanie/opuszczanie gospodarstwa czy zapis stanu przechodzą przez
funkcje security definer, które w kontrolowany sposób sprawdzają uprawnienia.
RLS działa jako dodatkowa warstwa (defense-in-depth) na szyfrogramie — ogranicza,
kto w ogóle pobierze rekord, choć i tak jest on nieczytelny bez klucza.
Klucze i sekrety
- W przeglądarce używany jest wyłącznie publiczny klucz
anon, chroniony przez RLS. - Klucze wrażliwe (np. service-role, klucze dostawcy płatności) nigdy nie trafiają do frontendu — żyją tylko po stronie serwera (zmienne środowiskowe).
- Brak sekretów w repozytorium.
Walidacja danych
Każdy formularz i każdy odczyt ze stanu przechodzi przez schematy Zod — nieprawidłowe lub złośliwe dane nie trafiają do aplikacji. Teksty są oczyszczane ze znaków kontrolnych.
Hasła
Hasła nie są przechowywane jawnie — Supabase trzyma jedynie jednokierunkowy hash (bcrypt). Nie da się ich odczytać; można je tylko zresetować lub nadpisać.
Operacje destrukcyjne
Reset danych i usunięcie konta wymagają potwierdzenia hasłem, aby zapobiec przypadkowej utracie danych.
Transport i nagłówki
Komunikacja po HTTPS, z nagłówkami bezpieczeństwa (m.in. CSP).