security upgrade
This commit is contained in:
@@ -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.
|
|
||||||
Reference in New Issue
Block a user