⚠  PROJEKT — niezweryfikowany prawnie. Wymaga akceptacji przed publikacją.

Biała Księga Bezpieczeństwa

Produkt: Exceptao / paraKSCol / CyberZgodność EDU  ·  Ostatnia aktualizacja: 2026-10-23  ·  Odbiorcy: Potencjalni klienci, recenzenci bezpieczeństwa, audytorzy, oficerowie ds. zgodności

Niniejszy dokument jest publicznym podsumowaniem architektury bezpieczeństwa platformy. Każde twierdzenie powinno być weryfikowalne przez dziennik audytowy, endpoint weryfikacji lub aneksy DPA. Ostatnia sekcja („Czego jeszcze nie robimy”) jest uczciwa w kwestii luk.

1. Filozofia bezpieczeństwa

Produkt jest sprzedawany specjalistom ds. bezpieczeństwa, którzy będą go dokładnie analizować przed zaufaniem mu z danymi compliance swojej organizacji. Trzy zasady kierują każdą decyzją projektową:

1. Awaria zamknięta (fail closed) — z jednym celowym wyjątkiem. Jeżeli mechanizm bezpieczeństwa nie może działać, czynność od niego zależna zostaje odrzucona, a awaria ujawniona; mechanizm nie jest pomijany z ostrzeżeniem. Czynność, której wiersza audytu nie da się zapisać, jest wycofywana razem z nim (krótka lista wyjątków, m.in. nieudane logowania i blokady kont, jest zapisywana w logu zamiast odrzucana — w przypadku logowań dlatego, że odrzucenie wycofałoby też licznik blokady). Żądanie lub zadanie w tle, które potrzebuje Vault do odpakowania klucza swojego Dzierżawcy, kończy się błędem, gdy Vault nie odpowiada (§ 7), a wdrożenie nie startuje, jeżeli Vault zwróci puste sekrety. Kopia zapasowa bazy danych, która nie może dotrzeć do jednego z dwóch dostawców przechowywania, trafia do drugiego, a jej uruchomienie kończy się jako nieudane, nie jako udane. Wyjątkiem jest uszkodzony łańcuch audytu — nie zatrzymuje on Usługi. Codzienna weryfikacja kończy się kodem błędu i wysyła e-mail do aktywnych administratorów Dzierżawcy, którego dotyczy, oraz na adres operacyjny Operatora, a przerwanie jest widoczne dla Dzierżawcy pod /api/audit/verify. Odmowa obsługi karałaby klienta za przerwanie, które już nastąpiło, a weryfikacja dała już kiedyś wynik fałszywie pozytywny. Oprogramowanie compliance, które po cichu degraduje się, jest gorsze niż brak oprogramowania.

2. Baza danych jest granicą bezpieczeństwa. Izolacja dzierżawców jest egzekwowana przez Row-Level Security PostgreSQL na poziomie bazy danych, nie przez filtry warstwy aplikacji. Błąd aplikacji, który zapomni filtrować po dzierżawcy, jest nieszkodliwy: baza danych zwraca zero wierszy.

3. Wykrywalność manipulacji zamiast jej zapobiegania. Architektura sprawia, że każda manipulacja jest wykrywalna i identyfikowalna przez łańcuch skrótów, znaczniki kotwic i endpoint weryfikacji.

2. Izolacja dzierżawców

2.1 FORCE ROW LEVEL SECURITY PostgreSQL

Każda tabela powiązana z dzierżawcą ma następujące ustawienia stosowane w czasie migracji:

ALTER TABLE <tabela> ENABLE ROW LEVEL SECURITY;
ALTER TABLE <tabela> FORCE ROW LEVEL SECURITY;

CREATE POLICY tenant_isolation ON <tabela>
  USING (tenant_id::text = current_setting('app.current_tenant_id', true));

FORCE ROW LEVEL SECURITY stosuje politykę nawet do właściciela tabeli. Para GUC (app.current_tenant_id, app.current_org_unit_id) jest ustawiana lokalnie dla transakcji, na początku transakcji każdego żądania:

# apps/tenants/context.py (uproszczone)
with connection.cursor() as cur:
    cur.execute("SELECT set_config('app.current_tenant_id', %s, true)", [str(tenant.id)])
    cur.execute("SET LOCAL ROLE app")

app.current_org_unit_id jest ustawiana w ten sam sposób i tylko dla użytkownika ograniczonego do określonych placówek (§2.3). set_config(…, true) to funkcyjna postać SET LOCAL: wartości GUC wygasną z końcem transakcji. Przed Postgresem nie ma żadnego poolera połączeń, a CONN_MAX_AGE = 0 — każde żądanie otrzymuje własne połączenie, zamykane wraz z końcem żądania. Wartość GUC nie może więc przetrwać poza swoją transakcją z samej konstrukcji: nie istnieje współdzielona sesja, do której mogłaby wyciec.

2.2 Podział ról bazy danych

