Podręcznik
5. Wstrzykiwanie
5.2. Content Security Policy
Jest to mechanizm umożliwiający zdefiniowanie w nagłówkach odpowiedzi serwera (Content-Security-Policy) lub w tagach meta dokumentu HTML skąd mogą pochodzić elementy wyświetlane przez przeglądarkę na danej stronie. Stanowi on jedną z metod ochronnych przed atakami XSS i niektórymi innymi podatnościami po stronie frontendowej.
Polityka może określać m.in.:
- default-src – domyślne źródło dla zasobów zewnętrznych,
- img-src, font-src, script-src, style-src - źródła ładowania wskazanych rodzajów zawartości zewnętrznej,
- connect-src - dozwolone adresy API dla JavaScriptu (XMLHttpRequest, Fetch API, WebSockets),
- form-action- dopuszczalne \texttt{action} formularzy,
- i kilka innych.
Z punktu widzenia ochrony przed atakami z wykorzystaniem JavaScript-u najważniejsze jest to, że domyślnie po zdefiniowaniu polityki CSP wszystkie skrypty muszą być ładowane z plików zewnętrznych, a skrypty umieszczone w kodzie, bądź właśnie wstrzyknięte w wyniku ataku nie wykonają się. Standard umożliwia dodanie atrybutu ‘unsafe-inline’ do polityki script-src, co pozwala na wykonywanie skryptów w kodzie HTML, ale automatycznie niweluje to ochronę przed wstrzyknięciami. Z tego powodu dla skryptów w kodzie, które są witalną częścią wielu frameworków web-owych można zastosować dopuszczenie z wykorzystaniem skrótu kryptograficznego kodu do wykonania.
Załóżmy, że chcemy dopuścić wykonanie następującego skryptu w kodzie html i zdefiniujemy politykę źródeł skryptów na ‘self’ czyli pochodzących z tej samej domeny, to skrypt, jako inline się nie wykona, co zobaczymy w konsoli narzędzi deweloperskich jako.<!DOCTYPE html>
<html><head>
<meta http-equiv="Content-Security-Policy" content="script-src 'self';">
</head>
<body>
<script>window.onload=()=>{alert(1);}</script>
</body>

