HTTP bezpečnostné hlavičky: Jednoduchý spôsob, ako posilniť vaše webové aplikácie

HTTP bezpečnostné hlavičky: Jednoduchý spôsob, ako posilniť vaše webové aplikácie

Moderné prehliadače a servery poskytujú účinné bezpečnostné mechanizmy prostredníctvom HTTP hlavičiek. Nastavíte ich raz a prehliadač bude politiku vynucovať pri každej požiadavke. Zablokujete celé triedy útokov ešte pred spustením aplikačného kódu. Patrí sem clickjacking, cross-site scripting, MIME sniffing, nezabezpečený prenos, úniky údajov medzi odlišnými pôvodmi a slabé spracovanie relácií. Hlavičky dopĺňajú validáciu vstupov, kódovanie výstupov a autentifikáciu. Sú v súlade s rizikami OWASP Top 10 a znižujú odchýlky spôsobené nesprávnou konfiguráciou naprieč stackmi.

Čo pre vás tieto hlavičky robia

  • Vynucujú HTTPS a zastavujú downgrade útoky pomocou HSTS.
  • Obmedzujú, odkiaľ sa môžu načítať skripty, štýly a iné zdroje, pomocou Content-Security-Policy (CSP).
  • Blokujú clickjacking riadením, kde sa môže váš web vkladať do rámcov, pomocou direktívy frame-ancestors (je súčasťou CSP a nahrádza staršiu hlavičku X-Frame-Options).
  • Vypínajú MIME sniffing pomocou X-Content-Type-Options.
  • Obmedzujú odosielanie údajov o odkazujúcej stránke pomocou Referrer-Policy.
  • Riadiace prístup k výkonným funkciám prehliadača pomocou Permissions-Policy.
  • Dosahujú izoláciu medzi pôvodmi pomocou COOP, COEP a CORP, keď to vyžaduje súbor funkcií.
  • Riadiace legitímny prístup k API z iných pôvodov pomocou CORS a overenie zámeru cez Fetch Metadata.
  • Chránia relácie pomocou súborov cookie Secure, HttpOnly a SameSite.
  • Overujú prostriedky CDN pomocou Subresource Integrity.

Ako s nimi pracovať

  • Vnímajte hlavičky ako konfiguráciu v kóde. Majte ich vo verziovacom systéme.
  • Nasadzujte najprv s report-only a kanárikovými trasami, potom vynucujte.
  • Validujte v CI pomocou kontrol cez curl a dôveryhodných skenerov.
  • Použite DAST na potvrdenie správania v stagingu a produkcii.
  • Revídujte politiky pri pridávaní nových skriptov tretích strán, nových API alebo funkcií.

TLDR

  • Začnite s CSP v režime Report-Only. Použite default-src 'self', nonce pre vložené skripty a frame-ancestors 'self'. Nechajte reportovanie zapnuté.
  • Zapnite HTTP Strict Transport Security po náprave HTTPS. Použite max-age=31536000; includeSubDomains. preload pridajte až vtedy, keď ste pripravení na každý subdomén.
  • Prestaňte používať HPKP, X-XSS-Protection a Expect-CT. Namiesto toho používajte HSTS a CSP.
  • Nastavte Referrer-Policy: strict-origin-when-cross-origin. no-referrer použite pri práci s citlivými údajmi.
  • Izoláciu medzi pôvodmi zapínajte len v prípade potreby. Použite COOP: same-origin a COEP: require-corp alebo credentialless. Pridajte CORP na svoje prostriedky.
  • Vždy posielajte X-Content-Type-Options: nosniff.
  • Uzamknite súbory cookie pomocou Secure; HttpOnly; SameSite=Lax alebo Strict. SameSite=None; Secure používajte iba pre súbory cookie tretích strán.
  • Používajte allowlisty CORS. Nikdy nekombinujte * s povereniami. Preflight cacheujte s krátkym Access-Control-Max-Age.
  • Pridajte kontroly Fetch Metadata na koncové body meniacie stav. Rýchlo odmietajte nebezpečné metódy cross-site.
  • Používajte Subresource Integrity pre skripty a štýly z CDN.

Hlavné hlavičky, bezpečné predvolené hodnoty a príklady

Content-Security-Policy (CSP)

Účel: obmedziť, odkiaľ môže vaša stránka načítať skripty, štýly, obrázky, rámce a ďalšie. Zmierňuje XSS a vkladanie údajov.

Bezpečný východiskový bod

Content-Security-Policy: default-src 'self'; base-uri 'self'; object-src 'none';
script-src 'self' 'nonce-{RANDOM}';
style-src 'self';
img-src 'self' data:;
frame-ancestors 'self';
upgrade-insecure-requests

Report-Only počas ladenia

Reporting-Endpoints: csp="https://example.com/csp-reports"
Content-Security-Policy-Report-Only: default-src 'self'; base-uri 'self'; object-src 'none'; script-src 'self' 'nonce-{RANDOM}'; style-src 'self'; img-src 'self' data:; frame-ancestors 'self'; upgrade-insecure-requests; report-to csp; report-uri https://example.com/csp-legacy

Nastavenie Reporting API

Report-To: {"group":"csp-endpoint","max_age":10886400,"endpoints":[{"url":"https://example.com/csp-reports"}],"include_subdomains":true}