RolaUprawnieniaUżywana przez
superużytkownik bootstrap (właściciel)Superużytkownik klastra; właściciel wszystkich tabel; DDLMigracje Django, nocny zrzut kopii zapasowej i jednorazowe polecenia operatorskie z jawnym opt-in — nigdy w ścieżce żądania
appSELECT, INSERT, UPDATE, DELETE na większości tabel biznesowych; NOSUPERUSER NOBYPASSRLS, więc ograniczona przez RLS przy każdym zapytaniu. Nie jednolicie: tam, gdzie ścieżka obsługi żądań nigdy nie może usunąć ani nadpisać wiersza, uprawnienie jest odebrane — app nie może usunąć rekordu samego Dzierżawcy i może aktualizować tylko wskazane jego kolumny (od 2026-09-29), a migracja odbierająca takie uprawnienie przerywa wdrożenie, jeśli uprawnienie przetrwaŚrodowisko uruchomieniowe aplikacji (ORM Django, widoki DRF)
audit_writerINSERT i SELECT na audit_log; brak UPDATE, DELETE i TRUNCATESerwis audytowy
superadminBYPASSRLS NOSUPERUSER NOLOGIN; SELECT na wyselekcjonowanej liście tabel, bez INSERT, UPDATE, DELETE i TRUNCATE na jakiejkolwiek tabeli — wyłącznie odczytyOdczyty międzydzierżawcze konsoli operatora i narzędzia łańcucha audytowego
platform_writerBYPASSRLS NOSUPERUSER NOLOGIN; INSERT/UPDATE na wyselekcjonowanej liście tabel; żadnych uprawnień do audit_logZapisy konsoli operatora
iam_definerBYPASSRLS NOSUPERUSER NOINHERIT NOLOGIN; właściciel dwóch funkcji wyszukiwania między Dzierżawcami (SECURITY DEFINER); SELECT na tenant_membership oraz SELECT/UPDATE na poziomie kolumn (trzy/jedna kolumna) w iam_password_reset_tokenNigdy nie jest przyjmowana przez sesję: osiągalna wyłącznie jako właściciel tych dwóch funkcji
app_privRola logowania, bez uprawnień superużytkownika, NOBYPASSRLS; dziedziczy app i może przechodzić (wyłącznie SET ROLE) do superadmin, platform_writer i audit_writer; bez własnych uprawnień poza tymiWorker zadań w tle i konsola operatora — nigdy backend obsługujący żądania
app_roNOLOGIN NOSUPERUSER NOBYPASSRLS; wyłącznie SELECT i tylko na tabelach, które czyta sama rola app; nie należy do żadnej roli; podlega tym samym politykom wierszowym, w tym FORCEOdczyty tylko do odczytu w układzie federacji (nadzorca JST); osiągana wyłącznie przez SET ROLE z app

2.3 Izolacja placówek i jednostek organizacyjnych w obrębie Dzierżawcy

Druga oś izolacji — org_unit_id — rozdziela placówki (Site) jednego Dzierżawcy, np. szkoły w Dzierżawcy JST. Każda placówka ma własną jednostkę organizacyjną, nadawaną przez bazę danych: wyzwalacz na tabeli site (site_org_unit_guard, tenants/0066) tworzy jednostkę przy utworzeniu placówki (przy aktualizacji — tylko dla placówki, która jeszcze jej nie ma), odrzuca jednostkę podaną przez wywołującego i nie pozwala jej później zmienić; jednostka należy wyłącznie do jednej placówki, a od tenants/0070 kolumna jest NOT NULL.

RLS egzekwuje jednostkę na sześciu tabelach: site, exception, control_programs_controlassignment, nis2_control_task, nis2_self_identification i incident, każda z polityką RESTRICTIVE org_unit_scope. Na każdej z nich poza site jednostkę wiersza ustawia baza danych na podstawie jego placówki: wyzwalacz BEFORE INSERT OR UPDATE (set_org_unit_from_site(), a dla przypisań zadań kontrolnych set_org_unit_from_target_site()) nadpisuje org_unit_id przy każdym zapisie i odrzuca placówkę, której zapisujący nie widzi, albo placówkę innego Dzierżawcy, a ograniczenie CHECK odrzuca wiersz, który wskazuje placówkę, ale nie ma jednostki. Wiersz bez placówki — wyjątek, zadanie, samoidentyfikacja lub incydent dotyczący całej organizacji — nie ma jednostki i baza danych z założenia pokazuje go w każdej jednostce. Aplikacja jest tu surowsza dla wyjątków i przypisań wymagań kontrolnych: użytkownik ograniczony do placówek nie widzi ani wyjątków poziomu organizacji, ani przypisań skierowanych do wszystkich placówek.

