Jeśli projekt ma działać poza lokalnym środowiskiem, nie są to dodatki „na później”. Cache potrafi zdjąć dużą część ruchu z bazy, ale może też zwracać nieaktualne dane. Kolejka poprawia przy wolnych operacjach, lecz wymaga idempotencji.
1. Cache w backendzie i przyspieszanie odpowiedzi
Cache nie jest tylko optymalizacją na koniec projektu. To sposób na zdjęcie pracy z bazy, API zewnętrznych i serwera, ale też źródło trudnych błędów, jeśli nie wiesz, kiedy dane stają się nieaktualne.
Redis
Redis to baza działająca głównie w pamięci, często używana jako cache, magazyn sesji, kolejka albo mechanizm pub/sub. Valkey jest alternatywą zgodną z Redis, rozwijaną pod opieką Linux Foundation. W najprostszym wariancie trzymasz w takim magazynie wynik wolnego zapytania przez kilka minut:
W praktyce równie ważna jak samo zapisanie jest strategia unieważniania cache po zmianie danych.
Kiedy cachować odpowiedzi backendu?
Cache ma sens tam, gdzie odczyt jest częsty, a zmiana rzadsza albo akceptujesz chwilowo nieświeże dane. Nie cachuj wszystkiego automatycznie, bo każdy cache trzeba potem unieważnić.
- Dane często czytane, rzadko zmieniane
- Wolne zapytania do bazy
- Wywołania zewnętrznych API
- Obliczenia / agregacje
Strategie cache w aplikacji webowej
Cache-aside jest najczęstszym modelem odczytu:
Write-through synchronizuje cache podczas zapisu. Warstwa cache przekazuje zapis do trwałego magazynu albo aplikacja aktualizuje oba miejsca w jednym kontrolowanym przepływie. To zmniejsza ryzyko nieświeżych odczytów, ale nie daje automatycznej atomowości między dwoma systemami.
Write-behind opóźnia zapis trwałych danych. Odpowiedź jest szybka, lecz awaria przed synchronizacją może spowodować utratę zmian.
Stale-while-revalidate przyspiesza odczyt kosztem świeżości. Użytkownik dostaje starszy wynik, a system odświeża go w tle.
Unieważnianie cache w backendzie
Problem polega na tym, że cache przyspiesza odczyt, ale oddala Cię od źródła prawdy. Masz trzy podstawowe podejścia:
- TTL ogranicza czas nieświeżych danych (
expire after N). To prosty i przewidywalny mechanizm, ale dane mogą być nieaktualne do końca tego okresu. - Zdarzenie usuwa powiązane wpisy cache. Po
UPDATEw bazie wyczyść konkretne klucze, na przykładdel('user:123'). - Wersjonowanie przełącza aktywny klucz cache. Klucz zawiera wersję, na przykład
user:123:v5; stare wpisy zostają, ale aplikacja przestaje je czytać.
Nie używaj KEYS users:list:* na produkcji, bo może zablokować Redis przy dużej liczbie kluczy. Jeśli musisz usuwać po wzorcu, użyj SCAN partiami albo trzymaj własny indeks kluczy per tag, jak na powyższym przykładzie.
Cache stampede i ochrona przed przeciążeniem
Cache może też zaszkodzić, gdy popularny klucz wygasa i nagle setki requestów jednocześnie idą do bazy. To cache stampede. Typowe zabezpieczenia:
Jitter rozprasza moment wygaśnięcia kluczy. Dodaj losowy przedział do TTL, żeby popularne wpisy nie wygasały równocześnie.
Blokada ogranicza równoległe odbudowy cache. Jeden request pobiera dane, a pozostałe czekają albo dostają starszy wynik.
Stale-while-revalidate pozwala obsłużyć ruch natychmiast. Użytkownik dostaje starszą odpowiedź, a backend odświeża cache w tle.
Pre-warming odświeża najpopularniejsze wpisy wcześniej. Uruchom go przed wygaśnięciem cache, ale monitoruj, czy nie generuje zbędnego obciążenia.
HTTP cache jako pierwszy poziom cache
Backend Redis to nie wszystko, ponieważ przeglądarka i przechowują odpowiedzi na podstawie nagłówków HTTP. Frontendowiec widzi to w panelu Network jako (disk cache), (memory cache) albo from CDN.
| Header | Co robi |
|---|---|
Cache-Control: public | CDN może cachować |
Cache-Control: private | Tylko przeglądarka użytkownika |
Cache-Control: no-store | Nie cachuj wcale |
Cache-Control: no-cache | Cachuj, ale zawsze rewaliduj |
max-age=3600 | Cache świeży przez godzinę |
s-maxage=3600 | TTL tylko dla CDN (override max-age) |
stale-while-revalidate=N | Po expiry serwuj stary, w tle pobierz świeży |
stale-if-error=N | Po błędzie serwuj stary (graceful degradation) |
ETag: "abc" | Identyfikator wersji odpowiedzi do rewalidacji |
Conditional request:
Trzy poziomy cache w aplikacji webowej
Czasy są poglądowe i mierzone z różnych miejsc: cache przeglądarki nie wymaga sieci, CDN liczy się od użytkownika, a Redis i baza od serwera aplikacji. Z perspektywy użytkownika dochodzi do nich droga sieciowa do backendu. Dobra aplikacja cachuje na każdym poziomie, gdzie ma to sens.
Cache frameworka i cache Next.js
Nowoczesne frameworki mają własne warstwy:
- Next.js Data Cache. Cachuje wyniki
fetch()zrevalidate. - Next.js Full Route Cache. Całe HTML strony statycznej.
- React
cache(). Deduplikacja wywołań w obrębie jednego żądania renderującego. use cache. Aktualny model cache w Next.js 16 przy włączonych Cache Components.unstable_cache. Starsze API z tagami i rewalidacją, nadal spotykane w projektach sprzed migracji.
W Next.js 16 use cache jest dostępne po włączeniu cacheComponents. Nie czytaj cookies() ani headers() bezpośrednio we współdzielonym zakresie cache. Dane zależne od użytkownika odczytaj poza nim i przekaż jako argument albo użyj mechanizmu przeznaczonego do prywatnego cache. Drugi argument 'max' w revalidateTag włącza zalecane zachowanie stale-while-revalidate; jeśli zapis i kolejny odczyt muszą być natychmiast spójne, sprawdź semantykę updateTag dla Server Actions.
2. Kolejki i zadania w tle
Nie każdy proces powinien kończyć się w czasie jednego requestu. Wysyłka maila, przeliczenie raportu, generowanie PDF-a, synchronizacja CRM czy przetwarzanie płatności mogą trwać za długo albo zależeć od zewnętrznego systemu. Kolejka pozwala szybko odpowiedzieć użytkownikowi, a ciężką pracę wykonać w tle.
Kod 202 Accepted mówi, że serwer przyjął zadanie, a nie że wysłał wiadomość. Dla operacji widocznych dla użytkownika udostępnij status zadania albo wyślij powiadomienie po jego zakończeniu. Zdefiniuj też retencję rezultatów, aby endpoint statusu nie wymagał przechowywania ich bez końca.
Popularne: BullMQ (Redis), RabbitMQ, AWS SQS, Inngest, Trigger.dev (event-driven, type-safe).
Idempotencja i deduplikacja zadań w kolejce
Kolejka nie gwarantuje automatycznie, że zadanie zostanie wykonane dokładnie jeden raz. Wiele systemów działa w modelu at-least-once, co oznacza, że operacja może zostać powtórzona, na przykład po ponownej próbie, restarcie procesu lub chwilowej awarii. Z tego powodu zadania muszą być idempotentne.
jobId ogranicza liczbę identycznych zadań w kolejce, ale sam nie gwarantuje pojedynczego skutku biznesowego. Rekord zadania może zostać usunięty zgodnie z polityką retencji, a worker może zakończyć się po wykonaniu operacji, lecz przed potwierdzeniem jej w kolejce. Dla płatności i dostawców API używaj ich idempotency key. Dla efektów w swojej bazie stosuj unikalny klucz operacji i transakcję.
Retry nie może powielać skutków biznesowych. Ponawiaj błędy przejściowe z wykładniczym opóźnieniem i jitterem. Błędy trwałe, takie jak niepoprawny adres lub odrzucona walidacja, kieruj od razu do obsługi, zamiast wykonywać bez końca.
Transactional outbox zapobiega utracie zdarzeń
Typowy endpoint najpierw zapisuje zamówienie, a potem publikuje OrderCreated. Awaria między tymi operacjami pozostawia zamówienie bez zadania. Odwrócenie kolejności może utworzyć zadanie dla transakcji, która ostatecznie się nie powiodła.
We wzorcu transactional outbox zmiana biznesowa i rekord zdarzenia trafiają do tej samej transakcji bazy:
Osobny publisher pobiera nieobsłużone rekordy z outbox, wysyła je do brokera i oznacza jako opublikowane. Publikacja nadal może nastąpić ponownie, dlatego konsument musi deduplikować zdarzenia po stabilnym eventId. Outbox rozwiązuje problem dwóch zapisów, lecz nie zastępuje idempotentnego workera.
Cron i zadania cykliczne
Cron to praca cykliczna, czyli raport nocny, czyszczenie cache, naliczenie subskrypcji, przypomnienia mailowe. Prosty mechanizm, ale w produkcji musi być idempotentny i monitorowany, ponieważ dwa równoległe uruchomienia potrafią narobić szkód.
Reguły dla cron:
- Zadanie cykliczne musi być idempotentne. Może uruchomić się ponownie po wdrożeniu albo retry.
- Blokada chroni przed równoległym wykonaniem. Przy wielu instancjach użyj na przykład blokady Redis lub advisory lock w PostgreSQL.
- Monitoring wykrywa brak wykonania zadania. Alertuj, gdy zadanie nie rozpoczęło się lub nie zakończyło w oczekiwanym czasie.
W produkcji użyj zarządzanej platformy: Vercel Cron, Cloudflare Cron Triggers, Inngest, GitHub Actions (cron + curl), Kubernetes CronJob.
Wzorce przetwarzania zadań w tle
Fan-out: jedno zdarzenie inicjuje wiele niezależnych zadań (np. nowy użytkownik wyzwala wysyłkę e-maila, tworzenie przestrzeni roboczej i zapis w CRM).
Pipeline: zadania są realizowane sekwencyjnie, gdzie ukończenie zadania A uruchamia zadanie B, a następnie C.
Ponawianie z wykładniczym opóźnieniem (retry with backoff): w razie błędu system podejmuje ponowne próby wykonania zadania, stopniowo wydłużając czas oczekiwania między nimi (np. 1s, 2s, 4s, 8s...).
Kolejka martwych wiadomości (Dead Letter Queue - DLQ): zadania, które wielokrotnie zakończyły się niepowodzeniem, są przenoszone do specjalnej kolejki w celu manualnej analizy.
Ustaw alert na rosnącą kolejkę martwych wiadomości. System może nadal odpowiadać kodem 200, ale z biznesowego punktu widzenia przestaje wykonywać część swojej pracy. Mierz też wiek najstarszego zadania, liczbę prób i czas przetwarzania, ponieważ sama długość kolejki nie pokazuje opóźnienia odczuwanego przez użytkownika.
3. File storage i upload plików
Pliki mają inne wymagania niż rekordy w bazie. Obrazy, dokumenty, avatary i eksportowane PDF-y zwykle nie powinny trafiać bezpośrednio do relacyjnej bazy danych. Najczęściej zapisujesz je w object storage, a w bazie trzymasz tylko metadane i ścieżkę.
Popularne magazyny obiektowe dla aplikacji to AWS S3, Cloudflare R2, Google Cloud Storage, Backblaze B2 i MinIO hostowane samodzielnie. Porównuj koszt operacji, przechowywania i transferu, a nie samą cenę za gigabajt.
Presigned URLs i upload bezpośrednio z frontendu
W większych systemach backend nie powinien przepuszczać każdego pliku przez siebie. Zamiast tego generuje presigned URL, a frontend uploaduje plik bezpośrednio do storage. Backend kontroluje uprawnienia i zapisuje metadane, ale nie musi trzymać całego pliku w pamięci.
Endpoint save-meta nie może ufać samemu key. Powinien sprawdzić właściciela prefiksu, odczytać metadane obiektu ze storage, potwierdzić limit rozmiaru i dopiero zlecić skanowanie. Presigned URL działa jak czasowe poświadczenie, dlatego nie zapisuj go w logach i ustawiaj możliwie krótki okres ważności.
Plusy:
- Backend nie pośredniczy w transferze pliku. Oszczędza pamięć i transfer aplikacji.
- Storage skaluje się niezależnie od backendu. Upload nie zajmuje połączenia z procesem aplikacji.
- Klient omija dodatkowy skok sieciowy. Plik trafia bezpośrednio do magazynu obiektowego.
Bezpieczeństwo uploadu plików
Presigned URL nie znaczy „dowolny upload”. Backend nadal musi narzucić zasady:
Allowlista ogranicza obsługiwane typy plików. Na przykład dopuść tylko
image/jpeg,image/pngiimage/webp,application/pdfLimit rozmiaru egzekwuje polityka storage. Sprawdź go ponownie po uploadzie,
Backend generuje bezpieczny klucz obiektu. Nie używaj nazwy ani ścieżki podanej przez użytkownika,
Bucket pozostaje domyślnie zasobem prywatnym. Publiczny dostęp nadawaj dopiero po weryfikacji,
Walidacja nie ufa nagłówkowi Content-Type. Sprawdź rozmiar, sygnaturę i rzeczywisty format przed aktywacją pliku,
Dokumenty wymagają skanowania przed udostępnieniem. Dotyczy to zwłaszcza PDF-ów i plików dostępnych dla innych użytkowników,
Publikacja następuje po zakończeniu kontroli. Upload trafia do prefiksu kwarantanny, a worker przenosi zaakceptowany obiekt do lokalizacji docelowej.
CDN dla statycznych plików
Pliki publiczne, takie jak avatary i obrazy postów, są zwykle dostarczane przez CDN, na przykład Cloudflare, Bunny lub CloudFront:
Optymalizacja obrazów po uploadzie
Surowe obrazy są ciężkie i tutaj mamy różne metody optymalizacji. Najpopularniejsze podejścia:
- Next.js Image optymalizuje warianty obrazów. Udostępnia zmianę rozmiaru, nowoczesne formaty i lazy loading.
- Usługi obrazowe wykonują transformacje na żądanie. Przykłady to Cloudinary, imgix i Cloudflare Images.
- Sharp przetwarza obrazy we własnym workerze. Możesz zmieniać rozmiar i format po uploadzie.
Na blogu StriveLab wykorzystuje Next.js Image oraz Sharp.
4. Środowiska i deployment backendu
Kod działający lokalnie to dopiero początek zabawy, ponieważ backend musi mieć środowiska, sekrety, migracje, monitoring, backupy i powtarzalny deployment.
Środowiska aplikacji: development, staging i produkcja
Zmienne środowiskowe i sekrety
Nigdy nie commituj .env do repo!
Opcje deploymentu dla backendu
Nie ma jednego najlepszego hostingu dla backendu. Wybór zależy od tego, czy potrzebujesz prostoty, kontroli, globalnego edge czy przewidywalnych kosztów.
Platform as a Service (łatwe):
- Vercel (Next.js)
- Railway
- Render
- Heroku
Container (więcej kontroli):
- Docker + Kubernetes
- AWS ECS
- Google Cloud Run
VPS (pełna kontrola):
- DigitalOcean
- AWS EC2
- Hetzner (Niemcy, świetna cena/wydajność)
- Coolify (PaaS hostowany samodzielnie na własnym VPS)
Edge / :
- Cloudflare Workers
- Vercel Functions (Fluid compute)
- Deno Deploy
- AWS Lambda + API Gateway
- Fly.io (globalne VM)
CI/CD i automatyzacja deploymentu
Pipeline w GitHub Actions albo GitLab CI sprawia, że testy, build i wdrożenie są powtarzalne:
Minimum sensownego pipeline'u:
- Instalacja zależności z lockfile (
npm ci,pnpm install --frozen-lockfile). - Lint, testy jednostkowe i testy typów.
- Build produkcyjny.
- Skan sekretów i zależności.
- Migracje bazy w kontrolowanym kroku.
- Deploy.
- Smoke test po wdrożeniu.
Strategie deploymentu bezpieczne dla produkcji
- Blue-green. Dwa środowiska, switch ruchu w jednej chwili (zero downtime)
- Canary. Nowa wersja dostaje 1% ruchu, jeśli nie pada → 10% → 50% → 100%
- Rolling. Instancje aktualizowane po kolei (Kubernetes default)
- Feature flags. Kod wdrożony, ale wyłączony; włączany per użytkownik albo kohorta (LaunchDarkly, Unleash, GrowthBook)
Migracje bazy danych bez downtime
Najczęstszy błąd przy deploymentach backendu to założenie, że kod i baza zmienią się dokładnie w tej samej sekundzie. W realnym wdrożeniu przez chwilę mogą działać dwie wersje kodu: stara i nowa. Migracje muszą być z nimi kompatybilne.
Bezpieczny wzorzec to expand → migrate → contract:
- Expand. Dodaj nową kolumnę/tabelę jako opcjonalną, bez usuwania starego pola.
- Deploy kodu. Nowa wersja potrafi pisać do starego i nowego modelu albo czytać oba.
- Backfill. Uzupełnij dane w tle, partiami.
- Przełącz odczyt. Aplikacja zaczyna czytać z nowej struktury.
- Contract. Dopiero po czasie usuń stare pole.
Unikaj migracji, które długo blokują tabele w godzinach ruchu. Przy dużych tabelach indeksy, backfill i zmiany NOT NULL trzeba planować osobno.
Health checks, readiness i rollback
Backend powinien mieć przynajmniej dwa endpointy kontrolne:
Po wdrożeniu uruchom smoke test: zalogowanie testowego użytkownika, podstawowy endpoint API, zapis/odczyt z bazy i jeden krytyczny flow biznesowy. Rollback też musi być przećwiczony: jeśli nowy kod jest cofany, baza nadal musi być kompatybilna z poprzednią wersją aplikacji.
Backups i disaster recovery
Backup jest użyteczny dopiero wtedy, gdy potrafisz go odtworzyć. Sama informacja „mamy backupy” niewiele znaczy, jeśli nikt nigdy nie sprawdził procesu odtwarzania.
- Automatyczne backupy bazy (PostgreSQL:
pg_dump, point-in-time recovery) - Regularny test potwierdza możliwość odtworzenia. Nie zakładaj, że sama obecność pliku backupu wystarczy.
- RTO określa dopuszczalny czas odtwarzania (Recovery Time Objective).
- RPO określa dopuszczalną utratę danych (Recovery Point Objective).
5. Monitoring i logging backendu
Bez monitoringu backend jest czarną skrzynką. Widzisz tylko, że użytkownik zgłasza problem, ale nie wiesz, czy zawiodła baza, zewnętrzne API, deployment, cache czy konkretna ścieżka w kodzie.
Logi aplikacji backendowej
Nie zapisuj w logach haseł, tokenów, pełnych nagłówków Cookie i Authorization ani kompletnych payloadów zawierających dane osobowe. Redakcję pól wrażliwych skonfiguruj w loggerze, zanim dane trafią do zewnętrznego systemu.
Popularne narzędzia do obsługi logów to Winston, Pino, Datadog i Papertrail.
Monitoring backendu
Monitoring odpowiada na pytanie, czy system działa zdrowo. Logi mówią, co się wydarzyło w konkretnym przypadku, a metryki pokazują trend i skalę problemu.
- Uptime pokazuje dostępność usługi.
- Latency pokazuje czas odpowiedzi.
- Errors pokazuje udział nieudanych żądań.
- Resources pokazuje nasycenie infrastruktury: CPU, RAM, dysk i pulę połączeń.
Popularne narzędzia do monitorowania systemu to Grafana, Datadog, New Relic, Sentry, Better Stack i Honeycomb.
Trzy filary observability
- Logi opisują pojedyncze zdarzenia systemowe.
- Metryki pokazują trendy oraz skalę: latency, throughput i błędy.
- Trace pokazuje drogę jednego żądania przez wszystkie usługi.
Minimum praktyczne dla frontendowca i backendowca to wspólny request ID. Backend zwraca go w nagłówku, frontend dołącza do raportu błędu, a logi pozwalają znaleźć dokładny request.
Distributed tracing w aplikacji webowej
W większych systemach pojedynczy request często przechodzi przez kilka usług. Bez trace'u widzisz tylko „endpoint trwa 800 ms”. Z trace'em widzisz, że 600 ms zjada konkretne zapytanie do bazy albo jedna integracja zewnętrzna.
OpenTelemetry oddziela instrumentację od dostawcy danych. Może eksportować telemetrykę między innymi do Datadog, Honeycomb, Tempo i Jaeger.
Alerty produkcyjne: co powinno budzić w nocy?
Alert powinien odpowiadać na objaw, nie na przyczynę. SRE Google definiuje tzw. „Four Golden Signals":
- Latency opisuje rozkład czasu odpowiedzi, na przykład p50, p95 i p99.
- Traffic pokazuje natężenie obsługiwanego ruchu, na przykład RPS.
- Errors pokazuje odsetek błędnych żądań, na przykład odpowiedzi 5xx.
- Saturation mierzy wykorzystanie dostępnych zasobów, między innymi CPU, RAM, dysku i puli połączeń.
Alert niech budzi tylko wtedy, gdy użytkownik faktycznie odczuwa problem. Reszta to ticket „do obejrzenia”.
Observability od frontendu do backendu
Frontend też powinien wysyłać błędy i metryki. Sentry, LogRocket, Datadog RUM pokazują, jak użytkownik dochodzi do błędu. Powiąż user-id / request-id między frontem a backendem, żeby widzieć całą ścieżkę.
6. Bezpieczeństwo backendu dla frontendowca
Bezpieczeństwo backendu to zestaw powtarzalnych praktyk: walidujesz dane, ograniczasz uprawnienia, nie ufasz klientowi, logujesz zdarzenia i zakładasz, że każdy publiczny endpoint będzie testowany przez kogoś nieżyczliwego.
Podstawowe zasady bezpieczeństwa backendu
- Waliduj wszystkie dane wejściowe po stronie serwera.
- Parametryzuj każde zapytanie do bazy danych. Unikaj injection.
- Hasła przechowuj przez adaptacyjne hashowanie. Preferuj Argon2id; bcrypt pozostaw głównie dla istniejących systemów.
- HTTPS chroni dane podczas transmisji.
- Rate limiting ogranicza automatyczne nadużycia.
- Autoryzację zawsze wykonuj na backendzie. może ukryć przycisk, ale nie może być źródłem prawdy.
- CORS kontroluje odczyt odpowiedzi przez przeglądarkę. Nie zastępuje uwierzytelniania ani autoryzacji.
Rate limiting w praktyce
Frontend reaguje na 429:
Powyższy kod używa domyślnego magazynu w pamięci, więc nie współdzieli licznika między procesami ani instancjami. W środowisku rozproszonym potrzebujesz wspólnego store, na przykład Redis, oraz poprawnej konfiguracji zaufanego proxy. Limit logowania projektuj przynajmniej na podstawie konta i źródła ruchu, ponieważ sam adres IP może reprezentować wielu użytkowników albo zmieniać się między próbami.
Limity na CDN i backendzie uzupełniają się. CDN lub WAF odrzuca część ruchu przed aplikacją, a backend egzekwuje reguły biznesowe dla konta, tokenu lub kosztownej operacji. Rate limiting utrudnia automatyczne nadużycia, lecz sam nie stanowi kompletnej ochrony przed DDoS.
CORS to nie autoryzacja
CORS mówi przeglądarce, czy JavaScript z danego origina może odczytać odpowiedź. Nie blokuje curl, aplikacji mobilnej, backendu ani atakującego, który woła API bezpośrednio. Dlatego CORS jest warstwą kontroli przeglądarki, a nie mechanizmem uprawnień.
Backend nadal musi sprawdzić sesję, token, role i właściciela zasobu.
OWASP Top 10 jako minimum bezpieczeństwa
OWASP Top 10 to lista najważniejszych kategorii ryzyk aplikacji webowych. Aktualną wersją jest OWASP Top 10:2025. Nie musisz znać każdego scenariusza ataku na pamięć, ale jako frontendowiec powinieneś rozumieć, które problemy są rozwiązywane wyłącznie po stronie backendu.
- Broken Access Control. Sprawdzanie uprawnień odbywa się dla każdego żądania na backendzie; ukrycie przycisku w UI nie wystarcza.
- Security Misconfiguration. Debug w produkcji, otwarte buckety, domyślne hasła, złe nagłówki.
- Software Supply Chain Failures. Zależności, build pipeline, lockfile, paczki npm, obrazy Dockera.
- Cryptographic Failures. HTTPS wszędzie, bezpieczne algorytmy, brak danych wrażliwych w logach.
- Injection. SQL injection, XSS, NoSQL injection, command injection.
- Insecure Design. Przykładowo, brak rate limitu na reset hasła albo brak modelu uprawnień.
- Authentication Failures. Słabe hasła, brak MFA, długie sesje, zły reset hasła.
- Software or Data Integrity Failures. Niepodpisane artefakty, niekontrolowane aktualizacje, zaufanie do niezweryfikowanych danych.
- Security Logging and Alerting Failures. Nie wiesz, że trwa atak albo wyciek.
- Mishandling of Exceptional Conditions. Wyjątki ujawniają dane, pomijają autoryzację albo zostawiają system w złym stanie.
SSRF nie zniknął jako problem, ponieważ w OWASP Top 10:2025 został włączony w szerszą kategorię Broken Access Control.
XSS, czyli Cross-Site Scripting
Atakujący wstrzykuje JS w kontekst Twojej domeny (komentarz, profil). Skradzione cookies, wyświetlone fałszywe formularze.
Obrona:
- Escapuj output. React i większość frameworków robi to domyślnie. Uważaj na
dangerouslySetInnerHTML. - Content-Security-Policy (CSP). Header, który mówi przeglądarce, skąd wolno ładować skrypty:
Code
- Sanityzuj HTML biblioteką przeznaczoną do tego celu, na przykład DOMPurify lub sanitize-html.
Walidacja inputu po stronie backendu
Walidacja w formularzu poprawia UX, walidacja na serwerze chroni system. Użytkownik może wyłączyć JavaScript, zmodyfikować payload w DevTools albo wysłać request z własnego skryptu.
Klient waliduje dla UX, a serwer waliduje dla bezpieczeństwa.
Mass assignment
Secret management w backendzie
Sekrety nigdy nie trafiają do repozytorium, nawet prywatnego.
- Lokalnie:
.env+.gitignore,direnv, 1Password CLI - CI/CD: GitHub Secrets, GitLab CI Variables
- Produkcja: AWS Secrets Manager, HashiCorp Vault, Doppler, Infisical
- Rotacja ogranicza czas użycia wykradzionego sekretu. Obejmuje między innymi klucze API i hasła do bazy.
Jeśli sekret trafił do repo, także w usuniętym commicie, uznaj go za skompromitowany i wymień. Samo usunięcie pliku nie unieważnia poświadczenia.
Supply chain i bezpieczeństwo zależności
Bezpieczeństwo zależy też od tego, co instalujesz i jak budujesz aplikację:
- commituj lockfile i instaluj zależności komendą deterministyczną (
npm ci,pnpm --frozen-lockfile), - włącz Dependabot albo Renovate,
- używaj
npm auditz rozsądkiem: nie każda podatność dotyczy ścieżki produkcyjnej, ale krytycznych nie ignoruj, - pinuj obrazy Dockera do wersji albo digestu,
- skanuj sekrety w CI,
- ogranicz uprawnienia tokenów CI/CD do minimum,
- nie uruchamiaj skryptów z internetu bez sprawdzenia, co robią.
SSRF przy URL-ach od użytkownika
SSRF pojawia się, gdy backend pobiera URL podany przez użytkownika, czyli może chodzić o import obrazka, webhook testowy, parser Open Graph, PDF generator. Atakujący może próbować zmusić serwer do połączenia z adresem wewnętrznym, np. metadata service w chmurze.
Obrona:
- allowlista hostów albo domen,
- blokada prywatnych adresów IP (
127.0.0.1,10.0.0.0/8,169.254.169.254, IPv6 local), - limit rozmiaru odpowiedzi i timeout,
- brak przekazywania sekretów do pobieranego URL,
- osobny worker/sandbox do pobierania nieufnych zasobów.
Security headers w aplikacji webowej
Standardowe headery, które dodaje helmet:
Zwraca między innymi:
Strict-Transport-Securitywymusza HTTPS przez wskazany czas (HSTS)X-Content-Type-Options: nosniffblokuje zgadywanie MIMEX-Frame-Options: DENYogranicza osadzanie strony w ramceReferrer-Policy: strict-origin-when-cross-originPermissions-Policyogranicza dostęp do funkcji przeglądarki
Sprawdź swoje headery na securityheaders.com.
RODO i prywatność w warstwie backendowej
RODO nie sprowadza się do bannera cookies ani pojedynczego endpointu usuwania konta. Zakres obowiązków zależy od roli organizacji, celu przetwarzania i podstawy prawnej. Projekt techniczny powinien uwzględniać przynajmniej:
- Jawny cel i podstawę przetwarzania danych oraz dokumentację, które pola są potrzebne do danego procesu,
- Minimalizację danych oraz okres retencji wraz z automatycznym usuwaniem lub anonimizacją rekordów po jego upływie,
- Obsługę praw osoby, której dane dotyczą, w tym dostępu, sprostowania, usunięcia i przenoszenia, gdy mają zastosowanie,
- Kontrolę podmiotów przetwarzających i transferów danych, w tym umowy powierzenia oraz lokalizacje usług, logów i backupów,
- Bezpieczeństwo, audyt dostępu i procedurę incydentową, obejmującą ocenę naruszenia oraz wymagane zgłoszenia.
Zgoda nie jest jedyną podstawą przetwarzania. W kontekście cookies i podobnych technologii odrębnie oceń wymagania ePrivacy: mechanizmy ściśle niezbędne mogą być traktowane inaczej niż analityka lub reklama. Nie uruchamiaj nieobowiązkowych trackerów przed uzyskaniem ważnej zgody, jeśli jest ona wymagana. Szczegóły prawne i lokalne wyjątki skonsultuj ze specjalistą od ochrony danych.
Co dalej: ścieżka nauki backendu dla frontendowca
Nie próbuj uczyć się backendu przez czytanie wszystkiego naraz. Najszybciej rośnie się przez mały projekt, który dotyka kilku prawdziwych problemów: logowania, bazy, walidacji, uploadu, webhooka i deploymentu. Poniższa ścieżka układa tematy od fundamentów do architektury.
Poziom 1: fundamenty backendu
- HTTP: request, response, kody statusu i nagłówki
- Node.js + Express (lub Hono / Fastify)
- Podstawy SQL: CRUD, JOIN, indeksy i transakcje
- Projektowanie : zasoby, metody i statusy HTTP
- CORS: działanie, typowe błędy i konfiguracja
Poziom 2: praktyka integracji
- PostgreSQL + Prisma / Drizzle
- Uwierzytelnianie: sesje, JWT, cookies i CSRF
- Walidacja inputu (Zod) i strukturalne błędy (RFC 9457)
- Deployment na Vercel, Railway lub Render
- Przyjmowanie i wysyłanie webhooków
Poziom 3: zaawansowane tematy backendowe
- Redis lub Valkey: cache, pub/sub i kolejki (BullMQ)
- Real-time przez i WebSockets
- Docker + pipeline CI/CD
- Monitoring / logging / tracing (OpenTelemetry, Sentry)
- Connection pooling / serverless drivery (PgBouncer, Neon)
Poziom 4: architektura systemów
- Microservices vs monolith
- Event-driven architecture, kolejki
- CQRS, Event Sourcing
- Systemy rozproszone: CAP theorem i eventual consistency
- Testy obciążeniowe (k6, Artillery)
Projekt do nauki backendu
Najlepszy projekt do nauki nie musi być oryginalny. Ma zmusić Cię do przejścia przez typowe decyzje backendowe. Dobrym kandydatem jest prosty blog z autentykacją:
- Rejestracja / logowanie (sesja albo JWT),
- postów z paginacją,
- Komentarze aktualizowane przez SSE jako rozszerzenie,
- Upload obrazów (presigned URLs do S3 / R2),
- Webhook handler (Stripe sandbox jako „płatne posty”),
- Deployment + CI/CD,
- Sentry / monitoring.
Taki projekt nie wygląda efektownie na pierwszy rzut oka, ale pokrywa większość problemów, które wracają w komercyjnych aplikacjach: stan użytkownika, dane, uprawnienia, pliki, integracje, błędy i deployment.
| Komponent | Rola | Popularne (2026) |
|---|---|---|
| Serwer | Logika aplikacji | Express, Fastify, Hono, NestJS |
| Runtime | Wykonanie kodu | Node.js, Bun, Deno, Cloudflare Workers |
| Baza danych | Przechowywanie | PostgreSQL, MySQL, MongoDB, SQLite (Turso) |
| ORM / query builder | Abstrakcja bazy | Prisma, Drizzle, Kysely |
| Cache | Przyspieszanie | Redis, Valkey, Memcached, HTTP cache |
| Auth | Bezpieczeństwo | Auth.js, Clerk, Supabase Auth, Better Auth |
| API style | Komunikacja | REST, GraphQL, tRPC |
| Real-time | Push z serwera | SSE, WebSockets, Pusher |
| Storage | Pliki | S3, Cloudflare R2, object storage + CDN |
| Kolejki | Zadania w tle | BullMQ, Inngest, Trigger.dev, SQS |
| Walidacja | Bezpieczny input | Zod, Valibot, Yup |
| Deployment | Hosting | Vercel, Railway, Fly.io, Render, Cloudflare |
| Observability | Co się dzieje | Sentry, Datadog, Better Stack, Honeycomb |
Wybierasz warstwę danych? Porównaj Drizzle ORM i Prisma przed wdrożeniem aplikacji.
Pozostałe części serii
- Backend dla frontendowca: serwer, bazy danych i API
- Backend dla frontendowca: auth, real-time i integracje