Poznámka: Použite report-to (moderné Reporting API) ako primárne. report-uri ponechajte iba kvôli podpore starších prehliadačov počas prechodu.

Tipy

  • Uprednostnite nonce pre vložené bootstrap skripty. Generujte náhodný nonce pre každú odpoveď.
  • Nahraďte X-Frame-Options direktívou frame-ancestors.
  • report-uri si ponechajte pre staršie prehliadače.
  • Použite report-to pre moderné Reporting API. Hodnota csp-endpoint musí zodpovedať názvu skupiny definovanému v samostatnej HTTP hlavičke Report-To.

Kontrolný zoznam nasadenia

  • Začnite s Content-Security-Policy-Report-Only na všetkých stránkach.
  • Generujte nový kryptograficky náhodný nonce pre každú odpoveď. Neopakujte ho medzi požiadavkami.
  • Odstráňte vložené obsluhy udalostí a eval. Nahraďte ich skriptmi, ktoré používajú nonce stránky.
  • Explicitne uveďte hostiteľov skriptov tretích strán. Vyhnite sa zástupným znakom a data: pre skripty.
  • Pridajte frame-ancestors 'self' aj vtedy, ak si myslíte, že rámce nepoužívate.
  • Ponechajte object-src 'none'. Zásuvné moduly by v roku 2025 nemali byť potrebné.
  • Prepnite na vynucovanie CSP, keď sa porušenia stabilizujú, a ponechajte reportovanie zapnuté.

Stratégia pre skripty tretích strán

  • Ak je to možné, uprednostnite serverové alebo tag managerom hostované zrkadlá prvej strany.
  • Pre analytiku povoľte iba presné pôvody a potrebné direktívy. Blokujte connect-src na neznámych hostiteľov.
  • Rotujte nonce a nepovoľujte 'unsafe-inline' ani 'unsafe-eval'.

CSP porovnanie

NázovÚčelKritické direktívyPríklad hodnotyPodpora v prehliadačochRiziko nefunkčnostiPoznámky k nástrojom
Content-Security-PolicyPolitika izolácie obsahu na strane klienta, ktorá obmedzuje sťahovanie zdrojov a vykonávacie kontexty na deklarované pôvody, čím zmierňuje odrazené, uložené a DOM-založené XSS, vkladanie aktívneho obsahu a UI útoky pomocou frame-ancestorsdefault-src, script-src s nonce, frame-ancestors, object-src 'none', upgrade-insecure-requestsPozri politiku vyššieChrome 25+, Edge 12+, Firefox 23+, Safari 7+, Opera 15+, iOS Safari 6+, IE 10–11 čiastočne cez X-Content-Security-PolicyStredné až vysoké. Vložené skripty bez nonce alebo hashu sú blokované, nedeklarovaní hostitelia tretích strán sa nenačítajú, konštrukcie typu eval prestanú fungovať a staršie tag managery či vložené obsluhy udalostí nebudú pracovaťPoužite Reporting API a počas migrácie ponechajte report-uri

HTTP Strict-Transport-Security (HSTS)

Účel: vynútiť HTTPS. Blokovať HTTP a pokusy o obchádzanie neplatným TLS.

Strict-Transport-Security: max-age=31536000; includeSubDomains

Preload

  • preload pridajte iba vtedy, keď každá subdoména používa HTTPS a bude ho používať aj naďalej. Keď ste si istí, môžete svoj doménový názov odoslať do oficiálneho zoznamu preload na hstspreload.org (otvorí sa v novom okne).
  • Vrátenie späť je pomalé a rizikové.

Upozornenie: HSTS preload je z praktického hľadiska trvalý. Odstránenie zo zoznamov preload v prehliadačoch môže trvať 6–12 mesiacov a vyžaduje koordináciu so všetkými hlavnými prehliadačmi. Odosielajte na hstspreload.org (otvorí sa v novom okne) až po splnení:

  • Všetky subdomény majú platné HTTPS (vrátane interných nástrojov)
  • Nikde neexistuje HTTP fallback
  • Máte zdokumentované obchodné schválenie trvalého vynucovania HTTPS

Kontrolný zoznam pripravenosti na preload

  • Každá subdoména poskytuje HTTPS s platnými certifikátmi.
  • Trvalé 301 presmerovanie z HTTP na HTTPS je nastavené pre všetkých hostiteľov.
  • Žiadne interné ani zdedené systémy nevyžadujú čisté HTTP.
  • Nastavte max-age aspoň na 31536000 a zapnite includeSubDomains na dva týždne pred odoslaním.
  • Zdokumentujte plán návratu. Odstránenie z preloadu trvá čas a nedá sa urobiť okamžite.

HSTS porovnanie

NázovÚčelKritické direktívyPríklad hodnotyPodpora v prehliadačochRiziko nefunkčnostiPoznámky k nástrojom
HSTSPolitika bezpečnosti prenosu, ktorá inštruuje používateľské agenty, aby automaticky upgradovali HTTP na HTTPS a fixovali len HTTPS pre pôvod, čím bránia downgrade protokolu a SSL strippingmax-age, includeSubDomains, voliteľne preloadmax-age=31536000; includeSubDomainsChrome 4+, Edge 12+, Firefox 4+, Safari 7+, Opera 12+, IE 11 na Windows 8.1 alebo Windows 7 s KB3058515Vysoké, ak akákoľvek subdoména alebo zdedený endpoint stále poskytuje HTTP alebo prezentuje neplatné TLS, pretože prehliadač tieto navigácie tvrdohlavo zlyháNajprv otestujte presmerovania a certifikáty