Kto jest ograniczany. app.current_org_unit_id przechowuje listę jednostek rozdzielonych przecinkami, więc użytkownik odpowiedzialny za dwie szkoły jest ograniczony do obu. Zmienna jest ustawiana dla każdego użytkownika, którego wszystkie role u Dzierżawcy są ograniczone do placówek — role nadane w placówce oraz wiersz roli itso o zasięgu całego Dzierżawcy, który poza Dzierżawcami JST oznacza placówki wskazujące tego użytkownika jako ITSO — na jednostki tych placówek. Członek Dzierżawcy bez roli albo bez placówki, do której ma dostęp (w Dzierżawcy JST wiersz roli itso lub school_director o zasięgu całego Dzierżawcy nie daje żadnej) otrzymuje wartość-strażnika, której nie nosi żadna jednostka, i widzi tylko wiersze poziomu organizacji. Użytkownik z dowolną inną rolą o zasięgu całego Dzierżawcy (tenant_admin, auditor i in., a poza Dzierżawcami JST także school_director o zasięgu całego Dzierżawcy) nie jest zawężany przez tę politykę — celowo.

Najpierw kontrola w kodzie aplikacji, pod nią zabezpieczenie w bazie danych. Odczyty i zapisy wyjątków, Zadań Kontrolnych NIS2, rekordów samoidentyfikacji i incydentów są ograniczane do placówek, w których użytkownik ma uprawnienie właściwe dla danej czynności (sites_granted), a zapis jest sprawdzany w placówce samego wiersza — przy przeniesieniu także w nowej. W Dzierżawcy JST role itso i school_director nadaje się wyłącznie per placówka: wiersz którejkolwiek z nich o zasięgu całego Dzierżawcy nie daje dostępu do żadnej placówki, a wskazanie kogoś jako ITSO placówki niczego mu nie nadaje.

Czego baza danych jeszcze nie rozdziela per placówka: ryzyk, aktywów, stanów zgodności kontroli i ich dowodów oraz powiązań dostawców z placówkami. Ryzyka i aktywa (od 2026-10-21) oraz stany zgodności są ograniczane per placówka wyłącznie w kodzie aplikacji.

Koordynator JST (posiadający rolę na poziomie JST) widzi zagregowany pulpit wszystkich instytucji w ramach JST. Izolację między Dzierżawcami egzekwuje RLS, a nie kod aplikacji; szkoła założona jako osobny Dzierżawca jest więc odizolowana od każdej innej szkoły przez RLS.

3. Uwierzytelnianie

3.1 Konta lokalne

3.2 WebAuthn passkeys

Passkeys WebAuthn (FIDO2) są dostępne na wszystkich kontach. Obsługiwane uwierzytelniające: platformy (Touch ID, Windows Hello, biometria Android) i sprzętowe klucze FIDO2 (YubiKey). Walidacja licznika logowań przy każdej asercji; spadł licznika wyzwala automatyczne unieważnienie i alert.

3.3 SSO OIDC

Konfiguracja per Dzierżawca. Obsługiwane przepływy: wyłącznie Authorization Code z PKCE. Walidacja tokenu: podpis (JWKS), iss, aud, exp, nbf, nonce. Preset „Zaloguj się przez Microsoft” (Entra ID / Azure AD).

3.4 SSO SAML 2.0

Konfiguracja per Dzierżawca przez przesłanie metadanych XML IdP. SSO inicjowane przez SP; SSO inicjowane przez IdP domyślnie wyłączone. Mapowanie atrybutów konfigurowalne (e-mail, imię i nazwisko, rola). Provisioning JIT z mapowaniem odkładań grupowych na role.

3.5 Sesje

Sesje po stronie serwera przechowywane w Redis (nie w bazie danych i nie w pliku cookie, który zawiera wyłącznie identyfikator sesji). Atrybuty cookie: Secure; HttpOnly; SameSite=Lax. Sesja unieważniana po stronie serwera przy wylogowaniu. Sesja kończy się w chwili, która nastąpi najwcześniej: wylogowanie, 15 minut bez żadnego żądania (domyślny limit bezczynności; administratorzy Dzierżawcy mogą go ustawić w zakresie 5–480 minut, w każdym planie) albo 8 godzin od zalogowania — aktywność nie wydłuża tego limitu.

4. Autoryzacja

5. Integralność dziennika audytowego

5.1 Egzekwowanie tylko do dołączania

Rola Postgres audit_writer ma INSERT i SELECT na audit_log oraz brak UPDATE, DELETE i TRUNCATE. Test regresyjny CI sprawdza dokładny zestaw uprawnień przy każdym pull requeście — jest to bramka scalania, a nie kontrola w chwili wdrożenia.

5.2 łańcuch skrótów SHA-256

row_hash_n = sha256( prev_hash_(n-1) || canonical(row_n) )

