česká verze

Jak správně nastavit CSP a script-src

napsal David Grudl před 20 dny | Nette

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.

Budu se věnovat direktivě script-src která říká, jaké skripty může stránka spouštět. Její nasazení totiž není zcela triviální.

Pokud bychom požadovali jen to, aby prohlížeč zabránil spouštění JavaScriptu přímo zapsaného v HTML kódu stránky (tj. inline skriptů) a dále skriptů uložených mimo naši doménu, je to jednoduché. Stačí použít script-src 'self'. Nebo povolit další domény script-src 'self' static.mojedomena.cz.

Jenže obvykle tak jednoduché to není. Často chceme používat i knihovny a nástroje umístěné 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. Provozovatelé služeb na CSP často kašlou a jen málokdy zdokumentují pravidla potřebná pro funkčnost jejich kódu. 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.

Další verze CSP level 2 nahrazuje whitelisty za tzv. nonce, což je náhodně vygenerovaný jednorázový token lišící se pro každý HTTP požadavek, který odešleme v hlavičce script-src 'nonce-c7f26c' a následně uvedeme v každém elementu:

<script nonce="c7f26c" src="..."></script>

<script nonce="c7f26c"> ... kód ... </script>

Skripty, které nemají správný nonce, prohlížeč zablokuje. S nonce konečně chytlo CSP věc za správný konec, bohužel ale nefunguje pro další skripty, které JavaScript dynamicky vkládá. Myšleno elementem vytvořeným pomocí document.createElement('script'). Jejich lokace je potřeba opět povolit whitelistem nebo do nich vložit JavaScriptem atribut nonce.

Tohle řeší až CSP level 3. Konečně! Stačí doplnit do hlavičky strict-dynamic. Bohužel podpora CSP 3 zatím není zdaleka ideální, chybí například v iOS.

Jak správně nastavit script-src?

Začneme s nonce & strict-dynamic. Na začátku každého requestu nonce vygenerujeme, odešleme v hlavičce a vypíšeme v každém elementu script (příklady níže). Tím máme zajištěno, že jen podpsané skripty se spustí a ostatní prohlížeč zablokuje. V prohlížečích podporujících CSP 3 tak máme vystaráno, všechny knihovny budou fungovat a netřeba nic víc dělat.

Ale prohlížeče podporující jen CSP 2? Tam by nefungovalo dynamické načítaných dalších skriptů. A samozřejmě nechceme pracně zkoumat, odkud která knihovna co donačítá, proto povolíme načítání odkudkoliv a to doplněním * do hlavičky, čímž částečně simulujeme strict-dynamic. Bohužel jen částečně, protože prohlížeč bude blokovat dynamické inline skripty, tedy elementy vytvořené pomocí document.createElement('script') které místo atributu src obsahují přímo kód. S tím si CSP 2 neporadí. Jestli se něco takového týká vašeho webu můžete zjistit monitoringem, viz níže.

A co v případě prohlížečů, které podporují jen CSP 1 a nonce tedy neznají? Jak jsem v úvodu psal, vyjmenování všech domén je stěží řešitelný úkol, což určitě nechceme podstupovat kvůli pradávným málo používaným prohlížečům, takže v nich ochranu vypneme, tj. povolíme načítání odkudkoliv a to již zmíněným uvedením hvězdičky, a dále povolením inline skriptů (tj. <script>...kód...</script>) pomocí unsafe-inline.

Výsledná podoba univerzální direktivy script-src vypadá následovně:

script-src 'nonce-XXXXX' 'strict-dynamic' * 'unsafe-inline'

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]

A v šablonách pak používat:

<script n:nonce src="...">

eval()

Content Security Policy také zakazuje používání funkce eval(). Je velmi nepravděpodobné, že některá z knihoven by tuhle funkci používala, ale kdyby ano, můžete ji povolit doplněním 'unsafe-eval' do hlavičky.

Kaskádové styly

Téměř totéž, co platí pro <script>, lze použít i pro kaskádové styly (<link> a <style>) s direktivou style-src. Chybí pouze strict-dynamic, který se týká jen JavaScriptu.

http:
    csp:
        style-src: [nonce, *, unsafe-inline]

A opět doplníme atributy n:nonce u elementů <style> nebo <link>.

Atributy onevent a style

Používání atributů jako onclick nebo style nelze nijak při nasazení nonce povolit, takže je potřeba je přepsat do klasických skriptů nebo stylů.

Obrázky, iframe a další

Také v případě obrázků, videa, audia, iframe a podobně můžete pomocí direktiv jako img-src, media-src, frame-src, font-src nebo object-src kontrolovat, odkud se načítají. Ale pozor, tady už se kombinace nonce a hvězdičky chová úplně jinak a je potřeba uvádět whitelist zdrojů.

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

Tak se dá odhalit, jestli třeba neselhává nějaká knihovna na dynamických skriptech v CSP 2, volání funkce eval nebo na nějaké chybě v prohlížeči.

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.

This is locked content for Nette partners only.
Unlock this by becoming a partner.
Are you already a partner? Please log in.

Recent posts