diff --git a/SECURITY_CHANGES.md b/SECURITY_CHANGES.md deleted file mode 100644 index 374bea0..0000000 --- a/SECURITY_CHANGES.md +++ /dev/null @@ -1,75 +0,0 @@ -# RustPad — analiza i lista poprawek - -## Zrealizowane zmiany - -### 1. Kontrola `Origin` dla WebSocketów - -- Żądanie upgrade jest odrzucane kodem `403`, gdy brakuje nagłówka `Origin`, ma on wartość `null`, jest nieprawidłowy albo wskazuje inną domenę. -- Porównywane są schemat i authority z rzeczywistym nagłówkiem `Host`. -- `X-Forwarded-Host` nie jest używany do autoryzacji, aby nie dopuścić do obejścia przez sfałszowany nagłówek. -- Gdy reverse proxy przekazuje `X-Forwarded-Proto`, schemat `Origin` musi być z nim zgodny. -- Kontrola obejmuje WebSockety workspace i pojedynczej notatki. - -### 2. Tokeny konta poza `localStorage` - -- Token konta jest wydawany wyłącznie jako ciasteczko `__Host-rustpad_session` z flagami: - - `HttpOnly` - - `Secure` - - `SameSite=Lax` - - `Path=/` -- Token konta nie jest zwracany w JSON, wysyłany w wiadomości WebSocket ani przyjmowany jako token konta z `Authorization`. -- Frontend usuwa stare wartości `rustpad:auth-token` i `rustpad:access:*` zawierające sekrety. -- `localStorage` zawiera jedynie niesekretne znaczniki stanu. -- Token dostępu po poprawnym haśle zasobu również trafia do ciasteczka `HttpOnly; Secure; SameSite=Lax`. -- Hasło strony publicznej nie jest już zapisywane w `sessionStorage`. - -### 3. Limitowanie prób - -Wprowadzono odpowiedzi `429 Too Many Requests` dla: - -| Operacja | Limit szczegółowy | Limit klienta | Okno | -|---|---:|---:|---:| -| Logowanie | 5 prób na login | 30 prób | 15 min | -| Żądanie resetu hasła | 3 próby na e-mail | 10 prób | 60 min | -| Potwierdzenie resetu | 10 prób na token | 20 prób | 15 min | -| Hasło workspace/notatki | 10 prób na zasób | 50 prób | 15 min | - -- Limity haseł zasobów działają w endpointach HTTP, endpointach wydających token dostępu oraz w obu kanałach WebSocket. -- Poprawna próba zeruje wyłącznie licznik konkretnego loginu, tokenu lub zasobu; nie zeruje limitu globalnego klienta. -- Klucz klienta korzysta z poprawnego adresu IP przekazanego przez zaufane proxy, z bezpiecznym fallbackiem, gdy IP nie jest dostępne. - -### 4. Bezpieczne serwowanie plików - -- Obrazy rastrowe PNG, JPEG, GIF, WebP, AVIF, BMP i ICO nadal mogą być wyświetlane inline. -- HTML, SVG, XML, PDF oraz wszystkie pozostałe typy są zwracane jako `application/octet-stream` z `Content-Disposition: attachment`. -- Dodano `X-Content-Type-Options: nosniff` oraz restrykcyjny `Content-Security-Policy`. -- Nazwa pliku w `Content-Disposition` jest sanityzowana. - -### 5. Upload tylko dla zalogowanych kont - -- Serwer wymaga ważnej sesji konta przed przyjęciem multipart uploadu do workspace lub notatki. -- Gość korzystający z publicznego zasobu, hasła zasobu albo linku udostępnienia nie może wgrywać plików. -- Frontend wcześniej blokuje przycisk i wyświetla komunikat, ale kontrola serwerowa pozostaje źródłem prawdy. - -### 6. Widok mobilny - -- Opcje edytora mobilnego używają tego samego stylu checkboxów co konfiguracja strony. -- Usunięto zduplikowane i nieużywane reguły CSS pozostałe po poprzedniej implementacji. - -## Kontrola wykonania - -- Sprawdzenie składni wszystkich plików JavaScript: zaliczone. -- Sprawdzenie pozostałości sekretów zapisywanych przez frontend: zaliczone. -- Sprawdzenie obecności zabezpieczeń cookies, WebSocketów, uploadu, plików i odpowiedzi `429`: zaliczone. -- Sprawdzenie nawiasów i zgodności zmienionych wywołań Rust: zaliczone statycznie. -- Sprawdzenie końcowego diffu pod kątem białych znaków: zaliczone. -- Kompilacja, `cargo fmt`, `cargo check` i testy Rust nie zostały uruchomione, ponieważ środowisko nie zawiera toolchainu Rust. - -## Lista przed wdrożeniem - -1. Wdrożyć wyłącznie przez HTTPS — ciasteczka z flagą `Secure` nie będą działać przez zwykły HTTP. -2. Reverse proxy musi zachowywać prawidłowy `Host` oraz nadpisywać, a nie ufać nagłówkom klienta: `CF-Connecting-IP`, `X-Real-IP`, `X-Forwarded-For` i `X-Forwarded-Proto`. -3. Przy wdrożeniu unieważnić istniejące sesje kont i istniejące tokeny dostępu do zasobów. Sekret wcześniej zapisany w przeglądarce mógł zostać skopiowany przed aktualizacją. -4. Dla wielu instancji aplikacji przenieść limiter do współdzielonego magazynu, np. Redis. Obecny limiter działa w pamięci pojedynczego procesu i zeruje się po restarcie. -5. W CI uruchomić co najmniej: `cargo fmt --check`, `cargo check`, `cargo test` oraz testy integracyjne logowania, uploadu, plików i WebSocketów za docelowym reverse proxy. -6. Zweryfikować ustawienia domen i subdomen. Jeżeli niezaufana treść może działać na subdomenie tej samej witryny, warto dodatkowo wdrożyć tokeny CSRF dla operacji modyfikujących dane.