Gdzie canonical = dwanaście pól składowych, zserializowanych przez Postgres do tekstu i połączonych znakiem \x1f (ASCII unit separator), w kolejności: tenant_id, actor_user_id, actor_ip, actor_user_agent, action, target_type, target_id, before, after, request_id, at, contract_version. timestamptz::text renderowany jest przy TimeZone = 'UTC' i DateStyle = 'ISO, MDY' (ustawionych na stałe w wyzwalaczu), a połączony tekst haszowany jest jako bajty UTF-8. Aby odtworzyć łańcuch zapytaniem SQL lub z danych wyeksportowanych z Postgresa, ustaw wcześniej te same TimeZone, DateStyle oraz client_encoding = 'UTF8'. Wersją listy pól jest contract_version, przechowywana w każdym wierszu i wchodząca do postaci kanonicznej jako jej dwunaste pole.

5.3 Endpoint weryfikacji

GET /api/audit/verify przechodzi przez pełny łańcuch skrótów dla żądającego Dzierżawcy i zwraca:

{
  "ok": true,
  "total_rows": 47291
}

To jest całe ciało odpowiedzi dla nieuszkodzonego łańcucha. Gdy łańcuch jest uszkodzony, endpoint zwraca 422 z ok: false oraz polami broken_at i reason. Do 2026-09-14 przykład pokazywał także first_row_at, last_row_at, last_anchor_at i schema_versions_seen — żadne z tych pól nie istnieje.

5.4 Dzienne migawki kotwic

Zadanie Celery beat uruchamiane codziennie (02:20 UTC) rejestruje bieżący row_hash najnowszego wiersza per Dzierżawca oraz łańcucha płaszczyzny sterowania w tabeli audit_chain_anchor, razem z tokenem znacznika czasu RFC 3161 nad tym skrótem, wystawionym przez zewnętrzny urząd znaczników czasu (TSA) — domyślnie freetsa.org (zob. sekcja 13); drugie zadanie, codziennie o 02:40 UTC, weryfikuje token każdej nowej kotwicy — jego podpis i łańcuch zaufania względem przypiętego certyfikatu głównego TSA — jeden raz, przy pierwszym uruchomieniu po jej utworzeniu (do 2026-09-22 zadanie to działało co tydzień). Wcześniejsze kotwice nie są ponownie sprawdzane według harmonogramu: operator sprawdza je wszystkie na żądanie (verify_anchors --all). Pełne przejście łańcucha odbywa się codziennie. Rola superadmin ma na tej tabeli wyłącznie SELECT.

5.5 Pseudonimizacja przy usuwaniu

Na zweryfikowane żądanie usunięcia (art. 17 RODO) rekord użytkownika otrzymuje znacznik (deleted-<uuid>@tombstone.invalid). Wiersze audytu przechowują actor_user_id, a nie adres e-mail, więc widok wiersza historycznego pokazuje znacznik bez przepisywania jakiegokolwiek wiersza — łańcuch skrótów jest zachowany z samej konstrukcji. Pola actor_ip i actor_user_agent nie są pseudonimizowane i pozostają przez cały okres istnienia konta Dzierżawcy.

Adresy e-mail w wierszach audytu zapisanych przed wdrożeniem produkcyjnym z 2026-10-12. Do wdrożenia produkcyjnego z 2026-10-12 część czynności zapisywała adres e-mail także w samym wierszu audytu — w polach before / after, a przy próbach logowania i resetu hasła w target_id. Wiersze audytu zapisane przed wdrożeniem produkcyjnym z 2026-10-12 (wydanie scalono 2026-10-11, do produkcji trafiło 2026-10-12) przy następujących czynnościach mogą więc zawierać adresy e-mail: auth.login.failed, auth.login.failure, auth.lockout, auth.saml.user_jit_provisioned, iam.password_reset.requested_unknown, iam.password_reset.no_tenant_context, iam.password_reset.suppressed_rate, iam.platform_admin.granted, iam.platform_admin.revoked, superadmin.tenant.create, platform_admin.impersonate.requested, platform_admin.impersonate.approved, platform_admin.impersonate.denied, platform_admin.impersonate.break_glass_declared, platform_admin.impersonate.break_glass_vetoed, platform_admin.impersonate.emergency_declared, platform_admin.impersonate.end, każda platform_admin.impersonate.action.*, platform_admin.tenant.suspend, platform_admin.tenant.restore, platform_admin.audit_search, audit.chain.discontinuity.declared, nis2.control_task.delegated, vendor.assessment.create, vendor.assessment.invite_sent, vendor.assessment.invite_failed, vendor.assessment.reviewers_notified, controls.assignment.notified, controls.due_reminded, controls.overdue_reminded, exception.expiry_reminded, report.quarterly_dispatched, ops.email_path.ok, ops.email_path.failed, tenant.profile.update, email.graph.connection_created, email.graph.connection_renewed, ops.pitr.drill.success, ops.pitr.drill.failed oraz, wyłącznie w dzierżawie demonstracyjnej, report.scheduled.created. Adres może się też znajdować w tekście swobodnym wiersza dowolnej czynności zapisanego przed tą datą — w komunikacie błędu, w opisie błędu od dostawcy tożsamości, w uzasadnieniu lub komentarzu wpisanym przez użytkownika. Wiersze te pozostają przez cały okres istnienia konta Dzierżawcy — w łańcuchu warstwy sterującej platformy przez cały okres istnienia platformy — na tej samej podstawie prawnej co actor_ip: uzasadniony interes w zakresie integralności audytu (art. 6 ust. 1 lit. f RODO). Ich przepisanie zniszczyłoby łańcuch skrótów, dlatego są ujawniane, a nie usuwane.

