# 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.