·3 min read·autor: Wedece Studio

Gdy restrykcyjny CSP zmienił statyczny Next.js w SSR

Nagłówek bezpieczeństwa potrafi zmienić wydajność serwisu, choć na ekranie nie pojawi się ani jeden nowy element. Przekonaliśmy się o tym podczas wzmacniania wedece.com. Polityka

Nagłówek bezpieczeństwa potrafi zmienić wydajność serwisu, choć na ekranie nie pojawi się ani jeden nowy element. Przekonaliśmy się o tym podczas wzmacniania wedece.com. Polityka Content Security Policy oparta na nonce wyglądała jak naturalny krok naprzód, lecz w naszej architekturze Next.js po cichu przełączyła wszystkie strony na renderowanie przy każdym żądaniu. Rozwiązaniem nie było usunięcie CSP, tylko dopasowanie go do realnego ryzyka i sposobu hostowania strony.

Skąd wziął się dynamiczny rendering

Pierwsza wersja generowała w middleware świeży nonce dla każdego żądania. Wartość trafiała do nagłówka CSP, a wspólny layout odczytywał ją z nagłówków, aby przekazać ten sam nonce skryptom Next.js, analityce i danym strukturalnym. To mocny mechanizm: przeglądarka uruchamia tylko skrypty oznaczone nieprzewidywalną wartością przypisaną do konkretnej odpowiedzi.

Ma on jednak konsekwencję architektoniczną. Next.js nie może wstawić wartości znanej dopiero przy żądaniu do HTML-a wygenerowanego wcześniej podczas budowania. Oficjalna dokumentacja wymaga więc dynamicznego renderowania stron korzystających z nonce. Ponieważ nagłówki odczytywał layout wspólny dla całego serwisu, także statyczne treści przestały korzystać ze zwykłego prerenderingu i cache CDN. Każde wejście uruchamiało pełny rendering React po stronie serwera.

Dlaczego Worker nie miał zapasu

wedece.com działa w Next.js przez OpenNext na Cloudflare Workers. Bezpłatny plan Workers przewiduje 10 ms czasu CPU na żądanie. Cloudflare podaje równocześnie, że cięższe zadania, w tym server-side rendering, zwykle zużywają 10–20 ms. SSR może działać na tej platformie, ale dla niemal statycznej strony marketingowej renderowanie każdej podstrony przy każdym wejściu nie dawało sensownego marginesu.

W naszej implementacji ruch równoległy kończył się błędem Workera 1102. Sam mechanizm bezpieczeństwa działał zgodnie z założeniem; nie pasował jednak do budżetu wykonania. To ważniejsza lekcja niż konkretny fragment konfiguracji: CSP jest częścią architektury renderowania, a nie nagłówkiem dopisywanym na końcu projektu.

Świadomy kompromis w produkcji

Przenieśliśmy CSP z middleware do statycznej konfiguracji headers() w next.config.ts. Obecna polityka ogranicza default-src do własnej domeny, jawnie wskazuje hosty analityki i reCAPTCHA oraz zachowuje restrykcje takie jak object-src 'none', frame-ancestors 'none', base-uri 'self' i form-action 'self'. Aplikacja nie odczytuje już nonce z żądania, więc strony publiczne znów mogą być prerenderowane i cachowane.

Kosztem jest dopuszczenie unsafe-inline dla skryptów i stylów. To osłabia ochronę przed wstrzykniętym kodem inline, dlatego nie jest uniwersalnym wzorcem. Uznaliśmy ten kompromis za adekwatny tylko dla obecnego zakresu wedece.com: strony informacyjnej bez logowania, kont użytkowników i treści użytkowników renderowanych na stronie. Dodanie którejkolwiek z tych funkcji oznacza obowiązkowy powrót do tej decyzji.

Nie używamy też strict-dynamic. W CSP Level 3 ta dyrektywa, przy poprawnym nonce lub hashu, powoduje ignorowanie list hostów, 'self' i 'unsafe-inline' dla skryptów. Dopisanie jej do statycznej polityki nie wzmocniłoby automatycznie ochrony — zmieniłoby model zaufania i mogłoby zablokować integracje zewnętrzne.

Sprawdzenie na prawdziwej odpowiedzi

Po zmianie CSP kontrolujemy odpowiedź produkcyjną, nie tylko plik konfiguracyjny. 23 września 2026 strona główna zwracała egzekwowaną politykę statyczną, x-nextjs-prerender: 1 oraz cache-control: s-maxage=31536000. Testy Playwright przechodzą przez najważniejsze trasy i sprawdzają blog, sitemapę, RSS oraz dane strukturalne. Osobny endpoint przyjmuje raporty naruszeń CSP i w produkcji przekazuje je do Sentry.

Praktyczna zasada brzmi: zacznij od polityki odpowiadającej modelowi zagrożeń, a potem zmierz jej wpływ na rendering, cache i skrypty zewnętrzne. Bezpieczeństwo i wydajność nie kończą się na poprawnej składni nagłówka — muszą działać razem pod rzeczywistym ruchem.

Podobało się? Piszemy co kilka tygodni.

Dołącz do newslettera po playbooki studia, narzędzia AI i świeże case studies.