Konferencja Mega Sekurak Hacking Party w Krakowie – 26-27 października!
Mikołajki z sekurakiem! od 2 do 8 grudnia!
Konferencja Mega Sekurak Hacking Party w Krakowie – 26-27 października!
Mikołajki z sekurakiem! od 2 do 8 grudnia!
CSP zainteresowałem się kilka lat temu, gdy zacząłem zgłębiać bezpieczeństwo technologii skupionych wokół HTML5. Z nagłówkami Content-Security-Policy miałem styczność jako web developer oraz pentester. W zależności od roli projektowej i doświadczenia, CSP było moim przyjacielem lub wrogiem. Sądzę, że warto zaznajomić się z tą technologią i wyciągnąć z niej to, co najlepsze, by zabezpieczyć użytkowników aplikacji webowych, ale także – aby nie utknąć na zbyt dużych restrykcjach w czasie testów.
W sieci istnieje wiele poradników dotyczących CSP. Niestety te, na które trafiałem, zawsze miały wspólną wadę – nie odwoływały się do rekomendowanej wersji standardu (obecnie – drugiej). Autorzy poradników często mieszają mechanizmy proponowane przez W3C z niestandardową implementacją przeglądarek oraz nie wyjaśniają różnic. Z tego powodu projekty z CSP, z którymi miałem do czynienia, posiadały bardzo liberalne zasady nieznacznie podnoszące poziom bezpieczeństwa. Obserwowałem też wdrożenia CSP, które całkowicie nie działały lub powodowały popsucie aplikacji internetowej.
Aby pomóc innym programistom i testerom, zdecydowałem się napisać artykuł, którego źródłem są wyłącznie: dokumentacje W3C oraz moje zawodowe doświadczenie.
Artykuł pisany jest w kontekście zwiększania bezpieczeństwa („utwardzania”/hardeningu) aplikacji internetowych. Testowanie, omijanie i atakowanie CSP będzie tematem osobnej publikacji.
Content Security Policy 1.0 W3C Candidate Recommendation 15 November 2012 (wyłącznie do celów informacyjnych).
Content Security Policy Level 2, W3C Candidate Recommendation, 21 July 2015.
Ten materiał jest efektem wniosków z analizy fragmentów unormowanych oraz nienormatywnych dokumentacji W3C. W obu przypadkach analizowałem tylko stabilne, rekomendowane standardy (o statusie CR), które nie powinny zostać zmienione.
W momencie pisania tekstu, zostały rozpoczęte prace nad CSP 3. Ze względu na to, że niektóre elementy CSP 3 zostały już zaimplementowane w przeglądarkach, w artykule również się do nich odniosę. Z uwagi na możliwe zmiany w dokumentacji i rzetelność opracowania, referencje do trzeciej wersji CSP będą w niniejszym opracowaniu wyraźnie zaznaczone.
W chwili tworzenia aplikacji internetowej z reguły wiadomo, jakie zasoby trafią do przeglądarek końcowych użytkowników. Programiści nie powinni mieć większego problemu z określeniem, z jakiego miejsca zostaną pobrane pliki HTML, skrypty, style czy multimedia.
Można by więc pokusić się o wskazanie dozwolonych źródeł (domen, ścieżek, protokołów) dla różnych grup zasobów. Gdyby przeglądarka respektowała takie wartości, to użytkownicy aplikacji (oraz agresorzy), nie mogliby spowodować załadowania (złośliwych) zasobów (skryptów, apletów…) z domeny niewskazanej wprost przez programistę.
Content Security Policy (CSP) jest właśnie koncepcją wykorzystującą listy dozwolonych źródeł, z których mogą zostać załadowane zasoby strony. Programista tworzy białą listę hostów i ścieżek, którą dodaje do nagłówka odpowiedzi strony internetowej. Nowoczesna przeglądarka respektuje tę listę i – w razie naruszenia polityki – blokuje ładowanie oraz wykonywanie niechcianego zasobu.
Włączenie polityk CSP w znacznym stopniu utrudnia przeprowadzenie udanych ataków XSS, UI Redressing (Clickjacking), złośliwego wykorzystania ramek czy wstrzyknięć CSS. Gdy agresor będzie próbował dodać szkodliwe elementy do strony (np. przez nieznaną podatność), restrykcje CSP zatrzymają żądanie o wrogi zasób (np. skrypt). Nawet gdy w aplikacji zostanie odnaleziona podatność XSS, potencjalny atakujący może mieć bardzo utrudnione zadanie w jej wykorzystaniu, ponieważ ładunki („payloady”) podsyłane ofiarom nie załadują szkodliwych skryptów w miejscu wstrzyknięcia.
CSP można włączyć na dwa sposoby:
Zalecany jest pierwszy wariant – CSP włączone przez znacznik <meta> (dla bezpieczeństwa) nie interpretuje wszystkich dyrektyw.
Domyślną polityką, od której zaczyna się budowanie nagłówka, jest: blokuj wszystko. Programista modyfikując wartość CSP, rozluźnia obostrzenia dla konkretnych grup zasobów (np. osobno dla skryptów, obrazków itp.). Gdy nowoczesna przeglądarka, wspierająca użyte dyrektywy, odbierze wraz z treścią strony nagłówek:
Content-Security-Policy: default-src 'self' cdn.example.com; img-src img.example.com;
to podczas przetwarzania kodu HTML (a potem podczas działania strony) powodującego wysłanie żądań o skrypty, style czy fonty, pozwoli wykonać je wyłącznie do:
W powyższym przykładzie obrazki będą mogły zostać załadowane tylko spod adresu http(s)://img.example.com/*. Nie będzie możliwości wczytania zasobów z innych hostów. Wskazana polityka CSP zablokuje również wywoływanie skryptów umieszczonych między znacznikami <script></script>. Nie wykonają się również akcje z atrybutów takich jak onclick czy oninput, gdyż wykonanie tzw. „skryptów inline” musiałoby zostać dopuszczone przez dodanie ‘unsafe-inline’:
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'
Jak widać, użycie CSP jest bardzo proste i intuicyjne. Zanim zapoznamy się z elementami, które możemy chronić, najpierw przyjrzyjmy się standardom stojącym za technologią oraz ich praktycznemu wsparciu w obecnych przeglądarkach.
Content Security Policy powstało z inicjatywy pracowników Google oraz Mozilli. Od samego początku przeglądarki tych dwóch firm najszybciej wprowadzały nowe rozszerzenia CSP, oczywiście każda w innym czasie. Po kilku latach firma Microsoft – jakby pod naciskiem konkurencji – również podjęła pierwsze próby implementacji CSP w swoich produktach. Ostatecznie pomysł na nowy standard trafił pod skrzydła grupy roboczej W3C.
Z początkiem 2016 roku CSP w wersji 1.0 zostało całkowicie zastąpione przez wersję drugą. Można również zapoznać się ze szkicem (W3C draft) trzeciej wersji standardu, uzupełnianej o nowe mechanizmy zabezpieczeń.
Content Security Policy w pierwszej wersji zostało bardzo dobrze przyjęte przez inżynierów bezpieczeństwa. Nieco gorzej wypadło w oczach web developerów, ponieważ w niektórych przypadkach, CSP okazało się bardziej skomplikowane niż przypuszczano. Dlatego też szybko rozpoczęto prace nad usprawnieniami, oznaczonymi numerem 1.1. Standard powoli się rozrastał, aż W3C zdecydowało się zmienić numerację na Level 2, zamrozić proces zmian i kontynuować pracę nad wersją trzecią.
Mogłoby się wydawać, że prace nad CSP przebiegały bardzo sprawnie – przeglądarki szybko implementowały kolejne dyrektywy CSP, a grupy robocze płynnie tworzyły nowe mechanizmy zabezpieczeń. Problem pojawił się w innym miejscu – po stronie użytkowej, kiedy programiści chcieli się nauczyć, jak korzystać z CSP oraz przekazać tę wiedzę dalej. Pojawiły się więc poradniki oraz benchmarki, do których – niestety – wkradło się wiele niespójności.
Do niedawna jeszcze mieliśmy niemały bałagan w samej standaryzacji i stopniu jej implementacji; na szczęście proces zaczyna się porządkować, niemniej nadal można trafić na wdrożenia CSP pisane w duchu wsparcia:
Aby uniknąć problemów w przyszłości, przed rozpoczęciem definiowania polityk CSP należy:
Wsparcie nowych technologii WWW w przeglądarkach można sprawdzić w serwisie „Can I use”. Pod adresem http://caniuse.com/#search=CSP znajdziemy podstawowe informacje o stopniu implementacji CSP w różnych przeglądarkach.
Wersje CSP 1.0 oraz 2.0 nie powinny się już zmieniać, więc http://caniuse.com jest dość dobrym (i często aktualizowanym) źródłem wiedzy. Trzeba tylko pamiętać o adnotacjach i wyszukiwać informacji o pełnym wsparciu i ze szczególną rezerwą podchodzić do przeglądarek z „częściowym wsparciem” – na przykład IE 10/11 w praktyce implementuje tylko jedną dyrektywę CSP 1.0 (sandbox), w dodatku przez niestandardowy nagłówek. Dość często Internet Explorer okazuje się więc niemiłą niespodzianką.
Pamiętając o tego rodzaju problemach, przyjrzyjmy się ogólnie, w jakich przeglądarkach możemy liczyć na wsparcie Content Security Policy.
Obecnie poziom wsparcia pierwszej wersji standardu jest bardzo wysoki. Kompletna implementacja standardu W3C została wdrożona w:
Problemem jest wyłącznie Internet Explorer 10/11, który obsługiwany jest tylko przez nagłówek ‘X-Content-Security-Policy’ i respektuje wyłącznie dyrektywę sandbox. Inne dyrektywy, takie jak chociażby script-src czy style-src, nie są interpretowane przez Internet Explorer w wersjach poniżej „Edge”.
Można założyć, że Internet Explorer w wersji 10 oraz 11 (i starszych) jest przeglądarką niewspierającą CSP.

