Nie są jednak magiczną zaporą. Nagłówek nie naprawi błędnej autoryzacji, podatnego API, SQL Injection, wycieku sekretów ani nieaktualnej biblioteki. Jest warstwą defense in depth: zmniejsza powierzchnię ataku i ogranicza to, co przeglądarka może zrobić po wystąpieniu innego błędu.
W 2026 roku najważniejsze jest rozróżnienie trzech grup:
- Nagłówki bazowe, które mają sens dla większości stron.
- Nagłówki zależne od architektury, które mogą blokować OAuth, płatności, CDN, iframe’y albo pliki PDF, jeśli zostaną dodane bez analizy.
- Nagłówki przestarzałe, których nie należy dodawać tylko po to, aby uzyskać wyższy wynik w przypadkowym skanerze.
TL;DR: zacznij od dobrze zaprojektowanego CSP, HSTS po pełnym wdrożeniu HTTPS,
X-Content-Type-Options: nosniff, jawnegoReferrer-Policyi rozsądnegoPermissions-Policy. Ochronę przed osadzaniem realizuj przede wszystkim przezframe-ancestorsw CSP, pozostawiającX-Frame-Optionsjako warstwę kompatybilności. COOP, COEP i CORP wdrażaj dopiero po analizie integracji cross-origin. Wyłącz lub usuńX-XSS-Protection,Expect-CT, HPKP i staryReport-To.
Zalecenia i stan kompatybilności zostały zweryfikowane 23 lipca 2026 roku.
Najważniejsze nagłówki w jednej tabeli
| Nagłówek | Typowa rekomendacja | Co ogranicza | Czy wdrażać wszędzie? |
|---|---|---|---|
Content-Security-Policy |
polityka dopasowana do aplikacji, najlepiej oparta na nonce lub hashach | XSS, injection, nieautoryzowane źródła zasobów, osadzanie | tak dla stron renderujących HTML, ale po testach |
Strict-Transport-Security |
max-age=31536000; includeSubDomains, a preload dopiero po analizie |
downgrade do HTTP, pomijanie błędów certyfikatu | tak, gdy cała domena i subdomeny poprawnie działają przez HTTPS |
X-Content-Type-Options |
nosniff |
MIME sniffing i część MIME confusion | tak |
Referrer-Policy |
strict-origin-when-cross-origin lub bardziej restrykcyjna |
wyciek ścieżek i parametrów URL | tak |
Permissions-Policy |
wyłącz nieużywane funkcje, np. camera=(), microphone=(), geolocation=() |
dostęp dokumentu i iframe’ów do wybranych API | zazwyczaj tak, po sprawdzeniu kompatybilności funkcji |
CSP frame-ancestors |
'none', 'self' albo konkretne originy |
clickjacking i niechciane osadzanie | tak dla dokumentów HTML |
X-Frame-Options |
DENY lub SAMEORIGIN jako kompatybilność |
clickjacking w starszych implementacjach | często, równolegle z frame-ancestors |
Cross-Origin-Opener-Policy |
zwykle same-origin, jeśli aplikacja nie wymaga zachowania relacji z popupami cross-origin |
część XS-Leaks i dostęp przez window.opener |
zależnie od OAuth, płatności i popupów |
Cross-Origin-Embedder-Policy |
require-corp lub credentialless tylko świadomie |
osadzanie cross-origin bez zgody zasobu | nie automatycznie |
Cross-Origin-Resource-Policy |
same-origin, same-site albo cross-origin zależnie od zasobu |
odczyt odpowiedzi przez niepożądane originy | zależnie od modelu udostępniania |
Cache-Control |
no-store dla szczególnie wrażliwych odpowiedzi; private dla spersonalizowanych |
przechowywanie danych w cache | dla odpowiedzi wrażliwych |
Set-Cookie |
Secure; HttpOnly; SameSite=Lax/Strict zależnie od procesu |
kradzież i niewłaściwe wysyłanie cookies | dla cookies sesyjnych |
Reporting-Endpoints |
endpoint raportów CSP/COOP/COEP | obserwowalność naruszeń polityk | opcjonalnie |
X-XSS-Protection |
usunąć albo 0 |
stary filtr XSS | nie włączać |
Expect-CT |
usunąć | przestarzały mechanizm CT | nie |
Public-Key-Pins |
nie używać | historyczny pinning certyfikatów | nie |
OWASP traktuje nagłówki jako ważne wzmocnienie bezpieczeństwa, ale podkreśla konieczność poprawnej konfiguracji i dopasowania do danego typu odpowiedzi.
Minimalny zestaw dla typowej strony
Poniższy przykład jest punktem startowym, nie konfiguracją do bezrefleksyjnego kopiowania:
Content-Security-Policy: default-src 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'none'; form-action 'self'; img-src 'self' data: https:; font-src 'self'; style-src 'self'; script-src 'self'; connect-src 'self'; upgrade-insecure-requests
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
X-Frame-Options: DENY
Ta polityka zablokuje:
- skrypty i style inline,
- zasoby z nieujętych originów,
- osadzanie strony w iframe,
- formularze wysyłane poza własny origin,
- użycie kamery, mikrofonu i geolokalizacji,
- ładowanie witryny przez HTTP po zapisaniu HSTS.
Jeżeli strona używa Google Fonts, zewnętrznego API, narzędzia analitycznego, mapy, płatności, logowania OAuth, menedżera tagów albo skryptów inline, politykę trzeba dostosować.
1. Content-Security-Policy: najważniejszy i najtrudniejszy nagłówek
Content-Security-Policy pozwala określić, z jakich źródeł przeglądarka może ładować skrypty, style, obrazy, fonty, ramki i połączenia sieciowe. Dobrze skonfigurowany CSP pomaga ograniczać XSS i ataki polegające na wstrzyknięciu danych, ale nie zastępuje walidacji, kodowania outputu i bezpiecznych API.
Podstawowe dyrektywy
| Dyrektywa | Rola | Typowa wartość startowa |
|---|---|---|
default-src |
fallback dla nieokreślonych typów zasobów | 'self' |
script-src |
dozwolone skrypty | nonce lub hashe; ewentualnie 'self' |
style-src |
dozwolone arkusze i style | 'self', nonce lub hashe |
img-src |
obrazy | 'self' data: https: |
font-src |
fonty | 'self' i konkretne CDN |
connect-src |
Fetch, XHR, WebSocket, EventSource | własne API i konkretne endpointy |
frame-src |
ramki osadzane przez stronę | tylko wymagane originy |
frame-ancestors |
kto może osadzić tę stronę | 'none' lub 'self' |
form-action |
dokąd formularze mogą wysyłać dane | 'self' lub wskazane endpointy |
base-uri |
dozwolone adresy dla <base> |
'self' albo 'none' |
object-src |
pluginy <object> i <embed> |
'none' |
upgrade-insecure-requests |
zamiana żądań HTTP na HTTPS | bez wartości |
Polityka allowlist kontra ścisły CSP
Polityka oparta wyłącznie na listach domen bywa trudna w utrzymaniu. Zaufany CDN może serwować wiele treści, a skrypt third-party może dynamicznie ładować kolejne zależności. web.dev rekomenduje ścisły CSP oparty na nonce albo hashach, a strict-dynamic pozwala ufać skryptom załadowanym przez zaufany skrypt.
Przykład polityki nonce:
Content-Security-Policy:
default-src 'self';
base-uri 'self';
object-src 'none';
frame-ancestors 'none';
form-action 'self';
script-src 'nonce-{RANDOM_NONCE}' 'strict-dynamic';
style-src 'self' 'nonce-{RANDOM_NONCE}';
img-src 'self' data: https:;
font-src 'self';
connect-src 'self' https://api.example.com;
upgrade-insecure-requests
W HTML:
<script nonce="{RANDOM_NONCE}">
window.__APP_CONFIG__ = { apiUrl: "https://api.example.com" };
</script>
Nonce musi być:
- losowy i trudny do przewidzenia,
- inny dla każdej odpowiedzi HTML,
- umieszczony zarówno w nagłówku, jak i zaufanych elementach,
- generowany po stronie serwera.
Stały nonce wpisany w konfigurację nie daje oczekiwanej ochrony. Jeśli strona jest statyczna i nie może generować nowej wartości dla każdej odpowiedzi, bardziej praktyczny może być CSP oparty na hashach.
unsafe-inline i unsafe-eval
Dodanie 'unsafe-inline' do script-src znacząco osłabia ochronę przed XSS, ponieważ zezwala na wykonywanie kodu inline. 'unsafe-eval' pozwala na mechanizmy wykonujące kod ze stringów, takie jak eval() i konstruktor Function().
Nie usuwaj tych ograniczeń tylko po to, aby uciszyć błędy w konsoli. Najpierw:
- przenieś kod inline do plików,
- użyj nonce lub hasha,
- zidentyfikuj bibliotekę wymagającą
eval, - sprawdź, czy można zmienić jej build albo konfigurację.
Trusted Types
Dyrektywa:
Content-Security-Policy: require-trusted-types-for 'script'; trusted-types app-policy
może wymusić przekazywanie typowanych wartości do wybranych DOM XSS sinków, takich jak innerHTML. Od lutego 2026 require-trusted-types-for jest dostępne w aktualnych głównych przeglądarkach, ale starsze wersje mogą go nie obsługiwać.
Trusted Types są rozwiązaniem zaawansowanym. Nie wystarczy dodać nagłówka: aplikacja musi definiować bezpieczne polityki transformacji, a używane frameworki i biblioteki muszą być zgodne.
CSP Report-Only
Najbezpieczniejsze wdrożenie zaczyna się od:
Content-Security-Policy-Report-Only: default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'; report-to csp-endpoint
Reporting-Endpoints: csp-endpoint="https://example.com/security/csp-reports"
Content-Security-Policy-Report-Only raportuje naruszenia bez blokowania zasobów, dzięki czemu można znaleźć brakujące originy przed włączeniem egzekwowania. Reporting-Endpoints zastępuje przestarzały nagłówek Report-To i powinien być preferowany przy deklarowaniu endpointów raportowania.
Raporty CSP mogą zawierać adresy i informacje o zasobach. Endpoint powinien:
- przyjmować tylko oczekiwane typy i rozmiary danych,
- mieć rate limiting,
- nie logować niepotrzebnych danych osobowych,
- nie renderować otrzymanego payloadu bez kodowania,
- mieć retencję dopasowaną do celu diagnostycznego.
2. Strict-Transport-Security: HTTPS bez drogi powrotnej
HSTS informuje przeglądarkę, że host powinien być odwiedzany wyłącznie przez HTTPS. Po zapisaniu polityki przeglądarka automatycznie zamienia przyszłe próby HTTP na HTTPS i nie pozwala użytkownikowi ominąć części błędów certyfikatu.
Przykład:
Strict-Transport-Security: max-age=31536000; includeSubDomains
Co oznaczają dyrektywy?
max-age=31536000- zapamiętanie polityki na rok,includeSubDomains- objęcie subdomen,preload- deklaracja chęci umieszczenia domeny na liście preload.
Dlaczego nie zaczynać od dwóch lat i preload?
Błędnie wdrożony HSTS może odciąć legalnych użytkowników. Jeżeli stara subdomena działa tylko po HTTP, certyfikat wygaśnie albo domena korzysta z infrastruktury, której nie kontrolujesz, includeSubDomains i długi max-age mogą spowodować poważną awarię.
Bezpieczniejszy rollout:
5 minut → 1 dzień → 1 tydzień → 1 miesiąc → 1 rok
Na każdym etapie sprawdź:
- domenę główną,
- wszystkie aktywne subdomeny,
- wildcard i SAN w certyfikatach,
- zasoby legacy,
- panele, API, pocztę webową i endpointy partnerów.
HSTS preload wymaga między innymi poprawnego certyfikatu, przekierowania HTTP do HTTPS, odpowiedniego max-age, includeSubDomains i dyrektywy preload. Wpis trafia następnie do kodu przeglądarek, a wycofanie może trwać wiele tygodni.
3. X-Content-Type-Options: zatrzymaj zgadywanie MIME
X-Content-Type-Options: nosniff
Nagłówek informuje przeglądarkę, aby respektowała zadeklarowany Content-Type i nie próbowała samodzielnie interpretować odpowiedzi jako innego typu. Dla skryptów i stylów odpowiedź może zostać zablokowana, jeśli MIME nie odpowiada oczekiwanemu typowi.
Nagłówek nie zastępuje poprawnej konfiguracji serwera. Nadal trzeba wysyłać prawidłowe wartości:
Content-Type: text/html; charset=utf-8
Content-Type: text/css; charset=utf-8
Content-Type: application/javascript; charset=utf-8
Content-Type: application/json; charset=utf-8
Content-Type: image/avif
Szczególnie ważne jest to przy:
- plikach przesyłanych przez użytkowników,
- endpointach pobierania,
- zasobach generowanych dynamicznie,
- storage i CDN,
- odpowiedziach błędów, które mogą zwracać HTML zamiast oczekiwanego JSON.
4. Referrer-Policy: ogranicz wyciek adresu źródłowego
Referrer-Policy określa, ile informacji z adresu bieżącej strony może zostać przesłane do kolejnego zasobu w nagłówku Referer.
Rozsądny domyślny wariant:
Referrer-Policy: strict-origin-when-cross-origin
Zachowanie:
- pełny adres przy żądaniach same-origin,
- tylko origin przy żądaniach cross-origin,
- brak referrera przy przejściu z HTTPS do HTTP.
Bardziej restrykcyjne opcje:
Referrer-Policy: no-referrer
albo:
Referrer-Policy: same-origin
Wybór zależy od analityki, afiliacji, systemów płatniczych i logiki partnerów. Nie umieszczaj sekretów, tokenów, adresów e-mail ani danych osobowych w URL - nawet najbardziej restrykcyjny Referrer-Policy nie rozwiązuje wszystkich miejsc, w których URL może zostać zapisany.
5. Ochrona przed clickjackingiem: frame-ancestors i X-Frame-Options
Najbardziej elastyczną kontrolę osadzania zapewnia CSP:
Content-Security-Policy: frame-ancestors 'none'
lub:
Content-Security-Policy: frame-ancestors 'self' https://portal.partner.example
frame-ancestors określa, które dokumenty nadrzędne mogą osadzić stronę w <frame>, <iframe>, <object> lub <embed>.
Dla kompatybilności można równolegle dodać:
X-Frame-Options: DENY
albo:
X-Frame-Options: SAMEORIGIN
MDN rekomenduje korzystanie z frame-ancestors, ponieważ daje szersze możliwości niż X-Frame-Options. Wartość ALLOW-FROM jest przestarzała i nowoczesne przeglądarki mogą zignorować cały nagłówek.
X-Frame-Options musi być wysłany jako nagłówek HTTP. Umieszczenie go w <meta http-equiv> nie działa.
6. Permissions-Policy: wyłącz funkcje, których strona nie potrzebuje
Przykład:
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()
Nagłówek pozwala kontrolować dostęp dokumentu i osadzonych iframe’ów do funkcji przeglądarki, takich jak kamera, mikrofon, geolokalizacja czy wybrane API urządzenia.
Można zezwolić własnej stronie:
Permissions-Policy: geolocation=(self), camera=(), microphone=()
albo konkretnemu originowi:
Permissions-Policy: geolocation=(self "https://maps.example")
Nie kopiuj długiej listy wszystkich możliwych dyrektyw. Część z nich jest eksperymentalna albo ma różny poziom wsparcia w przeglądarkach. Najpierw określ, które funkcje rzeczywiście wykorzystuje aplikacja, a następnie wyłącz pozostałe istotne możliwości.
7. COOP, COEP i CORP: izolacja cross-origin, ale nie dla każdej strony
Te trzy nagłówki często pojawiają się razem, lecz rozwiązują różne problemy.
Cross-Origin-Opener-Policy
Cross-Origin-Opener-Policy: same-origin
COOP kontroluje, czy nowy dokument otwarty przez window.open() lub nawigację może znajdować się w tej samej grupie kontekstów przeglądania. same-origin rozdziela dokument od cross-origin openerów i pomaga ograniczać klasę ataków XS-Leaks.
Może jednak przerwać:
- logowanie OAuth przez popup,
- płatności otwierane w nowym oknie,
- integracje, które oczekują dostępu do
window.opener, - komunikację z zaufanym popupem.
Dla niektórych takich procesów właściwsze może być:
Cross-Origin-Opener-Policy: same-origin-allow-popups
Cross-Origin-Embedder-Policy
Cross-Origin-Embedder-Policy: require-corp
COEP wymaga, aby zasoby cross-origin ładowane w trybie no-cors jawnie zezwalały na osadzenie przez CORP albo były pobierane w trybie CORS. Brak odpowiedniego nagłówka może zablokować obrazy, fonty, skrypty, iframe’y i inne zasoby third-party.
Alternatywa:
Cross-Origin-Embedder-Policy: credentialless
pozwala na część żądań no-cors bez jawnego CORP, ale usuwa credentials, w tym cookies.
Cross-Origin-Resource-Policy
Cross-Origin-Resource-Policy: same-origin
CORP określa, które originy mogą odczytać odpowiedź zasobu w żądaniach no-cors:
same-origin,same-site,cross-origin.
To polityka konkretnego zasobu, a nie całej komunikacji CORS. MDN ostrzega również o problemie z renderowaniem części plików PDF w Chrome przy niektórych zastosowaniach CORP, dlatego nagłówka nie należy dodawać globalnie bez testów.
Kiedy potrzebna jest cross-origin isolation?
Połączenie:
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
jest wymagane do cross-origin isolation używanego przez wybrane zaawansowane API, między innymi pełny dostęp do SharedArrayBuffer. Nie wdrażaj go jednak tylko w celu zdobycia dodatkowego punktu w skanerze. Najpierw zinwentaryzuj wszystkie zewnętrzne zasoby i procesy popup.
8. Bezpieczne cookies i Cache-Control
Choć Set-Cookie i Cache-Control nie zawsze są klasyfikowane jako „security headers”, ich konfiguracja ma bezpośredni wpływ na ochronę sesji i danych.
Cookie sesyjne
Set-Cookie: __Host-session=RANDOM_VALUE; Path=/; Secure; HttpOnly; SameSite=Lax
Secureogranicza wysyłanie cookie do HTTPS,HttpOnlyblokuje odczyt przez JavaScript,SameSiteogranicza przesyłanie w żądaniach cross-site,- prefiks
__Host-wymagaSecure,Path=/i braku atrybutuDomain, dzięki czemu cookie jest silniej związane z hostem.
SameSite=Strict jest bezpieczniejsze, ale może utrudniać powrót z logowania, płatności lub linków cross-site. SameSite=None wymaga Secure i powinno być używane tylko wtedy, gdy cookie naprawdę musi działać w kontekście cross-site.
Odpowiedzi wrażliwe
Cache-Control: no-store
no-store informuje cache prywatne i współdzielone, aby nie przechowywały odpowiedzi. Dla spersonalizowanych treści, które mogą być przechowywane w przeglądarce, ale nie w cache współdzielonym, odpowiednie może być:
Cache-Control: private, no-cache
MDN zaleca jawne private dla spersonalizowanych odpowiedzi, ponieważ brak właściwej polityki może doprowadzić do zapisania treści w cache współdzielonym.
9. Usuń informacje o stosie technologicznym
Nagłówki takie jak:
Server: nginx/1.24.0
X-Powered-By: PHP/8.4
X-AspNet-Version: 4.0.30319
ułatwiają fingerprinting. Ich usunięcie nie ukryje technologii przed zdeterminowanym atakującym, ale eliminuje bezpośrednie ujawnianie wersji.
Dobra praktyka:
- usuń
X-Powered-By, - wyłącz nagłówki wersji frameworka,
- ogranicz szczegółowość
Server, - nie dodawaj fałszywej, wprowadzającej w błąd wersji,
- nie zakładaj, że samo ukrycie nagłówka naprawia podatności.
OWASP zaleca usuwanie X-Powered-By i nieinformacyjne wartości Server, podkreślając jednocześnie, że stos można rozpoznać innymi metodami.
10. Nagłówki przestarzałe i błędne zalecenia
X-XSS-Protection
Nie włączaj:
X-XSS-Protection: 1; mode=block
OWASP ostrzega, że stary filtr XSS może w niektórych sytuacjach tworzyć podatności w bezpiecznej stronie. Rekomendacja to brak nagłówka lub jawne wyłączenie:
X-XSS-Protection: 0
Ochronę należy budować przez CSP, kodowanie outputu i bezpieczne API.
Expect-CT
Expect-CT jest w praktyce przestarzały, ponieważ nowoczesne klienty wymagają Certificate Transparency dla aktualnych certyfikatów. MDN określa go jako w większości obsolete od czerwca 2021 roku.
Public-Key-Pins
HPKP nie powinien być wdrażany. Błędny pin mógł długotrwale odciąć domenę od użytkowników, a mechanizm został usunięty z nowoczesnych przeglądarek. Korzystaj z poprawnego TLS, automatycznego odnawiania, CAA, monitoringu certyfikatów i ewentualnie HSTS preload po analizie.
Report-To
Stary nagłówek:
Report-To: { ... }
jest przestarzały. Do deklarowania endpointów należy używać:
Reporting-Endpoints: csp="https://example.com/reports/csp"
Access-Control-Allow-Origin: * jako „nagłówek bezpieczeństwa”
CORS nie jest zestawem nagłówków, które należy dodawać globalnie. Access-Control-Allow-Origin rozluźnia Same-Origin Policy dla wskazanych żądań. Dla API z credentials nie można łączyć wildcard * z dostępem uwierzytelnionym. Zezwalaj wyłącznie wymaganym originom i waliduj je po stronie serwera.
11. Przykładowe konfiguracje serwera
Nginx
add_header Content-Security-Policy "default-src 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'none'; form-action 'self'; img-src 'self' data: https:; style-src 'self'; script-src 'self'; connect-src 'self'; upgrade-insecure-requests" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header X-Frame-Options "DENY" always;
Opcja always jest ważna, aby nagłówki pojawiały się również dla odpowiedzi błędów i innych kodów, nie tylko wybranych odpowiedzi 2xx/3xx.
Apache
<IfModule mod_headers.c>
Header always set Content-Security-Policy "default-src 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'none'; form-action 'self'; img-src 'self' data: https:; style-src 'self'; script-src 'self'; connect-src 'self'; upgrade-insecure-requests"
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set X-Content-Type-Options "nosniff"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
Header always set X-Frame-Options "DENY"
</IfModule>
PHP
<?php
header("Content-Security-Policy: default-src 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'none'; form-action 'self'; img-src 'self' data: https:; style-src 'self'; script-src 'self'; connect-src 'self'; upgrade-insecure-requests");
header("Strict-Transport-Security: max-age=31536000; includeSubDomains");
header("X-Content-Type-Options: nosniff");
header("Referrer-Policy: strict-origin-when-cross-origin");
header("Permissions-Policy: camera=(), microphone=(), geolocation=()");
header("X-Frame-Options: DENY");
Nagłówki muszą zostać wysłane przed treścią odpowiedzi. Dla nonce generuj kryptograficznie losową wartość osobno dla każdego requestu.
Node.js / Express bez zależności
app.use((req, res, next) => {
res.setHeader(
"Content-Security-Policy",
"default-src 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'none'; form-action 'self'; img-src 'self' data: https:; style-src 'self'; script-src 'self'; connect-src 'self'; upgrade-insecure-requests"
);
res.setHeader(
"Strict-Transport-Security",
"max-age=31536000; includeSubDomains"
);
res.setHeader("X-Content-Type-Options", "nosniff");
res.setHeader("Referrer-Policy", "strict-origin-when-cross-origin");
res.setHeader(
"Permissions-Policy",
"camera=(), microphone=(), geolocation=()"
);
res.setHeader("X-Frame-Options", "DENY");
res.removeHeader("X-Powered-By");
next();
});
W aplikacji korzystającej z CDN, WebSocketów, map, płatności albo OAuth powyższy CSP trzeba rozszerzyć. Nie dodawaj 'unsafe-inline' tylko dlatego, że pierwszy test zakończył się błędami.
12. Jak wdrażać bez awarii?
Etap 1: inwentaryzacja
Spisz:
- wszystkie domeny skryptów, stylów, fontów i obrazów,
- endpointy API i WebSocket,
- iframe’y,
- popupy OAuth i płatności,
- zasoby na CDN,
- pliki przesyłane przez użytkowników,
- subdomeny objęte przyszłym HSTS,
- funkcje przeglądarki, których aplikacja rzeczywiście używa.
Etap 2: obserwacja
- uruchom CSP w
Report-Only, - zbieraj raporty i błędy konsoli,
- testuj wszystkie krytyczne ścieżki,
- testuj mobile i przeglądarki używane przez klientów,
- sprawdź odpowiedzi błędów, redirecty i pliki statyczne.
Etap 3: stopniowe egzekwowanie
- najpierw
object-src,base-uri,frame-ancestorsiform-action, - następnie zasoby statyczne,
- na końcu ścisłe
script-src, - rollout HSTS zaczynaj od krótkiego
max-age, - COOP/COEP testuj osobno na integracjach popup i cross-origin.
Etap 4: monitoring regresji
Dodaj testy w CI, które:
- pobierają reprezentatywne URL,
- weryfikują brak duplikatów nagłówków,
- sprawdzają zgodność wartości,
- wykrywają przypadkowe usunięcie CSP/HSTS,
- potwierdzają poprawne MIME types,
- wykonują test end-to-end logowania i płatności.
13. Jak testować nagłówki?
Najpierw sprawdź odpowiedź bezpośrednio:
curl -I https://example.com/
Dla redirectu i końcowej odpowiedzi:
curl -IL https://example.com/
Dla konkretnego zasobu:
curl -I https://example.com/assets/app.js
Sprawdź:
- czy nagłówki są obecne na stronie głównej, logowaniu, 404 i 500,
- czy CSP nie jest wysłany wielokrotnie z konfliktującymi wartościami,
- czy HSTS pochodzi wyłącznie z odpowiedzi HTTPS,
- czy
Content-Typeodpowiada rzeczywistej treści, - czy CDN lub proxy nie usuwa nagłówków,
- czy nagłówki nie występują wyłącznie na homepage.
Możesz również użyć bezpłatnego Inspektora nagłówków bezpieczeństwa POLPROG, który sprawdza między innymi HSTS, CSP i ochronę przed osadzaniem. Certyfikat oraz DNS sprawdzisz w Inspektorze DNS i SSL, a szerszą analizę SEO, wydajności, dostępności i bezpieczeństwa wykonasz przez Kondycję witryny.
Checklista wdrożenia
CSP
-
default-srcma restrykcyjną wartość. -
object-src 'none'. -
base-urijest ograniczone. -
frame-ancestorsodpowiada rzeczywistemu modelowi osadzania. -
form-actionogranicza cele formularzy. - Skrypty wykorzystują nonce lub hashe, jeśli aplikacja wymaga inline.
- Nonce jest losowy dla każdej odpowiedzi.
- Nie ma nieuzasadnionego
'unsafe-inline'. - Nie ma nieuzasadnionego
'unsafe-eval'. - CSP został najpierw przetestowany w Report-Only.
- Raporty mają rate limiting i ograniczoną retencję.
HTTPS i HSTS
- Wszystkie strony i zasoby działają przez HTTPS.
- HTTP przekierowuje bezpośrednio do HTTPS.
- Certyfikat jest monitorowany.
- Wszystkie subdomeny zostały zinwentaryzowane.
-
max-agezwiększano etapami. -
includeSubDomainsjest bezpieczne dla całej domeny. -
preloadzostał dodany dopiero po analizie konsekwencji.
Pozostałe nagłówki
-
X-Content-Type-Options: nosniff. - Wszystkie odpowiedzi mają właściwy
Content-Type. -
Referrer-Policyjest ustawiony jawnie. -
Permissions-Policywyłącza nieużywane funkcje. -
X-Frame-Optionsnie używaALLOW-FROM. - COOP nie psuje OAuth i płatności.
- COEP nie blokuje zasobów third-party.
- CORP jest dopasowany do konkretnego rodzaju zasobu.
- Cookies sesyjne mają
Secure,HttpOnlyi właściweSameSite. - Wrażliwe odpowiedzi mają właściwy
Cache-Control. -
X-Powered-Byi wersje frameworków są usunięte. -
X-XSS-Protectionjest wyłączony albo nieobecny. -
Expect-CT, HPKP i staryReport-Tozostały usunięte.
Werdykt
Dla większości stron firmowych i aplikacji właściwa kolejność jest następująca:
- Poprawne HTTPS, typy MIME i bezpieczne cookies.
- CSP dopasowany do aplikacji i wdrażany przez Report-Only.
- HSTS wdrażany etapami.
nosniff, Referrer-Policy, Permissions-Policy i ochrona przed framingiem.- COOP, COEP i CORP tylko wtedy, gdy model cross-origin jest dobrze zrozumiany.
- Usunięcie przestarzałych oraz informacyjnych nagłówków.
Najlepszy zestaw nagłówków nie jest najdłuższym zestawem. Jest najmniejszą polityką, która rzeczywiście odpowiada architekturze aplikacji, została przetestowana na krytycznych ścieżkach i jest monitorowana po każdym wdrożeniu.