Referrer-Policy

Účel: riadiť, koľko informácií o odkazujúcej stránke odosielate.

Predvolené

Referrer-Policy: strict-origin-when-cross-origin

Pre maximálne súkromie použite no-referrer.

Referrer-Policy porovnanie

NázovÚčelKritické direktívyPríklad hodnotyPodpora v prehliadačochRiziko nefunkčnostiPoznámky k nástrojom
Referrer-PolicyKontrola súkromia požiadaviek, ktorá obmedzuje granularitu hlavičky Referer pri navigáciách v rámci rovnakého aj odlišného pôvodu a pri sťahovaní podzdrojov, čím znižuje únik informácií o pôvode a cesteJeden token, napríklad no-referrer, strict-origin-when-cross-originstrict-origin-when-cross-originChrome 61+, Edge 79+, Firefox 52+, Safari 11.1+, Opera 48+, iOS Safari 12+Nízke. Niektoré analytiky, A/B smerovanie alebo platobné callbacky spoliehajúce sa na plnú cestu v referreroch môžu mať zníženú viditeľnosťSkontrolujte analytiky závislé od plných referrerov

Permissions-Policy

Účel: riadiť prístup k funkciám, ako sú geolokácia, kamera a mikrofón.

Prísne predvolené nastavenie

Permissions-Policy: geolocation=(), camera=(), microphone=()

Kroky auditu

  • Prehľadajte svoj kód na API funkcionalít.
  • Použite DevTools na zobrazenie výziev a blokovaných funkcií.
  • Otvorené politiky aplikujte na trasy, ktoré ich potrebujú.

Bežne obmedzované funkcie

  • geolocation=(), camera=(), microphone=() pre stránky, ktoré ich nikdy nepoužívajú.
  • payment=() a usb=() pre verejné marketingové stránky.
  • fullscreen=(self) pre aplikácie používajúce prehliadače médií.

Permissions-Policy porovnanie

NázovÚčelKritické direktívyPríklad hodnotyPodpora v prehliadačochRiziko nefunkčnostiPoznámky k nástrojom
Permissions-PolicyPolitika obmedzovania funkcií, ktorá povoľuje alebo zamieta výkonné schopnosti prehliadača podľa pôvodu a kontextu vkladania, a presadzuje princíp najmenších práv pre API ako geolokácia, kamera a mikrofónZoznamy povolených podľa funkciígeolocation=(), camera=(), microphone=()Chrome 88+, Edge 88+, Opera 74+, Firefox nepodporované, Safari nepodporovanéNízke až stredné. Stránky alebo iframy, ktoré sa implicitne spoliehali na výzvy, uvidia zamietnutie schopností, kým nebudú explicitne povolenéNastavujte podľa potreby na úrovni trasy

X-Content-Type-Options

Účel: zastaviť MIME sniffing. Zabraňuje tomu, aby prehliadač hádal typ obsahu, čo môže byť nebezpečné (napr. ak súbor vyzerá ako skript, môže vykonať textový súbor nahraný používateľom).

Hodnota

X-Content-Type-Options: nosniff

X-Content-Type-Options porovnanie

NázovÚčelKritické direktívyPríklad hodnotyPodpora v prehliadačochRiziko nefunkčnostiPoznámky k nástrojom
X-Content-Type-OptionsDirektíva presadzovania MIME, ktorá vypína sniffing obsahu pre odpovede skriptov a štýlov, a vyžaduje správny Content-Type na vykonanienosniffnosniffChrome 64+, Edge 12+, Firefox 50+, Safari 11+, Opera 51+, IE 8+Nízke, ak sú všetky prostriedky poskytované so správnymi MIME typmi. Nesprávne typované zdroje budú zablokovanéPoskytujte správny Content-Type

COOP, COEP, CORP

Účel: izolovať vašu aplikáciu od iných pôvodov a blokovať úniky medzi stránkami. Vyžadované pre niektoré pokročilé funkcie, ako je SharedArrayBuffer.

Clear-Site-Data: "cache", "cookies", "storage"  # Use on logout endpoints
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Resource-Policy: same-origin

Poznámky

  • COEP: credentialless môže zjednodušiť načítanie zdrojov tretích strán bez poverení. Najprv overte podporu.
  • Pred nasadením auditujte vloženia a použitie postMessage.

Kedy použiť izoláciu medzi pôvodmi

  • Potrebujete SharedArrayBuffer alebo výkonnostné API, ktoré vyžadujú izoláciu.
  • Chcete silnejšiu ochranu proti únikom medzi stránkami a komunikácii v popup oknách.

Riešenie problémov

  • Zlyhanie načítania obrázkov, písiem alebo WASM zvyčajne znamená chýbajúce CORP. Pridajte Cross-Origin-Resource-Policy: same-origin na svoje prostriedky alebo ich servujte z rovnakého pôvodu.
  • Widgety tretích strán sa nemusia dať vkladať pri COEP. Hostujte ich ako prvá strana alebo použite credentialless, ak je podporované.

COOP, COEP, CORP porovnanie