Rysunek 1. CSP 1.0 wspierane przez około 90% przeglądarek internautów.
Na początku 2016 roku, kompleksowym wsparciem CSP 2.0 może pochwalić się tylko Google Chrome i przeglądarki oparte na jej silniku (Opera, Opera Mobile, Android WebView, Android Chrome). Nieźle radzi sobie również Firefox, który od wersji 36 ma problemy tylko z interpretacją plugin-types oraz child-src. Za kilka miesięcy z pewnością „dogoni” przeglądarkę Google, zapewniając stuprocentowe wsparcie CSP 2.0.
Internet Explorer, Internet Explorer Edge, Safari oraz wersje mobilne tych przeglądarek na początku 2016 roku nie wspierały CSP 2.0.

Rysunek 2. CSP 2.0 wspierane przez ponad połowę przeglądarek internautów (w Polsce – 75%).
W celu szybszego wdrożenia wersji drugiej, W3C zdecydowało się na wyrzucenie niektórych dyrektyw CSP do kolejnej wersji standardu. Część z nich została już zaimplementowana przez twórców przeglądarek, więc możemy mówić o pierwszych wdrożeniach CSP Level 3.
Trudno jednak obecnie wyciągać wnioski o poziomie wsparcia CSP 3.0 w przeglądarkach, ponieważ standard ciągle ewoluuje. Niektóre z nowości są bardzo ciekawe i można pokusić się o ich wdrożenie – ale należy pamiętać, że z dnia na dzień może zmienić się sposób ich działania.
Więcej o nowinkach CSP Level 3 w sekcji: „Coś się kończy, coś zaczyna – CSP 3.0?”.
Content-Security-Policy jest nagłówkiem odpowiedzi serwera, którego wartością są polityki stopniowo rozluźniające zasadę „blokuj wszystko”.
Polityka CSP (CSP policy) składa się z dwóch elementów:
Ogólny schemat polityki (dyrektywy) wygląda następująco:
directiveX: source1 source2 sourceN;
Poniższy zapis definiuje więc trzy polityki:
Content-Security-Policy: script-src 'self'; img-src 'self'; style-src 'self' cdn.com;
Dyrektywy rozdziela się średnikami, białe znaki nie mają znaczenia. Powyżej widzimy restrykcje dla skryptów, obrazków oraz styli. Nie zmieniono definicji domyślnego zachowania, więc inne elementy w takim przypadku (np. fonty) byłyby blokowane.
Dyrektywami są słowa kluczowe, które opisują reguły dostępu do zasobu. Gdy przeglądarka nie wspiera danej dyrektywy, pominie ją i zacznie przetwarzać następną (czyli w przypadku braku wsparcia, przeglądarka nie przestaje nagle interpretować CSP).
Poniżej znajduje się lista dyrektyw oraz informacja, od której wersji standardu dana dyrektywa powinna być wspierana:
Istnieje też kilka bardzo ciekawych dyrektyw, które ostatecznie wypadły z CSP 2.0, ale mogą trafić do trzeciej wersji CSP:
W sekcji „Coś się kończy, coś zaczyna – CSP 3.0?” przyjrzymy się tym dyrektywom dokładniej.
Na listę źródeł dyrektywy może trafić:
Warto wspomnieć o kilku najczęstszych błędach w implementacji dyrektyw:
Domyślna polityka CSP blokująca dostęp do niezdefiniowanego źródła może zostać zmieniona przy pomocy dyrektywy default-src.
Gdy mamy wpływ na CSP w trakcie tworzenia aplikacji webowej (np. jako programista), dobrym pomysłem jest rozpoczęcie od pojedynczej, restrykcyjnej dyrektywy default-src (‘none’ lub ‘self’), a następnie „rozluźnianie” obostrzeń przez uszczegóławianie źródeł skryptów, obrazków itp. Dla zachowania czytelności, warto też dodawać default-src jako pierwszą politykę, nawet, gdy jej wartością miałoby być słowo kluczowe ‘none’.
Należy zaznaczyć, że po definicji default-src, wartości domyślne ustawiane są tylko na wybrane i niezdefiniowane dyrektywy.
Poniżej lista dyrektyw, które mogą przybrać wartości domyślne (według CSP 2.0):
Ta dyrektywa odnosi się do ograniczeń nakładanych na element <base>. Tag „base” w HTML pozwala określić:
Dodanie lub manipulacja wartości znacznika „base” przez atakującego może skutkować załadowaniem złośliwych zasobów (np. skryptów) z obcych źródeł. Definiując wartość base-uri, możemy znacznie utrudnić ataki wykorzystujące ten element.
Dotyczy dodatkowych (zagnieżdżonych) kontekstów przeglądarki (nested browsing context), czyli elementów takich jak ramki frame/iframe oraz „web workerzy” HTML5 (konkretnie są to restrykcje konstruktora Worker oraz SharedWorker).
Zastępuje frame-src z CSP 1.0.
Pozwala określić, co może być celem żądań asynchronicznych XMLHttpRequest send(), konstruktorów WebSocket, EventSource lub parametrów funkcji sendBeacon() technologii Beacon.
Dyrektywa ta wpłynie między innymi na takie wywołania w kodzie, jak:
Tu możemy określić ograniczenia dla fontów webowych, czyli np. źródeł, które pojawiają się w definicji @font-face w stylach CSS.
Obostrzenia dla atrybutu „action” formularza HTML.
Restrykcje zagnieżdżania zasobu w innych miejscach. Dotyczy to ramkowania strony przez takie elementy, jak ramki frame/iframe czy elementy <object>, <embed>, <applet> i podobne.
Obecnie jest to jedno z najlepszych zabezpieczeń przeciwko atakom UI Redressing (w szczególności Clickjacking) oraz innym zagrożeniom, których etapem jest wyświetlenie atakowanej strony wewnątrz ramki.
Domniemaną wartością frame-ancestors jest * (niezależnie od default-src, który nie wpływa na tę dyrektywę). Oznacza to, że strony domyślnie mogą być zagnieżdżane/ramkowane w innych miejscach.
Na liście dozwolonych źródeł frame-ancestors może się znaleźć:
Starsza, prostsza wersja child-src. Działa podobnie, ale wyłącznie dla ramek iframe/frame. Dyrektywa child-src działa na większą grupę elementów i powinna być używana zamiast frame-src, która oznaczona jest jako „deprecated” i prawdopodobnie zniknie w trzeciej wersji standardu.
Lista dozwolonych źródeł obrazków, które mogą być podane w:
Ograniczenia dla dozwolonych źródeł multimediów (filmy, dźwięki, ścieżki…) wskazywanych przez atrybut src wewnątrz tagów <video>, <audio>, <source> oraz <track>.
Restrykcje dla źródeł, z których mogą być pobierane obiekty obsługiwane przez pluginy przeglądarki. Dotyczy to między innymi apletów Flash, Silverlight oraz Java.
Content Security Policy w tej dyrektywie sprawdza:
Za pomocą tej dyrektywy możemy kontrolować rodzaj pluginów uruchamianych przez przeglądarkę do obsługi zasobów takich jak aplety Flash czy Silverlight, zagnieżdżanych przy pomocy znaczników <object> oraz <embed>.
W odróżnieniu od object-src wskazującego skąd obiekt może być załadowany, plugin-types służy do wskazania dozwolonych typów MIME. Gdy wartością dyrektywy będzie:
Content-Security-Policy: plugin-types application/pdf application/x-shockwave-flash
wtedy na odwiedzanej stronie przeglądarka będzie mogła uruchomić wyłącznie plugin do obsługi plików PDF oraz apletów Flash, ale nie będzie mogła obsłużyć apletów Javy oraz Silverlight.
Po włączeniu restrykcji należy upewnić się, że deklaracje obiektów w kodzie HTML mają ściśle zdefiniowany typ MIME – w przeciwnym wypadku nie zostaną załadowane, niezależnie od zawartości:
<object data='resource' type='application/pdf'></object>
Ze względu na nietypowy format listy źródeł domyślna polityka default-src nie wpływa na plugin-types. Na liście typów MIME nie mogą również pojawić się znaczniki wieloznaczne *.
Jest to specjalna dyrektywa, która wskazuje, pod jaki adres powinien zostać wysłany raport w przypadku naruszenia zasad CSP. Wartością dyrektywy powinien być adres URI.
Więcej o raportowaniu w sekcji „Funkcje zaawansowane › Raportowanie”.
Użycie tego słowa kluczowego w CSP spowoduje wyświetlenie całego zasobu (odwiedzanej strony) w trybie piaskownicy HTML5. Tryb ten, pierwotnie wprowadzony jako mechanizm ochrony ramek, pozwala na wyłączenie niektórych mechanizmów przeglądarki.
Gdy zasób jest wyświetlany w trybie „sandbox”, wtedy nakładane są nie niego wszystkie poniższe obostrzenia:
Wszystkie powyższe ograniczenia zostaną wprowadzone, gdy słowo kluczowe sandbox trafi na listę CSP:
Content-Security-Policy: sandbox;
Możliwe jest rozluźnienie niektórych obostrzeń trybu piaskownicy. Aby to zrobić, wystarczy na listę dozwolonych źródeł dyrektywy sandbox dodać wybrane słowa kluczowe z poniższej listy (dowolny zestaw oddzielony spacjami, bez cudzysłowów):
W poniższym przykładzie:
Content-Security-Policy: sandbox allow-scripts allow-popups;
załadowana strona będzie mogła wykonywać kod Javascript oraz tworzyć okna pop-up. Niezależnie od tego, czy logika wysyłania formularzy zostanie zaimplementowana przez kod HTML czy Javascript, ich wysłanie zostanie zabronione (nawet przy włączonym Javascript). Na stronie nie będzie również możliwości zmiany adresu ramkującej (nadrzędnej) strony (zmiana adresu kontekstu nadrzędnego przez window.top.location.href).
Szczegółowe informacje o HTML5 Sandboxing można przeczytać na stronach W3C.
Sztandarowa dyrektywa CSP, która włącza restrykcje dla skryptów na stronie. Na liście źródeł tej dyrektywy mogą pojawić się:
Użycie script-src bardzo utrudnia udane wykorzystanie błędów XSS. Lista dozwolonych hostów utrudni atakującemu dołączenie złośliwego skryptu ze swojej domeny. Brak wartości ‘unsafe-inline’ utrudni wykonanie skryptów „inline”, które są najpopularniejszą metodą dystrybucji ładunku XSS. Brak wartości ‘unsafe-eval’ utrudni zaś eksploatację błędów DOM XSS.
Jest to bardzo często używana dyrektywa, która działa analogicznie do script-src, tylko dotyczy kaskadowych arkuszy stylów – czyli plików CSS, oraz styli definiowanych wprost w kodzie HTML („inline”).
Po dodaniu nagłówka Content-Security-Policy przeglądarki od razu zaczną respektować wdrożone zasady i chronić użytkowników aplikacji webowej.
Niestety, o przeoczenia w CSP nietrudno – chociażby podczas odwoływania się do bibliotek hostowanych w sieciach CDN tylko na niektórych podstronach serwisu. W przypadku błędów, przeglądarki zazwyczaj zablokują zbyt dużo elementów na stronie, utrudniając korzystanie z serwisu. Czym aplikacja większa i architektura bardziej rozproszona, tym bardziej zbyt wysokie restrykcje mogą utrudnić, a nawet całkowicie uniemożliwić korzystanie z serwisu.
Remedium na tego rodzaju problemy jest tryb raportowania, który włącza się przez osobny nagłówek HTTP w celach testowych, jeszcze przed głównym wdrożeniem CSP:
Content-Security-Policy-Report-Only: politykiCSP;
Przeglądarka, odbierając powyższy nagłówek, będzie przetwarzała podane polityki, ale w momencie ich naruszenia nie zablokuje zasobu, zwracając błąd w konsoli Javascript (rysunek 3.).
Rysunek 3. Naruszenie CSP widoczne w konsoli Javascript spowodowane wstrzyknięciem ładunku XSS do kodu strony.
Aby rozszerzyć funkcje raportowania, warto użyć dyrektywy report-uri, dzięki czemu podczas naruszenia restrykcji, pod wskazany adres zostanie wysłany raport o tym zajściu. Raport jest zwykłym obiektem JSON, który należy odebrać we własnym serwisie webowym i np. zapisać w celu dalszej analizy.
Przykładowo – podczas naruszenia poniższych zasad:
Content-Security-Policy: default-src 'self'; report-uri http://example.org/csp-report.cgi
spowodowanych przez próbę załadowania obrazka http://evil.example.com/image.png, raport wysłany przez przeglądarkę przybierze postać przedstawioną na listingu 1.
{
"csp-report": {
"document-uri": "http://example.org/page.html",
"referrer": "http://evil.example.com/haxor.html",
"blocked-uri": "http://evil.example.com/image.png",
"violated-directive": "default-src 'self'",
"effective-directive": "img-src",
"original-policy": "default-src 'self'; report-uri http://example.org/csp-report.cgi"
}
}
Dostaniemy więc szczegółowe informacje o źródle problemu, polityce, która spowodowała blokadę, a nawet całą zawartość (bardzo przydatne, gdy nagłówek jest generowany dynamicznie przez serwer).
Tryb raportowania nie ogranicza się wyłącznie do debugowania poprawności mechanizmu CSP podczas rozwoju oprogramowania czy wdrożenia. Poniżej podaję dwa przykłady, które pokazują, w jaki sposób można połączyć standardowy tryb „CSP”, tryb „Report-Only” oraz report-uri.
Użycie dyrektywy report-uri połączone z systemem składowania raportów ich automatycznej analizy może posłużyć jako prosty system wykrywania włamań (głównie w kontekście nieznanych luk XSS). Raport, który zawiera naruszenia w rodzaju „próba wykonania skryptu inline” lub „ewaluacji funkcji Javascript”, może okazać się bardzo cennym sygnałem dla zespołu developerskiego.
Dyrektywę report-uri można wprowadzić niezależnie od tego, czy w projekcie istnieje możliwość użycia standardowego CSP (w trybie blokowania) czy też nie. Jeżeli programiści nie mogą jeszcze wdrożyć CSP (ze względu na ryzyko błędnego działania strony), to nic nie stoi na przeszkodzie, aby inżynier bezpieczeństwa zaproponował restrykcyjne polityki działające w trybie report-only.
Największą skuteczność wdrażania CSP uzyskujemy wtedy, gdy zaczynamy nowy projekt z bardzo rygorystycznymi zasadami stopniowo rozluźnianymi w trakcie rozwoju oprogramowania. Niestety nie zawsze mamy taką możliwość.
Gdy celem hardeningu z wykorzystaniem CSP jest duży serwis, którego działanie nie może zostać zakłócone, dobrym pomysłem jest rozpoczęcie od bardzo pobłażliwych polityk. Potem przy pomocy Content-Security-Policy-Report-Only wprowadzamy ostrzejsze restrykcje, analizujemy raporty potencjalnych błędów i wprowadzamy poprawki. Gdy raporty przestaną napływać, możemy zastąpić wartość CSP zawartością trybu raportowania i zacząć całą operację od nowa, testując jeszcze większe obostrzenia.
Po kilku iteracjach powinniśmy mieć dopracowane reguły w nagłówku CSP, które nie spowodują problemów na stronie.
Content Security Policy pokazuje największą siłę, gdy blokuje wywołanie kodu „inline”. Niestety, niekiedy przepisanie takich wstawek kodu może okazać się bardzo skomplikowane. Dlatego też w CSP 2.0 (pierwotnie w CSP 1.1) wprowadzono mechanizmy „nonce”(oraz „Inline Hash”), pozwalające na działanie wybranych skryptów (styli) osadzonych bezpośrednio w kodzie strony.
Mechanizm „nonce” wprowadza się w dwóch krokach.
Po pierwsze należy dodać go do dyrektywy skryptów (styli) przez słowo kluczowe ‘nonce-$RANDOM’ (w pojedynczych cudzysłowach), zastępując wartość $RANDOM trudnym do przewidzenia tokenem (analogicznie jak w przypadku tokenów anty-CSRF).
Następnie tę samą wartość umieszcza się w atrybucie nonce znacznika <script> lub <style>, których wykonanie chcemy dopuścić.
Kilka przykładów zastosowania dyrektywy „nonce” przedstawiono na listingu 2.
Content-Security-Policy: default: 'self'; script-src 'self' example.com 'nonce-Nc3n83cnSAd3wc3Sasdfn939hc3'
<script>
alert("Skrypt zostanie zablokowany, ponieważ polityka skryptów nie zawiera 'unsafe-inline'.")
</script>
<script nonce="EDNnf03nceIOfn39fn3e9h3sdfa">
alert("Zablokowane, ponieważ nonce polityki skryptów ma inną wartość")
</script>
<script nonce="Nc3n83cnSAd3wc3Sasdfn939hc3">
alert("Skrypt zostanie wykonany, ponieważ wartość nonce deklaracji skryptu zgadza się z wartością w polityce CSP")
</script>
<script src="https://example.com/ZEZWOLONY-ze-wzgledu-na-script-src.js"></script>
<script nonce="EDNnf03nceIOfn39fn3e9h3sdfa"
src="https://elsewhere.com/ZABLOKOWANY-ze-wzgledu-na-bledny-nonce.js"></script>
<script nonce="Nc3n83cnSAd3wc3Sasdfn939hc3"
src="https://elsewhere.com/DOZWOLONY-z-zewnetrznego-zrodla-ze-wzgledu-na-zgodnosc-nonce.js"></script>
Warto zaznaczyć, że mechanizm „nonce” nie musi służyć tylko do tzw. walki ze skryptami i stylami „inline”. Ostatni przykład z listy powyżej pokazuje, w jaki sposób, odwołując się do pojedynczych skryptów z CDN, można utrzymać silną, zwięzłą politykę CSP.
Jest to kolejny pomysł (obok „nonce”) na wskazanie zaufanego skryptu lub stylu „inline”. W tym wypadku – przy pomocy jednokierunkowych funkcji skrótu.
Gdy do listy dozwolonych źródeł skryptów/styli dodamy wartość ‘sha256-$base64hashInline’ (pojedyny cudzysłów), przeglądarka dopuści wykonanie kodu umieszczonego między tagami <script></script> (<style></style>), jeśli tylko hash SHA256 zawartości znaczników będzie równy wartości $base64hashInline (skrót musi być zakodowany algorytmem base64).
Obsługiwane algorytmy jednokierunkowych funkcji skrótu to:
Listing 3. przedstawia sposób użycia mechanizmu Inline Hash:
<!-- Przykład CSP dla skrótu sha512 ciągu:
alert('Hello, world.');
-->
Content-Security-Policy: default-src 'self' script-src 'self' 'sha512-
Q2bFTOhEALkN8hOms2FKTDLy7eugP2zFZ1T8LCvX42Fp3WoNr3bjZSAHeOsHrbV1Fu9/A0EzCinRE7Af1ofPrw=='
<!-- Zasady zdefiniowane w CSP dopuszczą wykonanie poniższego kodu HTML: -->
<script>alert('Hello, world.');</script>
<!-- Następne trzy wstawki zostaną zablokowane: -->
<script>alert(/XSS/);</script>
<script>
alert('Hello, world.');
</script>
<script> alert('Hello, world.');</script>
echo -n “alert(‘Hello, world.’);”
| openssl dgst -sha256 -binary | openssl enc -base64
echo -n “alert(‘Hello, world.’);”
| openssl dgst -sha256 -binary | openssl enc -base64 –A > hash.txt
Drugim sposobem dostarczenia wartości skrótu do CSP jest przeczytanie opisu błędu naruszenia zasad CSP dla skryptu „inline” i skopiowanie proponowanej wartości do polityki, tak jak pokazano na poniższym rysunku:

Rysunek 4. Wartość jednokierunkowej funkcji skrótu dla skryptu “inline”.
Poniżej wymieniam kilka dyrektyw, które zostały zaimplementowane w niektórych przeglądarkach i mogą trafić jako element standardu CSP Level 3:
Content Security Policy jest szybko rozwijającą się, łatwą w zrozumieniu technologią, która skutecznie utrudnia życie crackerom. Pokazuje największą moc wówczas, gdy jest rozwijana w projektach od samego początku – rygorystyczne polityki znacznie zwiększą bezpieczeństwo, a wyższa jakość kodu zmniejsza ogólną liczbę błędów.
Nie ma jednak róży bez kolców. Pobieżne zrozumienie standardu lub zgubienie się w szczegółach dokumentacji, może unieruchomić działanie serwisu. Wdrożone zasady należy przetestować w najważniejszych przeglądarkach – najlepiej przy pomocy CSP w trybie raportowania.
CSP nigdy nie może zastąpić bezpiecznego kodu – nowe ograniczenia pomagają zmniejszać skutki ataków (takich jak XSS), ale nie są mechanizmami do zapobiegania im!
Dużym problemem podczas wdrożenia CSP są również biblioteki Javascript implementujące tzw. „client–side MVC/MVVM”, które przestają działać przy rygorystycznych politykach. Z popularnych frameworków jedynie AngularJS od dawna może pochwalić się wsparciem CSP, jednak jest to raczej wyjątek potwierdzający regułę. Miejmy nadzieję, że konkurencja szybko pójdzie za przykładem frameworka firmy Google.
Wiedza o Content Security Policy szybko rozpowszechnia się wśród programistów i testerów. Niestety pobieżne zrozumienie CSP może skutkować wprowadzaniem liberalnych polityk, tylko nieznacznie podnoszących poziom bezpieczeństwa. Zachęcam do dokładnej analizy tego standardu i wdrożenia go do projektów webowych, aby skutecznie utrudnić życie potencjalnym agresorom.
Content Security Policy staje się uniwersalnym narzędziem konfiguracyjnym zabezpieczenia strony w przeglądarkach użytkowników. Z nadzieją czekam na kolejne wersje standardu oraz wdrożenia.
–vizzdoom
Nie żeby coś, ale błąd z opisem manifestu z CSP 3.0 dalej jest… Obiecaliście, że poprawicie – nieładnie, nieładnie ;)
Polecam do testów https://report-uri.io oraz https://securityheaders.io
Świetny art! Poza jedną małą wtopą: wyjątki zaprzeczają regułom ;)
W ostatniej liście (“Coś się kończy, coś zaczyna…”) trochę Wam się punktowanie rozjechało.
Poza tym, świetny wpis – DZIĘKI!
Rzeczywiście źle użyto tego sformułowania. W powiedzeniu tym wyjątek potwierdza ISTNIENIE reguły – w tym sensie, że gdyby nie istniały wyjątki, nie byłoby potrzeby formułowania reguły.
Witam,
Rozumiem że Państwo podchodzicie luźno do tematu i macie już jakąś wiedzę. Ja natomiast dopiero założyłem prostą stroną składającą się z bootstrapa: html + css + js i za cholerę nie wiem gdzie mam dodać tą linijkę: “Content-Security-Policy: default-src ‘self’ cdn.example.com; img-src img.example.com;” jeśli nie polecacie tego robić w metatagu..
Ja próbuję dodać tą linijkę w .htaccess: “Header set Content-Security-Policy “default-src ‘self’ (..)” ale strona https://observatory.mozilla.org/
Pokazuje mi że nie używam CSP, tym bardziej że chcę skorzystać z tego 2.0
Gdzie dodaje się dokładnie CSP?
pozdr
Po co używacie skryptu cgi do tworzenia raportu i go nie udostępniacie? tylko w błąd wprowadzacie użytkownika bo on może myśleć że w cgi będzie zapisany json’owy raport a to nie prawda. Wskazujecie w nagłówku scieżkę do skryptu który wygeneruje raport.. DUŻY babol Panowie, żeby nie powiedzieć porażka! Wystarczyłaby tylko informacja o tym dlaczego jest akurat .cgi