Od wdrożenia produkcyjnego z 2026-10-12 w treści ani w polu obiektu docelowego wiersza audytu nie jest zapisywany żaden tekst w postaci adresu e-mail. Osoba mająca rekord użytkownika jest identyfikowana wewnętrznym identyfikatorem. Każdy inny adres (kontakt zewnętrznego dostawcy, identyfikator wpisany w formularzu logowania lub resetu hasła) jest zapisywany jako odnośnik kluczowany: hmac-sha256:k0:, a po nim 128 bitów HMAC-SHA-256 pod kluczem platformy k0. Ponadto każdy wiersz przechodzi przez jedną ścieżkę zapisu, która przed zapisaniem zastępuje odnośnikiem każdy pozostały tekst w postaci adresu — w komunikacie błędu, w błędzie dostawcy tożsamości, w tekście wpisanym przez użytkownika. „W postaci adresu” oznacza nazwa@domena.tld lub nazwa@localhost; adres zapisany w inny sposób nie jest rozpoznawany. Do wdrożenia produkcyjnego poprawki z 2026-10-13 to zastępowanie mogło pozostawić fragment: gdy adresy lub domeny były połączone znakiem @ bez niczego pomiędzy (x@a.com@b.org), w wierszu zostawał odnośnik, po nim @ i nazwa domeny (hmac-sha256:k0:…@b.org) — nigdy cały adres. Wiersze zapisane od wdrożenia produkcyjnego z 2026-10-12 do wdrożenia produkcyjnego zawierającego tę poprawkę mogą zawierać taki fragment; są ujawniane, a nie usuwane. Od poprawki adres zachowuje własny odnośnik, a reszta tekstu połączonego znakami @ staje się drugim odnośnikiem. Do wdrożenia produkcyjnego poprawki z 2026-10-14 pozostawała druga luka: adres zawierający łączące znaki diakrytyczne — literę z akcentem zapisaną jako litera podstawowa i osobny znak (Unicode NFD) albo pismo, w którym samogłoski są takimi znakami, np. dewanagari lub tajskie, albo niewidoczny łącznik (ZWNJ/ZWJ) używany w nazwach perskich i indyjskich — nie był rozpoznawany w całości, więc wiersz mógł zachować go, w całości lub w części, jawnym tekstem. Wiersze zapisane przed wdrożeniem produkcyjnym zawierającym tę poprawkę mogą zawierać taki adres; są ujawniane, a nie usuwane. Od tej poprawki znak łączący lub łącznik jest częścią adresu, a zapis złożony i rozłożony tego samego adresu dają jeden odnośnik. Inne dane osobowe w tekście swobodnym — imię i nazwisko lub numer telefonu wpisane w uzasadnienie albo komentarz — są zapisywane tak, jak je wpisano, i pozostają jak reszta wiersza. Równe adresy dają równe odnośniki, więc powtarzane próby wobec jednego identyfikatora nadal dają się powiązać. Odnośnik jest pseudonimem i pozostaje daną osobową: każdy, kto może spowodować zapisanie przez platformę wybranego adresu i odczytać wiersz, albo kto posiada klucz platformy, może potwierdzić odgadnięty adres. Nie obejmuje to ciągu user-agent sesji wykonującej czynność: jest on zapisywany tak, jak go przesłał klient, a niektórzy klienci, zwłaszcza roboty indeksujące, umieszczają w nim adres kontaktowy.

6. Szyfrowanie

6.1 W transmisji

6.2 W spoczynku

6.3 Nagłówki bezpieczeństwa HTTP

Wszystkie odpowiedzi API zawierają nagłówki: Strict-Transport-Security (max-age=31536000; includeSubDomains, bez preload), Content-Security-Policy (`script-src 'self'`, bez `unsafe-inline`; nie oparty na nonce — API nie serwuje skryptów inline), X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Cross-Origin-Opener-Policy: same-origin, Cross-Origin-Resource-Policy: same-origin, Referrer-Policy: strict-origin-when-cross-origin, Permissions-Policy: camera=(), geolocation=(), microphone=(), payment=() (te cztery funkcje są wyłączone dla każdego źródła; pozostałe zachowują ustawienia domyślne przeglądarki). Cross-Origin-Resource-Policy i Permissions-Policy są wysyłane od 2026-10-12. Nagłówek Cross-Origin-Embedder-Policy nie jest wysyłany: dotyczy dokumentów, a API serwuje JSON i pliki do pobrania.