NázovÚčelKritické direktívyPríklad hodnotyPodpora v prehliadačochRiziko nefunkčnostiPoznámky k nástrojom
COOPIzolácia skupiny prehliadacích kontextov, ktorá umiestni stránku do samostatnej skupiny od dokumentov iného pôvodu, čím zmierňuje úniky údajov medzi oknami a niektoré XS-Leakssame-originsame-originChrome 83+, Edge 83+, Firefox 79+, Safari 15.2+, Opera 69+Stredné. Referencie na okná iného pôvodu, vzťahy opener a toky postMessage predpokladajúce rovnakú skupinu môžu prestať fungovaťAuditujte postMessage a window.open
COEPPolitika vkladania, ktorá vyžaduje, aby zdroje iného pôvodu explicitne povolili vloženie cez CORP alebo CORS, čím umožňuje izoláciu medzi pôvodmi a blokuje nepriehľadné no-cors vloženiarequire-corp alebo credentiallessrequire-corpChrome 83+, Edge 83+, Opera 69+, Firefox nepodporované, Safari nepodporovanéStredné až vysoké. Zdroje tretích strán bez hlavičiek CORP alebo CORS sa nenačítajú, vrátane písiem, obrázkov a WASMPridajte CORP na svoje prostriedky
CORPPolitika ochrany zdrojov, ktorá deklaruje, ktoré pôvody môžu zdroj vkladať v no-cors kontextoch, čím bráni neautorizovanému využitiu z iného pôvodusame-origin, same-site, cross-originsame-originChrome 73+, Edge 79+, Firefox 74+, Safari nepodporované, iOS Safari nepodporovanéNízke až stredné. Odberatelia z iného webu bez povoleného vzťahu nenačítajú chránené zdrojeNastavujte na statické zdroje

Cross-Origin Resource Sharing (CORS)

Účel: povoliť špecifické požiadavky medzi odlišnými pôvodmi.

Bezpečný príklad

# Preflight (OPTIONS)
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 600
Vary: Origin, Access-Control-Request-Method, Access-Control-Request-Headers

# Simple/actual response
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Credentials: true
Vary: Origin

Access-Control-Expose-Headers: Content-Length, X-Request-ID
Cross-Origin-Resource-Policy: same-origin

Preflight

  • Prehliadače posielajú OPTIONS na kontrolu politiky.
  • Cacheujte s krátkym Access-Control-Max-Age.

Pravidlá pre požiadavky s povereniami

  • Nepoužívajte * s povereniami. Odozvite povolený pôvod zo zoznamu povolených.
  • Vždy nastavte Vary: Origin, keď sa odpovede líšia podľa pôvodu.
  • Povoľte iba nevyhnutné metódy a hlavičky. Vyhnite sa širokému Access-Control-Allow-Headers: *.

Úskalia cacheovania preflight

  • V produkcii držte Access-Control-Max-Age striedmo, napríklad 600 sekúnd, aby sa zmeny politík prejavili rýchlo.
  • CDN môžu cachovať OPTIONS. Obíďte alebo ohraničte cache pre preflight cesty.

CORS porovnanie

NázovÚčelKritické direktívyPríklad hodnotyPodpora v prehliadačochRiziko nefunkčnostiPoznámky k nástrojom
CORS hlavičkyRámec autorizácie požiadaviek medzi pôvodmi, ktorý určuje, ktoré pôvody, metódy a hlavičky môžu pristupovať k chráneným zdrojom cez fetch/XHR, vrátane preflight vyjednávaniaAccess-Control-Allow-Origin, Access-Control-Allow-Methods, Access-Control-Allow-Headers, Access-Control-Allow-Credentials, Access-Control-Max-AgePozri príkladChrome 4+, Edge 12+, Firefox 3.5+, Safari 4+, Opera 12.1+, IE 10+Stredné. Nesprávne zoznamy povolených, chýbajúce Vary alebo zle ohraničené povolené hlavičky blokujú legitímnych klientov alebo umožnia nesúlad cacheovaných politíkVždy nastavte Vary: Origin

Fetch Metadata

Účel: identifikovať kontext požiadavky a blokovať zneužitie naprieč stránkami. Použite na posilnenie obrany proti CSRF.

Náčrt kontroly na serveri

# Pseudocode: reject unsafe, non-navigational cross-site requests
site = get_header("Sec-Fetch-Site")
mode = get_header("Sec-Fetch-Mode")
is_unsafe_method = (method in [POST, PUT, PATCH, DELETE])
is_cross_site = (site == "cross-site")
is_navigational = (mode == "navigate")

# Block requests that are cross-site, unsafe, AND not a top-level navigation
if (is_cross_site && is_unsafe_method && !is_navigational) {
  reject()
}

Príklad middleware pre Express

function fetchMetadataGuard(req, res, next) {
  const site = req.get("Sec-Fetch-Site") || "";
  const mode = req.get("Sec-Fetch-Mode") || "";
  const dest = req.get("Sec-Fetch-Dest") || "";
  const unsafe = ["POST", "PUT", "PATCH", "DELETE"].includes(req.method);
  const allowedSameSite = site === "" || site === "same-origin" || site === "same-site";
  const isNavigation = mode === "navigate" && dest === "document";

  if (unsafe && !allowedSameSite && !isNavigation) return res.sendStatus(403);
  next();
}

Fetch Metadata porovnanie

