Content Security Policy (CSP) je dodatečný bezpečnostní prvek, který prohlížeči říká, jaké další zdroje může stránka načítat a jak může být zobrazena. Chrání tak před vkládáním škodlivého kódu a útokům jako je XSS. Odesílá se v podobě hlavičky sestavené z řady direktiv. Jeho nasazení ale není vůbec triviální.
Obvykle chceme používat JavaScriptové knihovny umístěné na různých místech mimo náš server, například měřící kód Google Analytics, reklamní systémy, captchy atd. A tady bohužel první verze CSP selhává. Vyžaduje přesnou analýzu načítaného obsahu a nastavení správných pravidel. Tedy vytvořit whitelist, výčet všech domén, což není snadné, jelikož některé skripty dynamicky dotahují další skripty z jiných domén, nebo jsou na jiné domény přesměrované atd. A i když si dáte práci a seznam vytvoříte ručně, nikdy nevíte, co se může v budoucnu změnit, takže musíte neustále sledovat, jestli je seznam stále aktuální a opravovat ho. Analýza Google ukázala, že i to pečlivé ladění ve finále vede k tomu, že povolíte tak široký přístup, že celý smysl CSP padá, jen posíláte s každým požadavek mnohem větší hlavičky.
CSP level 2 už k problému přistupuje jinak, pomocí nonce, nicméně teprve třetí verze řešení dotáhla do konce. Bohužel zatím (rok 2019) nemá dostatečnou podporu u prohlížečů.
O tom, jak sestavit direktivy script-src
a
style-src
, aby správně fungovaly i ve starších
prohlížečích a přitom s tím bylo co nejméně práce, jsem sepsal podrobný
článek v partnerské sekci Nette. V zásadě výsledná podoba může
vypadat nějak takto:
script-src 'nonce-XXXXX' 'strict-dynamic' * 'unsafe-inline' style-src 'nonce-XXXXX' * 'unsafe-inline'
Příklad použití v PHP
Vygenerujeme nonce a odešleme hlavičku:
$nonce = base64_encode(random_bytes(16));
header("Content-Security-Policy: script-src 'nonce-$nonce' 'strict-dynamic' * 'unsafe-inline'");
A vložíme nonce do HTML kódu:
<script nonce="<?=$nonce?>" src="..."></script>
Příklad použití v Nette
Protože Nette má vestavěnou podporu pro CSP a nonce od verze 2.4, stačí v konfiguračním souboru uvést:
http:
csp:
script-src: [nonce, strict-dynamic, *, unsafe-inline]
style-src: [nonce, *, unsafe-inline]
A v šablonách pak používat:
<script n:nonce src="..."></script>
<style n:nonce>...</style>
Monitoring
Než nastavíte nová pravidla pro CSP, vyzkoušejte si je nejprve nanečisto
pomocí hlavičky Content-Security-Policy-Report-Only
. Ta funguje
ve všech prohlížečích podporujících CSP. Při porušení pravidel
prohlížeč nezablokuje skript, ale jen pošle notifikaci na URL uvedené
v direktivě report-uri
. K příjmu notifikací a jejich analýze
můžete použít třeba službu Report
URI.
http:
cspReportOnly:
script-src: [nonce, strict-dynamic, *, unsafe-inline]
report-uri: https://xxx.report-uri.com/r/d/csp/reportOnly
Můžete zároveň používat obě hlavičky a v
Content-Security-Policy
mít ověřené a aktivní pravidla a
zároveň v Content-Security-Policy-Report-Only
si testovat jejich
úpravu. Samozřejmě i selhání ostrých pravidlech si můžete nechat
monitorovat.