Security headers: HSTS, CSP, X-Frame-Options i inne
· 7 min czytania
Backend to forteca, ale druga połowa obrony jest w przeglądarce. HSTS, CSP i inne nagłówki blokują XSS, clickjacking i MITM - i są darmowe.
Dlaczego mają znaczenie
Aplikacja może być doskonale zabezpieczona po stronie backendu, a mimo to pozostawać podatna na ataki po stronie przeglądarki: cross-site scripting (XSS), clickjacking, protocol downgrade, MIME confusion. Security headers przesuwają obronę do samej przeglądarki.
Strict-Transport-Security (HSTS)
Wymusza HTTPS dla wszystkich przyszłych odwiedzin. Po pierwszej wizycie przez HTTPS przeglądarka zapamiętuje domenę i sama przepisuje każdy link http:// na https://, nawet jeśli użytkownik kliknie zły odnośnik.
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
max-age=63072000= obowiązuje 2 lataincludeSubDomains= reguła obowiązuje też dla wszystkich subdomen; wymusza HTTPS wszędzie, więc jeśli masz subdomenę działającą tylko przez HTTP, np.staging.example.com, stanie się niedostępna w przeglądarcepreload= pozwala na włączenie do listy HSTS preload wbudowanej w Chrome / Firefox / Safari
Uwaga:
Usunięcie HSTS z preload z listy trwa 6+ miesięcy. Nie włączaj preload, zanim nie zweryfikujesz, że HTTPS działa stabilnie również na wszystkich subdomenach.
Content-Security-Policy (CSP)
Najmocniejszy, ale zarazem najtrudniejszy do skonfigurowania nagłówek. Whitelistuje, skąd przeglądarka może ładować skrypty, style, obrazy i iframe'y. Bez CSP atakujący, który potrafi wstrzyknąć tag <script>, może uruchomić dowolny JS; z CSP tylko kod z zatwierdzonych źródeł.
Content-Security-Policy: default-src 'self'; script-src 'self' 'sha256-...'; img-src 'self' data: https://cdn.example.com; style-src 'self' 'unsafe-inline'; frame-ancestors 'none'
Częste dyrektywy:
default-src 'self'= domyślnie pozwól tylko na zasoby z mojej domenyscript-src= źródła JS (dla skryptów inline podaj hash lub nonce)style-src= źródła CSSimg-src= obrazyconnect-src= AJAX, WebSocket, EventSourceframe-ancestors 'none'= nikt nie może osadzić strony w iframe (lepsze niż X-Frame-Options)report-uri /csp-report= przeglądarka wysyła JSON przy każdej violation (ty łapiesz ją w backendzie i logujesz)- Uwaga:
report-urijest dziś deprecated - przeglądarki obsługującereport-togo ignorują. Nowoczesny sposób to dyrektywareport-toplus osobny nagłówekReporting-Endpoints;report-urizostaw tylko jako fallback dla Firefoksa, który nie obsługuje jeszczereport-to.
X-Frame-Options
Starsza alternatywa dla frame-ancestors. Chroni przed clickjackingiem, w którym atakujący osadza twoją stronę jako iframe i nakłada na nią niewidzialne przyciski.
X-Frame-Options: DENY
Wartości: DENY (nikt), SAMEORIGIN (tylko moja domena), ALLOW-FROM uri (deprecated).
X-Content-Type-Options
X-Content-Type-Options: nosniff
Wyłącza MIME sniffing, dzięki czemu przeglądarka respektuje Content-Type zwrócony przez serwer. Bez tego atakujący może wgrać plik z błędnym typem (np. obraz, który w rzeczywistości jest HTML ze skryptem) i przeglądarka może go uruchomić jako stronę WWW.
Referrer-Policy
Referrer-Policy: strict-origin-when-cross-origin
Kontroluje, ile informacji o poprzedniej stronie przeglądarka wysyła w nagłówku Referer przy kliknięciu. Domyślna wartość w nowoczesnych przeglądarkach to już strict-origin-when-cross-origin, ale jawne ustawienie nagłówka gwarantuje spójne zachowanie.
Permissions-Policy
Wyłącza API, których nie potrzebujesz, takie jak kamera, mikrofon, GPS i geolokalizacja. Atakujący wykorzystujący XSS nie może zażądać tych API.
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()
Praktyczna konfiguracja w nginx
server {
listen 443 ssl http2;
server_name example.com;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
# preload celowo tu pominęliśmy - dodaj go dopiero gdy masz 100% pewność (zob. pułapka z preload powyżej)
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
# CSP jest rozległa - zdefiniuj ją według swojej aplikacji
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; ..." always;
}
Kluczowe jest always - bez niego nginx pomija nagłówki przy odpowiedziach błędu (4xx, 5xx).
Audyt aktualnego stanu
Najprościej za pomocą narzędzia online. Nasz header check pokaże ci, których nagłówków brakuje i które są niewłaściwe. Do dokładnego audytu securityheaders.com również daje ocenę A-F.
Wnioski
Security headers należą do najlepszych inwestycji w bezpieczeństwo pod względem stosunku wysiłku do zysku: typowo pół godziny konfiguracji w reverse proxy przeciwko całej kategorii ataków po stronie przeglądarki. Audyt raz na pół roku w ramach regularnej konserwacji to rozsądne minimum.
Bezpłatny audyt security headers
Bez rejestracji, wynik w trzy sekundy.
Wypróbuj ePulz.io za darmo - 7 dni bez karty kredytowej.
Utwórz konto