NázovÚčelKritické direktívyPríklad hodnotyPodpora v prehliadačochRiziko nefunkčnostiPoznámky k nástrojom
Fetch MetadataValidácia kontextu požiadavky, ktorá skúma hlavičky Sec-Fetch-* na rozlíšenie požiadaviek rovnakého pôvodu, rovnakého webu a iného webu, čo umožňuje serverové spevnenie proti CSRF a XS-LeaksSec-Fetch-Site, Sec-Fetch-Mode, Sec-Fetch-Dest, Sec-Fetch-UserOdmietnuť nebezpečné metódy pri cross-siteChrome 76+, Edge 79+, Opera 63+, Firefox nepodporované, Safari nepodporovanéNízke pri zameraní na nebezpečné metódy. Príliš prísne pravidlá môžu blokovať legitímne navigácie medzi webmi alebo OAuth presmerovaniaLogujte odmietnutia na doladenie

Subresource Integrity (SRI)

Účel: zabezpečiť, aby CDN zdroje neboli pozmenené.

Príklad

<script src="https://cdn.example.com/app.js" integrity="sha384-BASE64HASH" crossorigin="anonymous"></script>

Poznámky

  • Pripnite verzie alebo automaticky aktualizujte hash hodnoty.
  • Používajte pre skripty a štýly.

Generovanie a overovanie hashov

  • Generovanie: openssl dgst -sha384 -binary app.js | openssl base64 -A
  • Overenie: SRI vždy otestujte v stagingu pred produkciou. Neplatné hashe = nefunkčný web.
  • Automatizácia: použite build nástroje na generovanie hashov počas nasadzovania

SRI porovnanie

NázovÚčelKritické direktívyPríklad hodnotyPodpora v prehliadačochRiziko nefunkčnostiPoznámky k nástrojom
SRIOverenie integrity podzdrojov, ktoré viaže externé skripty a štýly na kryptografické odtlačky, čím bráni spusteniu pozmenených CDN aktívintegrity, crossoriginPozri príkladChrome 45+, Edge 79+, Firefox 43+, Safari 11+, Opera 32+, iOS Safari 11.3+Stredné. Akákoľvek zmena upstream aktíva bez zodpovedajúcej aktualizácie hash spôsobí tvrdé zlyhanieAutomatizujte aktualizácie hashov

Bezpečné súbory cookie

Účel: chrániť relácie.

Bezpečný príklad

Set-Cookie: session=abc...; Path=/; Secure; HttpOnly; SameSite=Lax

Poznámky

  • Moderné prehliadače pri chýbajúcom SameSite používajú predvolene Lax. Buďte explicitní.
  • SameSite=None; Secure používajte iba pre cookie tretích strán.
  • Nastavte Path=/ len keď je to potrebné. Užšie cesty znižujú vystavenie.
  • Rozsah Domain obmedzte na čo najmenej hostiteľov. Vyhnite sa cookie na superdoméne vo veľkých prostrediach.
  • Rotujte ID relácie pri prihlásení a zmene oprávnení. Pri odhlásení invalidujte.
  • Používajte krátke expirácie pre reláčne cookie. Preferujte serverové úložiská relácií s možnosťou odvolania.

Porovnanie cookie

NázovÚčelKritické direktívyPríklad hodnotyPodpora v prehliadačochRiziko nefunkčnostiPoznámky k nástrojom
Set-CookieOchrana dôvernosti relácie a viacvrstvová obrana proti CSRF cez Secure prenos, neprístupnosť zo skriptu s HttpOnly a cross-site sémantiku so SameSiteSecure, HttpOnly, SameSiteSecure; HttpOnly; SameSite=LaxHttpOnly a Secure podporované všetkými modernými prehliadačmi. SameSite=None vyžaduje Chrome 67+, Edge 16+, Firefox 60+, Safari 13+, iOS Safari 13+Nízke až stredné. Cross-site toky, vložené SSO alebo staršie integrácie tretích strán môžu zlyhať bez SameSite=None; Secure tam, kde je potrebnéPred sprísnením auditujte cross-site toky

Zastaralé alebo neodporúčané hlavičky

HlavičkaOdstránené/Zastarané a odkedyDôvodNáhrada
HTTP Public-Key-Pins (HPKP)Odstránené, 2018-05-29, riziko denial-of-service a nepriateľského pripinovaniaVysoké riziko samospôsobenej uzáveryNahraďte Public-Key-Pins pomocou HSTS preload a Certificate Transparency
X-XSS-ProtectionZastarané, 2019-10, prehliadače ho zrušili, môže vytvárať XSS zraniteľnosti a koliduje s CSPNeúčinné a zavádzajúceNahraďte X-XSS-Protection politikou Content-Security-Policy bez vložených skriptov
Expect-CTZastarané, 2022-11, CT vymáhané Chromiom, hlavička je zastaranáCT je dnes súčasťou ekosystémuNamiesto Expect-CT sa spoliehajte na Certificate Transparency a hlavičku odstráňte
X-Frame-OptionsNahradené moderným mechanizmom, referencia z 2016-12-15 pre adopciu CSP frame-ancestors, obmedzené direktívy a interoperabilitaObmedzená syntax a ovládanieNahraďte X-Frame-Options hlavičkou Content-Security-Policy: frame-ancestors

Konfiguračné postupy

Nginx