7. Zarządzanie sekretami

8. Architektura sieciowa

9. Kopie zapasowe i odtwarzanie po awarii

10. Bezpieczeństwo łańcucha dostaw

11. Zarządzanie podatnościami

WażnośćWynik CVSSSLA naprawy
Krytyczna≥ 9,024 godziny od potwierdzonej podatności
Wysoka7,0–8,97 dni
Średnia4,0–6,930 dni
Niska< 4,0Następne wydanie mniejsze

Skoordynowane ujawnianie: security@parakscol.pl. .well-known/security.txt opublikowany na wszystkich domenach marki. Zewnętrzny test penetracyjny planowany przed pierwszym płatnym klientem.

12. Reagowanie na incydenty

Udokumentowany podręcznik IR: wykrywanie i triage, izolacja, eliminacja, odtwarzanie, post-mortem i powiadamianie regulacyjne.

Jurysdykcja / prawoPowiadomienie organu nadzorczegoPowiadomienie osób dotkniętych
RODO / UE≤ 72 godziny od powzięcia wiadomości (art. 33)Bez zbędnej zwłoki dla naruszeń wysokiego ryzyka (art. 34)
Polska (KSC / NIS2)24 h wczesne ostrzeżenie; 72 h zgłoszenie; sprawozdanie końcowe w ciągu miesiąca od zgłoszenia 72 h (art. 23 NIS2)Zgodnie z obowiązującym prawem

Obowiązek Operatora powiadamiania Administratora (Dzierżawcy) o naruszeniu: ≤ 72 godziny, zgodnie z DPA §8.

13. Czego jeszcze nie robimy (uczciwa sekcja)

Wierzymy w nienadmiarowe twierdzenia. Poniższa lista jest uczciwa w kwestii luk.

ElementStatusPlan
Certyfikacja SOC 2 Type IIJeszcze nie — zaangażowanie audytorskie nie rozpoczęteArchitektura zaprojektowana pod kątem gotowości SOC 2. Zaangażowanie audytora planowane po fazie GA.
Certyfikacja ISO 27001Jeszcze niePlanowana po SOC 2 Type II.
FedRAMPNie dotyczy w v1Brak klientów federalnych USA w v1.
Zewnętrzny urząd znaczników czasu RFC 3161W użyciu od 2026-09-22 (freetsa.org); komercyjny TSA jeszcze nieobsługiwanyCodzienne zadanie (02:20 UTC) kotwiczy głowę łańcucha audytowego każdego Dzierżawcy oraz głowę łańcucha płaszczyzny sterowania w zewnętrznym urzędzie znaczników czasu RFC 3161 — domyślnie freetsa.org, bezpłatnej publicznej usłudze prowadzonej przez podmiot trzeci — a każdy nowy token jest weryfikowany jeden raz, przy najbliższym codziennym uruchomieniu (02:40 UTC), względem przypiętego certyfikatu głównego TSA; wcześniejsze tokeny są sprawdzane ponownie na żądanie (sekcja 5.4). TSA otrzymuje wyłącznie skrót SHA-256 głowy łańcucha: żadnego wiersza audytu ani danych osobowych, dlatego nie figuruje na liście podwykonawców (/legal/subprocessors), która obejmuje usługi otrzymujące dane osobowe. Token znacznika czasu dowodzi, kiedy głowa łańcucha istniała, a nie kto ją zapisał. Jeszcze niezrealizowany jest komercyjny TSA: weryfikator obsługuje obecnie wyłącznie odpowiedzi freetsa.org.
Cykliczny zewnętrzny test penetracyjnyPierwszy test planowany przed pierwszym płatnym klientemRoczna kadencja po osiągnięciu odpowiednich przychodów.
Program bug bountyJeszcze nieFaza 2/3 — Intigriti lub HackerOne.
Warm-standby DR (RTO ≤ 30 min)Jeszcze nie — obecny RTO ≤ 4 godzinyFaza 3 — wymaga repliki hot-standby i automatycznego przełączania awaryjnego.
Zdalny atest LUKSAutomatyczne otwieranie: wdrożone (LUKS2 + Clevis/Tang NBDE). Zdalny atest: nieoferowany.Wolumin odblokowuje się przy starcie z dwóch niezależnych serwerów Tang — nic nie jest wpisywane i na maszynie nie ma materiału klucza. Awaryjnie służy hasło deponowane offline; zweryfikowane podczas provisioningu przez zablokowanie Tang zaporą i potwierdzenie, że rozruch zatrzymuje się do czasu jego podania. Nie stosujemy zdalnego atestu stanu rozruchu opartego o TPM.

13.1 Klucze Dzierżawców i kryptograficzne usuwanie: obowiązuje od 2026-10-11

