BusiKM — Dokumentacja bezpieczeństwa
1. Uwierzytelnianie JWT
Przepływ logowania
System BusiKM wykorzystuje dwutokenowy mechanizm JWT (JSON Web Token) oparty na bibliotece djangorestframework-simplejwt:
Użytkownik Backend Redis (DB2)
| | |
|-- POST /api/auth/login ->| |
| |-- Weryfikacja danych |
| |-- Generowanie tokenów |
|<-- access + refresh -----| |
| | |
|-- request + access ----->| |
| |-- Walidacja tokenu |
|<-- odpowiedź ------------| |
| | |
|-- POST /api/auth/refresh | |
| + refresh token ------>| |
| |-- Rotacja tokenu ------->|-- Blacklist starego
|<-- nowy access + refresh | |
Parametry tokenów
| Parametr | Wartość | Opis |
| Access token TTL | 15 minut | Krótki czas życia minimalizuje ryzyko przejęcia |
| Refresh token TTL | 7 dni | Umożliwia dłuższe sesje bez ponownego logowania |
| Algorytm | HS256 | HMAC z kluczem symetrycznym (SECRET_KEY) |
| Rotacja refresh | Włączona | Każde odświeżenie generuje nowy refresh token |
| Blacklisting | Redis DB2 | Unieważnione tokeny przechowywane w Redis |
Rotacja tokenów
Po każdym użyciu refresh tokena:
- Stary refresh token trafia na blacklistę w Redis DB2.
- Generowany jest nowy pair access + refresh.
- Klient otrzymuje oba nowe tokeny.
Zapobiega to ponownemu użyciu skradzionego refresh tokena.
Mechanizm token_version — wylogowanie ze wszystkich urządzeń
Każdy użytkownik posiada pole token_version w modelu. Przy operacji „wyloguj ze wszystkich urządzeń":
token_version jest inkrementowany. - Wszystkie istniejące tokeny zawierają starą wersję.
- Middleware porównuje
token_version z tokenu z aktualnym w bazie. - Niezgodność wersji powoduje odrzucenie tokenu (HTTP 401).
2. Kontrola dostępu oparta na rolach (RBAC)
Role systemowe
| Rola | Identyfikator | Opis |
| Kierowca | driver | Rejestracja tras, podgląd własnych danych |
| Właściciel firmy | owner | Pełny dostęp do danych firmy, zarządzanie użytkownikami |
| Księgowy | accountant | Dostęp do danych finansowych i raportów firmy |
| Biuro rachunkowe | accounting_firm | Obsługa wielu firm klientów z różnym poziomem dostępu |
Klasy uprawnień (Permission Classes)
| Klasa | Opis |
IsDriver | Dostęp tylko dla kierowców |
IsOwner | Dostęp tylko dla właścicieli firm |
IsAccountant | Dostęp tylko dla księgowych |
IsAccountingFirm | Dostęp tylko dla biur rachunkowych |
IsDriverOrOwner | Dostęp dla kierowców i właścicieli |
IsOwnerOrAccountantOrAF | Dostęp dla właścicieli, księgowych i biur rachunkowych |
IsAccountantOrAF | Dostęp dla księgowych i biur rachunkowych |
ActionPermissionMixin
class TripViewSet(ActionPermissionMixin, viewsets.ModelViewSet):
action_permissions = {
'list': [IsAuthenticated, IsDriverOrOwner],
'create': [IsAuthenticated, IsDriver],
'retrieve': [IsAuthenticated, IsOwnTrip],
'export': [IsAuthenticated, IsOwnerOrAccountantOrAF],
}
3. Izolacja danych firmowych
CompanyScopedMixin
class CompanyScopedMixin:
def get_queryset(self):
return super().get_queryset().filter(
company_id=self.request.user.company_id
)
Zasada 404 zamiast 403
Gdy użytkownik próbuje uzyskać dostęp do obiektu należącego do innej firmy, system zwraca HTTP 404 (Not Found), a nie 403 (Forbidden). Dzięki temu:
- Atakujący nie wie, czy obiekt istnieje.
- Nie można enumerować zasobów innych firm.
- Brak wycieku informacji o strukturze danych.
Pokrycie testami
Izolacja firmowa jest zabezpieczona ponad 50 testami weryfikującymi brak dostępu do obiektów cudzej firmy, poprawność filtrowania list, zwracanie 404 i brak możliwości modyfikacji danych innej firmy.
4. Uprawnienia na poziomie obiektu
| Klasa | Zastosowanie |
IsOwnTrip | Kierowca widzi i edytuje tylko swoje trasy |
IsOwnVehicle | Kierowca widzi tylko pojazdy przypisane do niego |
IsOwnCompany | Użytkownik może modyfikować tylko dane swojej firmy |
class IsOwnTrip(BasePermission):
def has_object_permission(self, request, view, obj):
if request.user.role == 'driver':
return obj.driver_id == request.user.id
return True # Właściciele widzą wszystkie trasy firmy
5. Izolacja multi-tenant dla biur rachunkowych
Architektura
Biuro rachunkowe
|
|-- Klient A (full access)
|-- Klient B (read_only)
|-- Klient C (reports_only)
Poziomy dostępu
| Poziom | Opis | Dozwolone operacje |
full | Pełny dostęp | Odczyt, zapis, edycja, eksport, raporty |
read_only | Tylko odczyt | Przeglądanie danych, bez modyfikacji |
reports_only | Tylko raporty | Generowanie i pobieranie raportów |
6. Ograniczanie liczby zapytań (Rate Limiting)
Warstwa globalna (Middleware)
| Typ użytkownika | Limit | Okno czasowe |
| Anonimowy | 100 zapytań | 1 minuta |
| Uwierzytelniony | 300 zapytań | 1 minuta |
Implementacja oparta na algorytmie sliding window w Redis.
Warstwa DRF (Throttle Classes)
| Klasa throttle | Limit | Zakres | Zastosowanie |
AnonRateThrottle | 30/min | Per IP | Endpointy publiczne |
UserRateThrottle | 120/min | Per user | Endpointy uwierzytelnione |
LoginRateThrottle | 5/min | Per email | Logowanie (ochrona brute force) |
GPSUploadThrottle | 10/min | Per user | Upload danych GPS |
ExportThrottle | 5/min | Per user | Generowanie eksportów/raportów |
7. Ochrona przed atakami brute force
Próba logowania
|
|-- Sprawdzenie limitu per IP -----> Przekroczony? -> 429
|
|-- Sprawdzenie limitu per email --> Przekroczony? -> 429
|
|-- Weryfikacja danych logowania
| |
| |-- Niepoprawne -> Log + inkrementacja liczników
| |
| |-- Poprawne -> Reset liczników + wydanie tokenów
8. Zgodność z OWASP Top 10
| ID | Kategoria | Status | Implementacja |
| A01 | Broken Access Control | Zabezpieczone | RBAC, CompanyScopedMixin, uprawnienia obiektowe, 50+ testów izolacji, 404 zamiast 403 |
| A02 | Cryptographic Failures | Zabezpieczone | JWT z HS256, hasła hashowane (bcrypt/argon2), HTTPS everywhere, brak PII w logach |
| A03 | Injection | Zabezpieczone | Django ORM (parametryzowane zapytania), walidacja serializatorów DRF, brak raw SQL |
| A04 | Insecure Design | Zabezpieczone | Wielowarstwowa architektura bezpieczeństwa, zasada najmniejszych uprawnień, code review |
| A05 | Security Misconfiguration | Zabezpieczone | DEBUG=False w produkcji, usunięty domyślny SECRET_KEY, CSP headers, HSTS |
| A06 | Vulnerable Components | Zabezpieczone | pip-audit, npm audit, Dependabot, bandit SAST, regularne aktualizacje |
| A07 | Identification and Authentication Failures | Zabezpieczone | JWT z rotacją, brute force protection, token_version, blacklisting |
| A08 | Software and Data Integrity Failures | Zabezpieczone | Podpisane tokeny JWT, walidacja MIME plików, CI/CD z kontrolą integralności |
| A09 | Security Logging and Monitoring Failures | Zabezpieczone | Logowanie nieudanych logowań, rate limit events, structured logging |
| A10 | Server-Side Request Forgery (SSRF) | Zabezpieczone | Brak endpointów pobierających URL od użytkownika, walidacja uploadu plików |
9. Bezpieczeństwo transportu
HTTPS
- Cała komunikacja odbywa się wyłącznie przez HTTPS.
- Konfiguracja
SECURE_SSL_REDIRECT = True wymusza przekierowanie HTTP -> HTTPS.
HSTS
SECURE_HSTS_SECONDS = 31536000 # 1 rok
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
Bezpieczne ciasteczka
SESSION_COOKIE_SECURE = True # Tylko przez HTTPS
CSRF_COOKIE_SECURE = True # Tylko przez HTTPS
SESSION_COOKIE_HTTPONLY = True # Niedostępne z JavaScript
10. Polityka CORS
| Środowisko | Dozwolone origin |
| Development | http://localhost:3000, http://localhost:8081 |
| Staging | https://staging.busikm.pl |
| Produkcja | https://app.busikm.pl, https://busikm.pl |
11. Bezpieczeństwo uploadu plików
Walidacja wielopoziomowa
- Walidacja rozszerzenia — dozwolone tylko określone rozszerzenia plików.
- Walidacja MIME type — sprawdzenie nagłówka Content-Type.
- Walidacja magic bytes — odczyt pierwszych bajtów pliku w celu weryfikacji rzeczywistego formatu.
- Limit rozmiaru — maksymalnie 10–15 MB w zależności od typu pliku.
Ochrona przed XSS przez pliki
Wszystkie pliki serwowane z nagłówkiem Content-Disposition: attachment.
Przechowywanie plików
- Pliki przechowywane w prywatnym bucket S3 (brak publicznego dostępu).
- Dostęp do plików wyłącznie przez presigned URLs z ograniczonym czasem ważności.
12. Zarządzanie sekretami
| Środowisko | Mechanizm | Opis |
| Backend (dev/prod) | Plik .env | Nigdy nie commitowany do repozytorium (w .gitignore) |
| Aplikacja mobilna | EAS Secrets | Szyfrowane zmienne środowiskowe Expo Application Services |
| CI/CD | GitHub Secrets | Szyfrowane zmienne dostępne w GitHub Actions |
| Produkcja | Zmienne środowiskowe | Ustawiane bezpośrednio na platformie hostingowej |
13. Bezpieczeństwo warstwy webowej
Ciasteczka httpOnly dla JWT
- Token niedostępny z poziomu JavaScript (ochrona przed XSS).
- Automatycznie dołączany do zapytań przez przeglądarkę.
- Flagi
Secure i SameSite=Lax.
Wzorzec BFF (Backend for Frontend)
- Klient webowy komunikuje się z BFF na tej samej domenie.
- BFF zarządza tokenami JWT (przechowuje w httpOnly cookies).
- BFF przekazuje zapytania do API, dołączając token w nagłówku Authorization.
- Eliminuje to konieczność przechowywania tokenów w localStorage/sessionStorage.
Nagłówki bezpieczeństwa
# Content Security Policy
CSP_DEFAULT_SRC = ("'self'",)
CSP_SCRIPT_SRC = ("'self'",)
CSP_STYLE_SRC = ("'self'", "'unsafe-inline'")
CSP_IMG_SRC = ("'self'", "data:", "https:")
# Pozostałe nagłówki
X_FRAME_OPTIONS = 'DENY' # Ochrona przed clickjacking
SECURE_CONTENT_TYPE_NOSNIFF = True # Blokada MIME sniffing
SECURE_BROWSER_XSS_FILTER = True # Filtr XSS przeglądarki
14. Bezpieczeństwo aplikacji mobilnej
SecureStore (Expo)
- Na iOS: Keychain (szyfrowanie sprzętowe).
- Na Android: Keystore + EncryptedSharedPreferences.
- Dane niedostępne dla innych aplikacji.
15. Skanowanie zależności i analiza statyczna
| Narzędzie | Typ | Język | Zastosowanie |
bandit | SAST | Python | Analiza statyczna kodu pod kątem podatności |
pip-audit | SCA | Python | Skanowanie zależności pip pod kątem znanych CVE |
npm audit | SCA | JavaScript | Skanowanie zależności npm pod kątem znanych CVE |
eslint-plugin-security | SAST | JavaScript | Reguły ESLint wykrywające niebezpieczne wzorce |
Dependabot | SCA | Wszystkie | Automatyczne PR z aktualizacjami bezpieczeństwa |
Polityka reakcji na podatności
- Krytyczne (Critical) — natychmiastowa naprawa, deploy w ciągu 24h.
- Wysokie (High) — naprawa w bieżącym sprincie.
- Średnie (Medium) — naprawa w kolejnym sprincie.
- Niskie (Low) — umieszczenie w backlogu.
Podsumowanie
Bezpieczeństwo BusiKM opiera się na wielowarstwowej architekturze ochrony:
- Warstwa transportu — HTTPS, HSTS, bezpieczne ciasteczka.
- Warstwa uwierzytelniania — JWT z rotacją, blacklisting, token_version.
- Warstwa autoryzacji — RBAC, uprawnienia obiektowe, ActionPermissionMixin.
- Warstwa izolacji danych — CompanyScopedMixin, TenantContextMiddleware.
- Warstwa ochrony przed nadużyciem — rate limiting, brute force protection.
- Warstwa przechowywania — szyfrowane tokeny (SecureStore/httpOnly), prywatny S3.
- Warstwa CI/CD — automatyczne skanowanie SAST/SCA, Dependabot.
Każda warstwa działa niezależnie — kompromitacja jednej nie oznacza kompromitacji całego systemu (zasada defense in depth).