# /etc/nginx/conf.d/security.conf
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), camera=(), microphone=()" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Cross-Origin-Opener-Policy "same-origin" always;
add_header Cross-Origin-Embedder-Policy "require-corp" always;
add_header Cross-Origin-Resource-Policy "same-origin" always;

location / {
  set_by_lua_block $csp_nonce {
    local rand = require("resty.random").bytes(16, true)
    return ngx.encode_base64(rand)
  }

  add_header Content-Security-Policy
    "default-src 'self'; base-uri 'self'; object-src 'none'; \
    script-src 'self' 'nonce-$csp_nonce'; style-src 'self'; img-src 'self' data:; \
    frame-ancestors 'self'; upgrade-insecure-requests" always;
}

# CORS example for API
location /api/ {
    if ($request_method = 'OPTIONS') {
        add_header Access-Control-Allow-Origin "https://example.com";
        add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
        add_header Access-Control-Allow-Headers "Content-Type";
        add_header Access-Control-Allow-Credentials "true";
        add_header Access-Control-Max-Age 600;
        return 204;
    }
    add_header Access-Control-Allow-Origin "https://example.com";
    add_header Access-Control-Allow-Credentials "true";
    add_header Vary "Origin";
    proxy_pass http://backend;
}

Apache httpd

# In <VirtualHost> or .htaccess with AllowOverride All
# e.g., SetEnvIfNoCase Request_URI ".*" CSP_NONCE=%{UNIQUE_ID}e
Header always set Content-Security-Policy "default-src 'self'; base-uri 'self'; object-src 'none'; script-src 'self' 'nonce-%{CSP_NONCE}e'; style-src 'self'; img-src 'self' data:; frame-ancestors 'self'; upgrade-insecure-requests"
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "geolocation=(), camera=(), microphone=()"
Header always set X-Content-Type-Options "nosniff"
Header always set Cross-Origin-Opener-Policy "same-origin"
Header always set Cross-Origin-Embedder-Policy "require-corp"
Header always set Cross-Origin-Resource-Policy "same-origin"

# CORS example
<Location /api/>
  Header always set Access-Control-Allow-Origin "https://example.com"
  Header always set Access-Control-Allow-Credentials "true"
  Header always set Vary "Origin"
  RewriteEngine On
  RewriteCond %{REQUEST_METHOD} OPTIONS
  RewriteRule ^ - [R=204,L]
  Header always set Access-Control-Allow-Methods "GET, POST, OPTIONS"
  Header always set Access-Control-Allow-Headers "Content-Type"
  Header always set Access-Control-Max-Age "600"
</Location>

Node.js Express

import express from "express";
import crypto from "crypto";

const app = express();

// CSP nonce per response
app.use((req, res, next) => {
  res.locals.cspNonce = crypto.randomBytes(16).toString("base64");
  next();
});

app.use((req, res, next) => {
  const nonce = res.locals.cspNonce;
  res.setHeader("Content-Security-Policy",
    "default-src 'self'; base-uri 'self'; object-src 'none'; " +
    "script-src 'self' 'nonce-" + nonce + "'; style-src 'self'; img-src 'self' data:; " +
    "frame-ancestors 'self'; upgrade-insecure-requests");
  res.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
  res.setHeader("Referrer-Policy", "strict-origin-when-cross-origin");
  res.setHeader("Permissions-Policy", "geolocation=(), camera=(), microphone=()");
  res.setHeader("X-Content-Type-Options", "nosniff");
  res.setHeader("Cross-Origin-Opener-Policy", "same-origin");
  res.setHeader("Cross-Origin-Embedder-Policy", "require-corp");
  res.setHeader("Cross-Origin-Resource-Policy", "same-origin");
  next();
});

// Fetch Metadata guard
app.use((req, res, next) => {
  const site = req.get("Sec-Fetch-Site");
  const unsafe = ["POST","PUT","PATCH","DELETE"].includes(req.method);
  if (site === "cross-site" && unsafe) return res.status(403).end();
  next();
});

// CORS allowlist example
app.use("/api", (req, res, next) => {
  const origin = req.get("Origin");
  if (origin === "https://example.com") {
    res.setHeader("Access-Control-Allow-Origin", origin);
    res.setHeader("Access-Control-Allow-Credentials", "true");
    res.setHeader("Vary", "Origin");
  }
  if (req.method === "OPTIONS") {
    res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
    res.setHeader("Access-Control-Allow-Headers", "Content-Type");
    res.setHeader("Access-Control-Max-Age", "600");
    return res.status(204).end();
  }
  next();
});

app.get("/", (req, res) => {
  res.send(`<script nonce="${res.locals.cspNonce}">console.log("ok")</script>`);
});

app.listen(3000);

Cloudflare Workers