Stan na 2026-10-11. Klucze szyfrowania danych (DEK) przypisane do poszczególnych Dzierżawców są używane w obu wdrożeniach produkcyjnych od 2026-10-10 (wydanie R2 w ramach P0-1): każdy aktywny Dzierżawca ma własny klucz, opakowany kluczem przypisanym mu w silniku tranzytowym Vault, a poświadczenie Dzierżawcy zapisane od tego dnia jest szyfrowane tym kluczem. W chwili włączenia kluczy żaden Dzierżawca nie miał zapisanego poświadczenia integracji ani logowania, więc nie było czego migrować. Od 2026-10-11 (wydanie R3b, oba wdrożenia produkcyjne) klucz Dzierżawcy jest jedyną ochroną jego poświadczeń: kopie pod kluczem ogólnoplatformowym, zachowywane do tego dnia, zostały usunięte, a klucz ogólnoplatformowy, który je szyfrował, nie jest już ładowany przez aplikację ani przechowywany w bieżących sekretach Vault. Kryptograficzne usuwanie („crypto-shredding”) poświadczeń Dzierżawców obowiązuje zatem od 2026-10-11, w granicach opisanych poniżej. Sekrety TOTP nie są objęte kluczami Dzierżawców (ograniczenie 5).

Dlaczego nie czekaliśmy 30 dni. Projekt przewidywał, że harmonogram zacznie obowiązywać 30 dni (okres retencji kopii zapasowych) po wydaniu R3, ponieważ kopia zapasowa wykonana przed R3 mogłaby zawierać kopię poświadczenia pod kluczem ogólnoplatformowym. Tu żadna jej nie zawiera, bo takiej kopii nigdy nie utworzono: w chwili włączenia kluczy każda kolumna poświadczeń była pusta, a testy odtworzenia z 2026-10-11, wykonane na ostatnich kopiach zapasowych sprzed R3b, również wykazały puste wszystkie kolumny poświadczeń. Operator uznał więc 2026-10-11 to oczekiwanie za zbędne. Gdyby takie kopie istniały, oczekiwanie obowiązywałoby.

Harmonogram usunięcia — obowiązuje od 2026-10-11. Kryptograficzne usunięcie może zostać zlecone wyłącznie dla zarchiwizowanego Dzierżawcy. Zlecenie jest wstrzymywane na 30-dniowy okres karencji, w którym można je anulować; po jego upływie klucz Dzierżawcy jest niszczony. Zaszyfrowane migawki Vault wykonane przed tą chwilą są przechowywane do 30 dni (VAULT_SNAPSHOT_RETENTION_DAYS, domyślnie 30 — to samo okno co dla kopii zapasowych bazy danych), a odtworzenie migawki w tym oknie przywróciłoby klucz. Usunięcie staje się więc po naszej stronie nieodwracalne około 60 dni od potwierdzonego zlecenia: 30 dni karencji, a następnie do 30 dni przechowywania zaszyfrowanych kopii zapasowych i migawek Vault. Obejmuje zapisane poświadczenia Dzierżawcy (sekrety logowania, poczty i integracji); nie obejmuje sekretów TOTP ani łańcucha audytowego (ograniczenia 2 i 5).

