Anonimowość i Bezpieczeństwo

Dokumentacja techniczna wyjaśniająca jak System Sygnalista chroni Twoją tożsamość i zapewnia bezpieczeństwo zgłoszeń

Szyfrowanie SSL/TLS Ochrona CSRF Bezpieczna baza Pełna anonimowość

System Sygnalista został zaprojektowany z myślą o pełnej ochronie tożsamości zgłaszających. Poniżej znajdziesz szczegółową dokumentację techniczną wyjaśniającą jak to działa.

Jak działa anonimowość?

System Sygnalista oferuje dwa tryby składania zgłoszeń: anonimowy i jawny. Wybór należy do Ciebie i możesz go zmienić w dowolnym momencie przed wysłaniem zgłoszenia.

Zgłoszenie anonimowe

Twoja tożsamość pozostaje całkowicie nieznana. System nie wymaga żadnych danych osobowych, a jedynie treść zgłoszenia.

Zgłoszenie jawne

Dobrowolnie ujawniasz swoją tożsamość, co umożliwia kontakt zwrotny i potencjalnie szybsze rozpatrzenie sprawy.

Jak to działa w kodzie?

Decyzja o anonimowości jest zapisana w zmiennej is_anonymous. Gdy wybierasz tryb anonimowy, pola z danymi osobowymi (reporter_name, reporter_email itd.) są automatycznie ustawiane na NULL w bazie danych.

api/submit.php - linia 35, 109-113
// Sprawdzenie czy zgłoszenie jest anonimowe
$isAnonymous = ($_POST['is_anonymous'] ?? '1') === '1';

// Przy zapisie do bazy - dane osobowe tylko gdy NIE anonimowe
$stmt->execute([
    // ...
    $isAnonymous ? 1 : 0,                    // is_anonymous
    $isAnonymous ? null : $_POST['reporter_name'],  // NULL gdy anonimowe
    // pozostałe dane osobowe również NULL gdy anonimowe
]);

Co zapisujemy w bazie danych?

Poniższa tabela pokazuje dokładnie jakie dane są zapisywane w zależności od trybu zgłoszenia:

Pole w bazie Zgłoszenie anonimowe Zgłoszenie jawne
report_id (numer zgłoszenia) ✓ Zapisywane ✓ Zapisywane
category_ids (kategorie) ✓ Zapisywane ✓ Zapisywane
category_note (opis) ✓ Zapisywane ✓ Zapisywane
is_anonymous (flaga) ✓ = 1 (true) ✓ = 0 (false)
reporter_name (imię/nazwisko) ✗ NULL ✓ Zapisywane
reporter_email (e-mail) ○ Opcjonalnie* ✓ Zapisywane
reporter_position (stanowisko) ✗ NULL ○ Opcjonalnie
reporter_phone (telefon) ✗ NULL ○ Opcjonalnie
created_at (data zgłoszenia) ✓ Zapisywane ✓ Zapisywane

* E-mail w trybie anonimowym jest zapisywany tylko jeśli zaznaczysz opcję "Chcę otrzymać potwierdzenie e-mail". Nie jest on jednak powiązany z Twoją tożsamością.

database/schema.sql - tabela reports
CREATE TABLE reports (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    report_id VARCHAR(32) NOT NULL UNIQUE,  -- np. SYG-20260204-A1B2C3D4
    category_ids JSON NOT NULL,
    category_note TEXT NOT NULL,
    is_anonymous TINYINT(1) DEFAULT 1,      -- domyślnie anonimowe!
    reporter_name VARCHAR(255) DEFAULT NULL, -- NULL gdy anonimowe
    reporter_email VARCHAR(255) DEFAULT NULL,
    -- ... pozostałe pola
);

Czego NIE zapisujemy w trybie anonimowym?

Dla Twojego bezpieczeństwa, następujące dane NIGDY nie są zapisywane w zgłoszeniu anonimowym:

  • Imię i nazwisko – pole reporter_name zawsze NULL
  • Stanowisko / dział – pole reporter_position zawsze NULL
  • Numer telefonu – pole reporter_phone zawsze NULL
  • Cookies identyfikujące – nie używamy śledzących cookies
  • Fingerprint przeglądarki – nie zbieramy unikalnych cech przeglądarki
  • Historia przeglądania – nie mamy dostępu do Twojej historii
Ważna informacja o adresie IP

Adres IP jest technicznie zapisywany przez serwer WWW w logach dostępu. Jest to standardowe działanie każdego serwera. Jednak nigdy nie łączymy adresu IP z treścią zgłoszenia w celu identyfikacji osoby zgłaszającej. Logi serwera są automatycznie usuwane po 30 dniach.

Generowanie numeru zgłoszenia

Każde zgłoszenie otrzymuje unikalny, kryptograficznie bezpieczny numer. Numer ten nie zawiera żadnych informacji pozwalających zidentyfikować osobę zgłaszającą.

Format numeru zgłoszenia

Przykład: SYG-20260204-A1B2C3D4
SYG - stały prefiks
20260204 - data (RRRRMMDD)
A1B2C3D4 - losowy ciąg (8 znaków hex)

config/database.php - linia 35-37
function generateReportId(): string {
    return 'SYG-' . date('Ymd') . '-' . strtoupper(bin2hex(random_bytes(4)));
}

Funkcja random_bytes(4) generuje 4 bajty (32 bity) losowych danych używając kryptograficznie bezpiecznego generatora liczb losowych (CSPRNG). Daje to 4.294.967.296 możliwych kombinacji (2^32).

  • Nieprzewidywalność – nie można zgadnąć numeru kolejnego zgłoszenia
  • Unikalność – kolizje są praktycznie niemożliwe
  • Brak sekwencji – numery nie zdradzają kolejności zgłoszeń