Oczywiście ustawienie polityki na ‘unsafe-inline’ zezwoli na wykonanie skryptu, narażając jednocześnie na ataki XSS.
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';">
Możemy jednak dopuścić tylko ten konkretny skrypt definiując politykę jako
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'sha256-BLJc16dHcdpqP+T7olQlSt2wiWY1VPsqPDV4ZbMCSDo=';">
Wyliczając skrót za pomocą
echo -n ‘window.onload=()=>{alert(1);}‘
| openssl dgst -sha256 -binary | openssl base64
co umożliwi jego wykonanie i uniemożliwi jakąkolwiek ingerencję w ten skrypt zmieniającą skrót kryptograficzny.
Przy większych systemach polityka staje się bardzo skomplikowana i bez użycia zewnętrznych narzędzi trudno jest ją testować. Przykładem narzędzia do weryfikacji polityki jest CSP Evaluator (https://csp-evaluator.withgoogle.com/). Jak bardzo rozbudowana potrafi być polityka jest polityka dla twitter.com (2023-12):
connect-src 'self' blob: https://api.x.ai https://api.x.com https://*.pscp.tv https://*.video.pscp.tv https://*.twimg.com https://api.twitter.com https://api.x.com https://api-stream.twitter.com https://api-stream.x.com https://ads-api.twitter.com https://ads-api.x.com https://aa.twitter.com https://aa.x.com https://caps.twitter.com https://caps.x.com https://pay.twitter.com https://pay.x.com https://sentry.io https://ton.twitter.com https://ton.x.com https://ton-staging.atla.twitter.com https://ton-staging.atla.x.com https://ton-staging.pdxa.twitter.com https://ton-staging.pdxa.x.com https://twitter.com https://x.com https://upload.twitter.com https://upload.x.com https://www.google-analytics.com https://accounts.google.com/gsi/status https://accounts.google.com/gsi/log https://checkoutshopper-live.adyen.com wss://*.pscp.tv https://vmap.snappytv.com https://vmapstage.snappytv.com https://vmaprel.snappytv.com https://vmap.grabyo.com https://dhdsnappytv-vh.akamaihd.net https://pdhdsnappytv-vh.akamaihd.net https://mdhdsnappytv-vh.akamaihd.net https://mdhdsnappytv-vh.akamaihd.net https://mpdhdsnappytv-vh.akamaihd.net https://mmdhdsnappytv-vh.akamaihd.net https://mdhdsnappytv-vh.akamaihd.net https://mpdhdsnappytv-vh.akamaihd.net https://mmdhdsnappytv-vh.akamaihd.net https://dwo3ckksxlb0v.cloudfront.net https://media.riffsy.com https://*.giphy.com https://media.tenor.com https://c.tenor.com https://ads-twitter.com https://analytics.twitter.com https://analytics.x.com ; default-src 'self'; form-action 'self' https://twitter.com https://*.twitter.com https://x.com https://*.x.com; font-src 'self' https://*.twimg.com; frame-src 'self' https://twitter.com https://x.com https://mobile.twitter.com https://mobile.x.com https://pay.twitter.com https://pay.x.com https://cards-frame.twitter.com https://accounts.google.com/ https://client-api.arkoselabs.com/ https://iframe.arkoselabs.com/ https://vaultjs.apideck.com/ https://recaptcha.net/recaptcha/ https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/; img-src 'self' blob: data: https://*.cdn.twitter.com https://*.cdn.x.com https://ton.twitter.com https://ton.x.com https://*.twimg.com https://analytics.twitter.com https://analytics.x.com https://cm.g.doubleclick.net https://www.google-analytics.com https://maps.googleapis.com https://www.periscope.tv https://www.pscp.tv https://ads-twitter.com https://ads-api.twitter.com https://ads-api.x.com https://media.riffsy.com https://*.giphy.com https://media.tenor.com https://c.tenor.com https://*.pscp.tv https://*.periscope.tv https://prod-periscope-profile.s3-us-west-2.amazonaws.com https://platform-lookaside.fbsbx.com https://scontent.xx.fbcdn.net https://scontent-sea1-1.xx.fbcdn.net https://*.googleusercontent.com https://t.co/1/i/adsct; manifest-src 'self'; media-src 'self' blob: https://twitter.com https://x.com https://*.twimg.com https://*.vine.co https://*.pscp.tv https://*.video.pscp.tv https://dhdsnappytv-vh.akamaihd.net https://pdhdsnappytv-vh.akamaihd.net https://mdhdsnappytv-vh.akamaihd.net https://mdhdsnappytv-vh.akamaihd.net https://mpdhdsnappytv-vh.akamaihd.net https://mmdhdsnappytv-vh.akamaihd.net https://mdhdsnappytv-vh.akamaihd.net https://mpdhdsnappytv-vh.akamaihd.net https://mmdhdsnappytv-vh.akamaihd.net https://dwo3ckksxlb0v.cloudfront.net; object-src 'none'; script-src 'self' 'unsafe-inline' https://*.twimg.com https://recaptcha.net/recaptcha/ https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/ https://client-api.arkoselabs.com/ https://www.google-analytics.com https://twitter.com https://x.com https://accounts.google.com/gsi/client https://appleid.cdn-apple.com/appleauth/static/jsapi/appleid/1/en_US/appleid.auth.js https://static.ads-twitter.com 'nonce-ZDQ1N2IyNTctODNjYy00MmE0LTgwNjYtNTJhZDM4MWE1NTZh'; style-src 'self' 'unsafe-inline' https://accounts.google.com/gsi/style https://*.twimg.com; worker-src 'self' blob:; report-uri https://twitter.com/i/csp_report?a=O5RXE%3D%3D%3D&ro=false