Dziesięć ograniczeń, które publikujemy, aby nikt nie przypisywał kryptograficznemu usuwaniu więcej, niż ono zapewnia:

  1. Kryptograficzne usunięcie nie przetrwa odtworzenia migawki Vault wykonanej przed nim. Odtworzenie takiej migawki przywraca klucz. Ograniczają to 30-dniowa retencja migawek oraz obowiązkowy krok procedury odtwarzania, który ponawia każde usunięcie zarejestrowane po wykonaniu migawki. Właściwe sformułowanie brzmi „w oknie retencji kopii zapasowych”, nigdy „natychmiast i na zawsze”.
  2. Kryptograficzne usunięcie nie usuwa łańcucha audytowego i nie może go usuwać. Łańcuch jest tylko do dopisywania; po usunięciu każdy wiersz audytu pozostaje, a /api/audit/verify nadal go weryfikuje. Zapis o usunięciu przetrwa same dane. Usunięcie danych pseudonimizuje rekord użytkownika, do którego wiersze audytu odwołują się wewnętrznym identyfikatorem; same wiersze audytu nigdy nie są przepisywane (§5.5).
  3. Klucz Dzierżawcy jest nieeksportowalny, co działa w obie strony. W projekcie to dzięki temu skradziona baza danych jest bezużyteczna bez Vault — i z tego samego powodu utrata magazynu Vault wraz ze wszystkimi jego migawkami uczyniłaby chronione dane nieodzyskiwalnymi. Właśnie dla tej drugiej połowy istnieje test odtworzenia migawek z depozytu.
  4. Szyfrowanie wiąże sekret z Dzierżawcą, tabelą i kolumną — nie z chwilą jego zapisu. Szyfrogram unieważnionego poświadczenia odzyskany z okna odtwarzania do punktu w czasie może zostać ponownie zapisany w miejsce nowego przez kogoś z uprawnieniem zapisu do bazy danych i da się go odszyfrować. Ryzyko zaakceptowane, nierozwiązane.
  5. Sekrety TOTP nie są chronione kluczem Dzierżawcy. Konta użytkowników nie należą do jednego Dzierżawcy, dlatego projekt chroni sekrety TOTP jednym kluczem Vault na poziomie platformy: klucz każdego użytkownika jest wyprowadzany z klucza głównego platformy opakowanego kluczem tranzytowym Vault platform-iam (§6.2), więc crypto-shred Dzierżawcy ich nie obejmuje; usunięcie użytkownika usuwa jego sekret.
  6. „Klucze w Vault” to twierdzenie o danych w spoczynku, a nie w czasie działania. Klucz Dzierżawcy w postaci jawnej jest przechowywany w pamięci aplikacji i ponownie używany przez najwyżej 60 sekund, a klucz TOTP platformy — przez cały czas życia procesu. Kto może odczytać pamięć działającego kontenera, może odczytać klucze, jak w każdym projekcie, który cokolwiek odszyfrowuje. Klucze Dzierżawców zmieniają to, że skradziony dysk, kopia zapasowa bazy danych, kopia do odtwarzania do punktu w czasie ani konfiguracja kontenera nie ujawniają żadnego klucza Dzierżawcy.
  7. Awaria Vault staje się awarią wszystkich zaszyfrowanych sekretów połączeń. Od włączenia kluczy Dzierżawców 2026-10-10 awaria Vault czyni szesnaście kolumn poświadczeń w dziewięciu tabelach jednocześnie nieczytelnymi dla wszystkich Dzierżawców — logowanie SSO, poczta Microsoft Graph, Slack, Teams, PagerDuty, ServiceNow, Jira i SIEM — a platforma odmawia działania (logowanie SSO odpowiada komunikatem o chwilowej niedostępności), zamiast sięgać po klucz ogólnoplatformowy. Logowanie hasłem lokalnym i TOTP zaprojektowano tak, aby nie wywoływało Vault przy każdym żądaniu.
  8. Poświadczenie operatora, które może autoryzować kryptograficzne usunięcie, jest pełnym administratorem Vault i nie może być niczym mniej. Ograniczenie jest proceduralne — domyślnie tryb próbny, najpierw wiersz audytu, poświadczenie nieprzechowywane na żadnym serwerze produkcyjnym — a nie kryptograficzne.
  9. Poświadczenie służące do tworzenia kluczy nie może niszczyć ich wersji. Musi móc rotować klucze i ustawiać minimalną wersję odszyfrowania, więc może czasowo uniemożliwić odszyfrowanie danych Dzierżawcy — to awaria, odwracalna jednym zapisem — ale Vault odmawia mu operacji, która trwale usuwa wersje klucza. Zweryfikowano na aktywnej polityce w obu wdrożeniach produkcyjnych 2026-09-22.
  10. Wycofane klucze ogólnoplatformowe przetrwały wyłącznie w zaszyfrowanych migawkach Vault, do około 2026-11-10. Klucz, którym szyfrowano kopie poświadczeń pod kluczem ogólnoplatformowym (IAM_OIDC_KEY), oraz dawny klucz sekretów TOTP (IAM_TOTP_KEY) zniknęły z aplikacji i z bieżących sekretów Vault w obu wdrożeniach (2026-10-11). Tego samego dnia wszystkie starsze wersje magazynu klucz-wartość Vault, które nadal przechowywały którykolwiek z nich, zostały trwale zniszczone, a Operator usunął swoje kopie depozytowe offline obu kluczy. Jedyne kopie, które można przywrócić, znajdują się w zaszyfrowanych nocnych migawkach Vault wykonanych wcześniej i przechowywanych przez najwyżej 30 dni, więc ostatnia z nich wygaśnie około 2026-11-10. Żaden szyfrogram pod kluczem IAM_OIDC_KEY nie istnieje, więc jego kopie niczego nie odszyfrowują. Kopie zapasowe bazy danych wykonane przed migracją klucza TOTP (P0-1, faza 6, 2026-10-11) zawierają sekrety TOTP zaszyfrowane kluczem IAM_TOTP_KEY; odtworzenie migawki Vault wykonanej przed usunięciem klucza pozwoliłoby je ponownie odczytać, dopóki same te kopie zapasowe nie wygasną po 30 dniach.

14. Kontakt

CelKontakt
Ujawnianie luk bezpieczeństwasecurity@parakscol.pl
Prywatność / DPAiod@parakscol.pl
.well-known/security.txtOpublikowany na każdej domenie marki
Klucz publiczny PGPOpublikowany pod /.well-known/pgp-key.asc na wszystkich trzech domenach marek; odcisk 9E3CDE9EB1891E03334081A66AACF8B73B629008