Artikel
1 maj, 2024
Kul knep och djupa fallgropar i Content Security Policy (CSP)
Det är inte sällan man hör talas om att webbsidor råkar ut för Cross-Site Scripting (XSS), clickjacking eller code-injection-attacker, som alla exploaterar funktioner i webbläsaren. Content Security Policy, eller CSP, existerar för att göra webbappar mer säkra mot just den här typen av attacker.
CSP:s uppgift är att stänga av eller begränsa funktionalitet på din webbsida, och kan därmed hindra den från att till exempel ladda ned externa och potentiellt skadliga script. Det är dock viktigt att komma ihåg att CSP inte är ett komplett skydd mot den här typen av attacker, utan snarare ett extra lager som gör det svårare att utföra dem.
Hur fungerar CSP?
Kortfattat fungerar en CSP genom att verifiera om en resurs, såsom en bild eller extern kod, är tillåten eller inte. Exempel; om ett script försöker ladda in en bild undersöker CSP om adressen bilden laddas in från kommer från en godkänd källa eller inte. Är den inte godkänd laddas bilden inte ned. Detsamma gäller annat webbinnehåll, såsom script och CSS (Cascading Style Sheet) - du låser helt enkelt ned webbsidan i större utsträckning.
Om en webbsida använder CSP brukar det gå att se i "HTTP response headers", eller i "meta tags" i HTML-koden. Här lägger man in en lista av nyckelord och sökvägar som bland annat berättar för en besökande webbläsare vilka resurser den får ladda in och inte. CSP innehåller även fler funktioner, såsom möjligheten att rapportera vilka script en sida använder.
Vägar runt CSP
Trots att CSP är ett effektivt skydd för att mitigera angrepp som utnyttjar brister i webbsidor, är det viktigt att känna till att det inte är ett universalmedel mot brister och att det finns sätt att komma runt policyn.
Om vi leker med tanken att en sida är sårbar för XSS, men som har implementerat CSP - hur kan man som angripare då göra för att kringgå detta? Det finns en del användbara tricks som varierar beroende på hur serverns CSP är konfigurerad, som går under namnet CSP-bypass. I många fall kan CSP-bypasses tillämpas när policyn inte är implementerad på ett korrekt sätt. I exemplen nedan tittar vi närmare på olika nyckelord som förekommer i CSP, och hur de kan utnyttjas för en CSP-bypass.
Unsafe-inline
Direktivet “unsafe-inline” främsta användningsområde är när man ska skriva om så kallad “inline-kod” på en hemsida, men fortfarande vill använda CSP för att kontrollera andra aspekter. Inline-kod innebär kod som skrivs direkt i koden för hemsidan, istället för att länkas in som en scriptfil.
Detta är det av alla nyckelord som bör undvikas i högsta möjliga mån, för precis som nyckelordet antyder så är detta osäkert. Det tar nämligen bort mycket av det skydd som CSP kan ge, till exempel genom att tillåta externa script - vilket med andra ord innebär jackpot för den som utför XSS. Genom att använda sig av "unsafe-inline"så tillåter man Javascript på webbsidan igen, vilket innebär att en angripare skulle kunna utföra en typisk XSS direkt på sidan.
Detta nyckelord bör endast användas om man även har specificerat "strict-dynamic" i sin CSP. I de flesta moderna webbläsare ignoreras unsafe-inline helt i detta fall.
För att undvika riskerna som kommer med att använda "unsafe-inline" kan direktivet i de allra flesta fall ersättas med andra ord, som dessutom fungerar bättre. Vilket nyckelord som passar bäst beror lite på ändamålet, men ofta är CSP-nonce eller CSP-hash bra alternativ.
script-src 'self';
Policyn tillåter endast script som kommer från sidan själv. I dessa fall kan en angripare söka sätt att ladda upp script på själva webbsidan. Finns det filuppladdning på samma sida? I så fall skulle en angripare kunna ladda upp en egen scriptfil för att kringgå CSP. Finns det däremot inte någon filuppladdning, kan man istället försöka utnyttja "JSON with padding"(JSONP), som kortfattat är ett sätt att kringgå Same-Origin Policy för att extrahera data från en server.
Attacken möjliggörs genom att lägga till, och därefter utnyttja, en tillåten JSONP-endpoint. XSS-payloaden kan se ut ungefär så här, där example.com är en JSONP-endpoint;
<script src=http://example.com/api/jsonp/v1?callback=alert("CSP bypassed!");//></script>
Scriptet skulle i sin tur tolkas av JSONP på följande sätt;
alert("CSP bypass!");//{"key":"value"}. Det riktiga värdet kommenteras ut med //.
Wildcards
När man konfigurerar CSP kan det kännas enklast att använda så kallade wildcards (*) i sin policy. "*" betyder i det här fallet vad som helst, till exempel: script-src 'https://*.någonsida.com. Ibland använder utvecklare wildcards som en temporär lösning för att fritt kunna jobba utan restriktioner, men det är enkelt att glömma bort att ändra det senare.
Men i själva verket gör denna typ av wildcards det snarare svårare att kontrollera just vad som tillåts. Skulle till exempel en subdomän eller endpoint från någonsida.com råka ut för en attack eller ha en JSONP-endpoint som går att utnyttja, kan en angripare utföra ovan nämnda tekniker.
CSP och olika webbläsare
CSP varierar även lite beroende på vilken webbläsare som används. Första webbläsaren som hade stöd för CSP var Firefox 4, som släpptes år 2011. Efter detta började även andra populära webbläsare, med några undantag, också implementera stöd för CSP.
CSP har olika versioner; Level 1, Level 2 och Level 3, där en majoritet av moderna webbläsare minst kommer kunna använda CSP Level 2, som är en rekommenderad standard. Det finns vissa gamla CSP-header-namn som inte längre bör användas, men som kan vara värda att ha koll på. Dessa brukar börja med X, såsom "X-WebKit-CSP" och "X-Content-Security-Policy", som främst användes som experimentella headers när CSP var nytt.
Annat som är värt att nämna är att gamla Internet Explorer inte stödjer CSP, förutom CSP:Sandbox som hjälper emot popups. Nya Edge har däremot stöd för CSP.
Sammanfattning
CSP är ett ämne man kan lägga mycket tid på att grotta ned sig i, och det finns mycket att säga som inte ryms inom den här artikeln. Sammanfattningsvis kan man dock säga att det är viktigt att policyn konfigureras korrekt, och att ytterligare åtgärder fortsätter tillämpas för att skydda sig mot exempelvis XSS, såsom att undvika att använda dynamisk kod. Annars är det i princip som att sätta dit ett lås på en dörr, men inte stänga dörren.
Det finns massvis med information gällande Content Security Policy och hur det bäst konfigureras, samt andra sätt att utföra CSP-bypass. Eftersom det är scenariospecifikt rekommenderas det att man identifierar alla script och applicerar CSP efter hur webbsidan fungerar. Historiskt kunde man applicera ett CSP-direktiv som identifierade vilka script som laddades in, kallad “report uri”. Den är nu utbytt till “report-to”, men kan vara inkompatibel med mindre populära eller äldre webbläsare.
Rekommenderade sidor för mer information;
https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
https://content-security-policy.com
https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html
https://w3c.github.io/webappsec-csp