Tokeny bezpieczeństwa

System wykorzystuje dwa mechanizmy ochrony przed atakami:

1. Token CSRF (Cross-Site Request Forgery)

Chroni przed atakami polegającymi na wymuszeniu wykonania akcji przez zalogowanego użytkownika.

/ - linia 6-7
if (empty($_SESSION['csrf_token'])) {
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));  // 256 bitów entropii
}

Token jest generowany przy pierwszym wejściu na stronę i weryfikowany przy wysyłce formularza:

api/submit.php - linia 17-19
if (empty($_POST['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) {
    $errors['csrf_token'] = 'Nieprawidłowy token bezpieczeństwa';
}

2. CAPTCHA matematyczna

Prosta weryfikacja "człowiek vs. robot" bez zewnętrznych usług (jak Google reCAPTCHA).

/ - linia 9-12
$a = random_int(1, 10);
$b = random_int(1, 10);
$_SESSION['captcha_answer'] = (string)($a + $b);  // Odpowiedź w sesji
$captchaQuestion = "{$a} + {$b}";               // Pytanie dla użytkownika
Dlaczego własna CAPTCHA?

Zewnętrzne usługi CAPTCHA (jak Google reCAPTCHA) mogą śledzić użytkowników i zbierać dane. Nasza prosta matematyczna CAPTCHA nie wymaga żadnych zewnętrznych połączeń, co zwiększa prywatność.

Autozapis i szkice zgłoszeń

System automatycznie zapisuje postęp wypełniania formularza, abyś mógł wrócić do niego później. Oto jak to działa:

Generowanie tokena szkicu

config/database.php - linia 31-33
function generateToken(): string {
    return bin2hex(random_bytes(32));  // 64-znakowy token hex (256 bitów)
}

Token jest zapisywany w localStorage przeglądarki (nie w cookies!) i służy wyłącznie do odzyskania szkicu.

Co zawiera szkic?

Pole Opis
draft_token 64-znakowy losowy identyfikator
current_step Aktualny krok formularza (1-6)
selected_categories Wybrane kategorie (JSON)
form_data Wypełnione pola formularza (JSON)
is_anonymous Czy zgłoszenie anonimowe
Automatyczne usuwanie szkiców

Szkice są automatycznie usuwane po 7 dniach nieaktywności. Odbywa się to przy każdym zapytaniu do API szkiców:

api/draft.php - linia 13
$db->exec("DELETE FROM report_drafts WHERE updated_at < DATE_SUB(NOW(), INTERVAL 7 DAY)");

Szyfrowanie i bezpieczna transmisja

SSL/TLS (HTTPS)

Całe połączenie między Twoją przeglądarką a serwerem jest szyfrowane certyfikatem SSL. Nikt nie może podsłuchać transmisji.

PDO Prepared Statements

Wszystkie zapytania do bazy danych używają parametryzowanych zapytań, co chroni przed SQL Injection.

Sanityzacja danych

Wszystkie dane wejściowe są walidowane i sanityzowane przed zapisem do bazy i wyświetleniem.

CSPRNG

Do generowania tokenów używamy kryptograficznie bezpiecznego generatora liczb losowych (random_bytes).

config/database.php - PDO z bezpiecznymi opcjami
$options = [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES => false,  // Prawdziwe prepared statements
];
$pdo = new PDO($dsn, DB_USER, DB_PASS, $options);

Przepływ danych przy zgłoszeniu anonimowym

Oto krok po kroku co dzieje się z Twoimi danymi podczas składania anonimowego zgłoszenia:

1

Wejście na stronę

Generowany jest token CSRF i pytanie CAPTCHA. Zapisywane w sesji PHP (nie w bazie danych).

2

Wypełnianie formularza

Autozapis co 30 sekund. Szkic trafia do tabeli report_drafts z losowym tokenem.

3

Wybór "Anonimowe"

Flaga is_anonymous = 1 oznacza, że pola danych osobowych będą NULL.

4

Wysłanie zgłoszenia

Weryfikacja CSRF i CAPTCHA. Wygenerowanie numeru SYG-XXXXXXXX-XXXXXXXX.

5

Zapis do bazy

Zgłoszenie trafia do tabeli reports. Pola osobowe = NULL. Szkic jest usuwany.

6

Powiadomienie HR

E-mail do działu HR zawiera TYLKO treść zgłoszenia, bez żadnych danych identyfikujących.

Zgodność z przepisami

System Sygnalista został zaprojektowany zgodnie z:

  • Dyrektywa UE 2019/1937 – o ochronie osób zgłaszających naruszenia prawa Unii
  • Ustawa z dnia 14 czerwca 2024 r. o ochronie sygnalistów – polska implementacja dyrektywy
  • RODO – Rozporządzenie o ochronie danych osobowych
  • Kodeks pracy – w zakresie ochrony pracowników
Gwarancje prawne dla sygnalistów

Zgodnie z przepisami, sygnalista korzystający z wewnętrznego kanału zgłoszeń jest chroniony przed:

  • Rozwiązaniem umowy o pracę
  • Obniżeniem wynagrodzenia
  • Wstrzymaniem awansu
  • Zmianą miejsca pracy
  • Jakimikolwiek działaniami odwetowymi

Okres przechowywania danych

Zgodnie z art. 29 ust. 5 Ustawy o ochronie sygnalistów, dane są przechowywane przez 5 lat od daty zakończenia postępowania, po czym są usuwane.