export default {
  async fetch(req, env, ctx) {
    const headers = new Headers({
      "Content-Security-Policy":
        "default-src 'self'; base-uri 'self'; object-src 'none'; " +
        "script-src 'self'; style-src 'self'; img-src 'self' data:; " +
        "frame-ancestors 'self'; upgrade-insecure-requests",
      "Strict-Transport-Security": "max-age=31536000; includeSubDomains",
      "Referrer-Policy": "strict-origin-when-cross-origin",
      "Permissions-Policy": "geolocation=(), camera=(), microphone=()",
      "X-Content-Type-Options": "nosniff",
      "Cross-Origin-Opener-Policy": "same-origin",
      "Cross-Origin-Embedder-Policy": "require-corp",
      "Cross-Origin-Resource-Policy": "same-origin"
    });

    if (req.method === "OPTIONS") {
      headers.set("Access-Control-Allow-Origin", "https://example.com");
      headers.set("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
      headers.set("Access-Control-Allow-Headers", "Content-Type");
      headers.set("Access-Control-Allow-Credentials", "true");
      headers.set("Access-Control-Max-Age", "600");
      return new Response(null, { status: 204, headers });
    }

    headers.set("Access-Control-Allow-Origin", "https://example.com");
    headers.set("Access-Control-Allow-Credentials", "true");
    headers.append("Vary", "Origin");

    return new Response("OK", { headers });
  }
};

Poznámka k nonce v Edge Workers

Tento príklad pre jednoduchosť poskytuje statickú CSP. Zavedenie nonce (podľa odporúčania) v edge workerovi, ako je Cloudflare, je zložitejšie. Vyžaduje, aby ste:

  • vygenerovali náhodný nonce, napríklad pomocou crypto.randomUUID(),
  • načítali odpoveď z originu,
  • použili HTML prepisovač, napríklad HTMLRewriter v Cloudflare, na streamovanie odpovede, vložili atribút nonce do vašich značiek <script> a <style>, a potom
  • pridali hlavičku Content-Security-Policy do finálnej odpovede, vrátane vygenerovanej hodnoty 'nonce-...'.

Overenie

# Show all response headers
curl -s -D - https://example.com/ -o /dev/null

# Check a single header
curl -s -D - https://example.com/ -o /dev/null | grep -i strict-transport-security

# Check CORS preflight
curl -s -D - -X OPTIONS https://api.example.com/endpoint \
  -H "Origin: https://example.com" \
  -H "Access-Control-Request-Method: POST" -o /dev/null

Skript na validáciu bezpečnostných hlavičiek

#!/bin/bash
# Comprehensive security header check
URL="https://example.com"
echo "Testing security headers for $URL"

CRITICAL_HEADERS=(
  "Content-Security-Policy"
  "Strict-Transport-Security"
  "X-Content-Type-Options"
  "Referrer-Policy"
  "Permissions-Policy"
)

# Fail if any required header is missing
for h in "${CRITICAL_HEADERS[@]}"; do
  curl -s -D - https://example.com/ -o /dev/null | grep -iq "^$h:" || { echo "Missing $h"; exit 1; }
done

# Ensure CSP contains frame-ancestors
CSP_VALUE=$(curl -s -D - https://example.com/ -o /dev/null | awk 'BEGIN{IGNORECASE=1}/^Content-Security-Policy:/{print substr($0,index($0,$2))}')
echo "$CSP_VALUE" | grep -iq "frame-ancestors" || { echo "CSP missing frame-ancestors"; exit 1; }

# Test HSTS preload readiness
echo "HSTS Preload Check:"
curl -s "https://hstspreload.org/api/v2/status?domain=$(echo $URL | sed 's|https://||')" | jq .

Očakávané výsledky

  • Požiadavka na dokument zobrazuje CSP, HSTS, Referrer-Policy, COOP, COEP, CORP a X-Content-Type-Options.
  • Preflight zobrazuje CORS hlavičky, ktoré ste nastavili.
  • grep nájde presnú hlavičku a hodnotu.

Nástroje vývojára v prehliadači

  • Otvorte kartu Network, načítajte stránku, vyberte požiadavku na dokument a skontrolujte odpoveďové hlavičky.
  • Majte otvorenú konzolu, aby ste zachytili porušenia CSP v režime Report-Only.
  • Skontrolujte panel Application pre súbory cookie a ich príznaky.

Rýchle kroky

  • Chrome: karta Network, potom vyberte dokument a Response Headers. Filtrovať pomocou csp, strict-transport, referrer-policy.
  • Otvorte konzolu a obnovte načítanie, aby ste videli porušenia Content Security Policy v režime Report-Only.
  • Firefox: panel Storage, potom Cookies. Skontrolujte príznaky Secure, HttpOnly a SameSite.

Nasadzovanie a monitorovanie

  • Inventarizácia a východiskový stav (týždeň 1)
    • Zmapujte všetky domény a subdomény
    • Zadokumentujte aktuálny stav hlavičiek
    • Identifikujte všetky závislosti tretích strán
  • CSP Report-Only (týždne 2–3)
    • Nasaďte CSP v režime report-only
    • Monitorujte porušenia 14 a viac dní
    • Opravte legitímne porušenia v kóde
  • Základné hlavičky (týždeň 4)
    • Nasadiť `X-Content-Type-Options: nosniff`
    • Nasadiť `Referrer-Policy: strict-origin-when-cross-origin`
    • Nasadiť `Permissions-Policy` s bezpečnými predvolenými hodnotami
  • HSTS postupne (týždne 5–8)
    • Začnite s `max-age=300` na nekritickej subdoméne
    • Postupne zvýšte na `max-age=31536000`
    • `includeSubDomains` pridajte až po overení všetkých subdomén
  • CSP vynucovanie (týždeň 9+)
    • Prepnite CSP do režimu vynucovania
    • Ponechajte zapnuté reportovanie
    • Monitorujte nové porušenia
  • Pokročilá izolácia (voliteľné)
    • Nasaďte COOP/COEP/CORP iba ak je to potrebné
    • Otestujte požiadavky na izoláciu medzi pôvodmi

Bežné chyby

  • Použitie Access-Control-Allow-Origin: * s povereniami. Je to neplatné a nebezpečné. Použite zoznam povolených a Vary: Origin.
  • Posielanie iba X-Frame-Options. Použite frame-ancestors v CSP.
  • Zabudnutie na X-Content-Type-Options: nosniff.
  • Nenastavené príznaky cookie. Použite Secure; HttpOnly; SameSite.
  • Preload HSTS skôr, než ste pripravení.
  • Rozbitie widgetov tretích strán pomocou COEP alebo CORP. Urobte audit a pridajte explicitné povolenia.
  • Vnímanie CSP ako jedinej záchrany. Stále potrebujete kódovanie výstupov a validáciu vstupov.

Ďalšie úskalia a rýchle opravy

  • CSP povoľuje 'unsafe-inline'. Opravte použitím nonce alebo hashov a odstránením vložených obslúh.
  • Chýbajúce frame-ancestors v CSP. Pridajte ho aj vtedy, ak posielate X-Frame-Options.
  • COEP require-corp nasadené bez CORP na statických zdrojoch. Pridajte Cross-Origin-Resource-Policy na obrázky, písma a WASM.
  • CORS Access-Control-Allow-Headers nastavené na *. Nahraďte presnými používanými hlavičkami.
  • Cookies s SameSite=None, ale chýba Secure. Vždy párujte None so Secure.

Otázky

Uprednostnite frame-ancestors. Niektoré tímy nechávajú obe kvôli kompatibilite, ale CSP je moderný mechanizmus.

Povoľte iba potrebné pôvody. Pre svoje vložené bootstrappy použite nonce. Vyhnite sa zástupným znakom.

Nie. Použite ho iba vtedy, keď každá subdoména používa HTTPS a pri ňom aj zostane.

strict-origin-when-cross-origin vyhovuje väčšine webov. Pre prísnejšie súkromie použite no-referrer.

Použite oboje. Tokeny zostávajú primárne. Fetch Metadata poskytuje rýchlu cestu na odmietnutie.

Rozširuje prístup k dátam. Nikdy nekombinujte s povereniami. Použite zoznamy povolených pôvodov.

Len ak potrebujete izoláciu medzi pôvodmi alebo silnejšiu ochranu proti únikom naprieč stránkami. Najprv otestujte vkladania.

Nie. Je zastaraný.

Väčšina prehliadačov považuje cookie bez SameSite za Lax. Atribúty nastavte explicitne.

Použite curl s OPTIONS, odošlite Origin a Access-Control-Request-Method.

Áno. Pripnite verzie a používajte SRI. Pokrýva manipuláciu na CDN.

Áno. Edge je vhodné miesto. Pre trasy s inými politikami ponechajte prepisy na úrovni aplikácie.

Záver

HTTP hlavičky prinášajú rýchle, merateľné prínosy s nízkym rizikom. Najprv nasadzujte bezpečné predvolené hodnoty, potom pridávajte prísnejšie kontroly podľa správania aplikácie. Politiky držte v kóde, testujte ich v CI a pravidelne ich revidujte.

Referencie

Zsolt Oroszlány

Autor článku Zsolt Oroszlány

Vedúci kreatívnej agentúry Playful Sparkle prináša viac ako 20 rokov skúseností v oblasti grafického dizajnu a programovania. Vedie inovatívne projekty a svoj voľný čas trávi cvičením, pozeraním filmov a experimentovaním s novými funkciami CSS. Zsoltovo oddanie práci a záľubám je hnacou silou jeho úspechu v kreatívnom priemysle.

Spoločne posuňme váš úspech na vyššiu úroveň!

Vyžiadajte si bezplatnú cenovú ponuku

Súvisiace články

Prečítajte si článok 'Podrobný návod na vytvorenie vášho prvého Python balíka'

Podrobný návod na vytvorenie vášho prvého Python balíka

Vytvorenie Python modulu si vyžaduje viac než len písanie kódu. Moderný vývoj si žiada vhodné nástroje, štandardizované pracovné postupy a automatizáciu. Prečítajte si viaco Podrobný návod na vytvorenie vášho prvého Python balíka

Prečítajte si článok 'Zvládnutie formátovania reťazcov v jazyku JavaScript pomocou sprintf()'

Zvládnutie formátovania reťazcov v jazyku JavaScript pomocou sprintf()

Formátovanie reťazcov je základným aspektom programovania, ktorý vývojárom umožňuje vytvárať dynamický a čitateľný textový výstup vkladaním premenných a aplikovaním špecifických pravidiel formátovania. Prečítajte si viaco Zvládnutie formátovania reťazcov v jazyku JavaScript pomocou sprintf()

Prečítajte si článok 'Ako implementovať režim súhlasu Google v2?'

Ako implementovať režim súhlasu Google v2?

Súkromné predpisy, ako je Všeobecné nariadenie o ochrane údajov (GDPR) a Kalifornský zákon o ochrane súkromia spotrebiteľov (CCPA), zásadne zmenili spôsob, akým podniky pristupujú k údajom používateľov. Prečítajte si viaco Ako implementovať režim súhlasu Google v2?