>>
Gepubliceerd op: 20 november 2024, Bijgewerkt op: 21 november 2024, min. leestijd

Waarom je een goede Content Security Policy nodig hebt

Stel je voor: je hebt zojuist een Pentest laten uitvoeren op je applicatie. Alle gevonden kwetsbaarheden zijn netjes opgelost, en toch blijft je securityspecialist aandringen op het implementeren van iets dat een ‘Content Security Policy’ (CSP) wordt genoemd. Of misschien heb je al een CSP, maar wordt er gezegd dat deze niet veilig genoeg is. Waarom zou je extra tijd en middelen besteden aan iets waarvan je dacht dat het al onder controle was? Laten we duiken in een stukje geschiedenis.

Het belang van security headers

Toen browsers ooit werden ontworpen, had niemand kunnen voorzien welke soorten aanvallen later allemaal mogelijk zouden zijn. Sommige aanvallen die we nu kennen, zouden kunnen worden geëlimineerd of in ieder geval beperkt als we de manier waarop browsers werken zouden aanpassen. Maar het aanpassen van hoe browsers werken, heeft een te grote impact op bestaande diensten op het internet. Niet echt een optie dus. Het alternatief?

We geven beheerders met hogere beveiligingsbehoeften de mogelijkheid om extra beschermingslagen toe te voegen. Dit kan door middel van security headers. Als een site wordt bezocht, dan reageert de server met een toegevoegde HTTP response header. Dit is een extra regel voor je browser, die jouw deel van het internet - je website of webapplicatie - veiliger maakt.

Wat is een CSP?

Content Security Policy, of kortweg CSP, is een voorbeeld van zo’n security header [1,2]. Het idee is simpel: een CSP beperkt wat een browser kan doen met content en waar die content vandaan mag komen. In de standaardinstelling zijn er weinig beperkingen, wat betekent dat een website content kan laden van vrijwel elke bron op het internet. Dit kan gaan om ogenschijnlijk onschuldige zaken zoals afbeeldingen, maar ook om JavaScript-code die direct in de browser wordt uitgevoerd. Met een CSP bepaal jij als website-eigenaar precies waar die content vandaan mag komen en onder welke voorwaarden.

Zie de CSP als je tweede verdedigingslinie. Mocht een aanvaller erin slagen om een kwetsbaarheid te vinden, dan maakt de CSP het voor die aanvaller veel moeilijker om daar misbruik van te maken. We kunnen hier een concreet van voorbeeld geven.

Het gevaar van cross-site scripting

Frontend content- en code-injectie kwetsbaarheden zijn al lange tijd een bekend probleem. Dit is een kwetsbaarheidsklasse waarbij gegevens, zoals tekst die door een gebruiker wordt verzonden, niet correct worden verwerkt door de applicatie. Hierdoor kan een aanvaller de beveiliging omzeilen en eigen markup (HTML), styling (CSS), of client-side code (JavaScript) toevoegen aan de webapplicatie. Vooral bij JavaScript is dit gevaarlijk, omdat een aanvaller client-side code kan uitvoeren in de browser van een slachtoffer. Dit wordt cross-site scripting genoemd (XSS) en geeft een aanvaller volledige controle over de applicatie, geauthentiseerd als het slachtoffer.

Meer dan 30% van de applicaties die Computest Security het afgelopen jaar heeft getest, waren kwetsbaar voor een vorm van XSS.

Een van de uitkomsten uit het onderzoek 'De Staat van Applicatiebeveiliging 2024'

Nu denk je misschien: "Maar als mijn applicatie niet kwetsbaar is voor XSS, heeft een CSP toch geen toegevoegde waarde?" Het is maar de vraag of je echt zeker bent dat je niet kwetsbaar bent. XSS mag dan wel tot de ‘oudjes’ behoren als het om aanvalsmethodes gaat, het blijft een probleem wat veel organisaties treft. Meer dan 30% van de applicaties die Computest Security het afgelopen jaar heeft getest, waren kwetsbaar voor een vorm van XSS [3]. Houd er rekening mee dat de gemiddelde klant van Computest Security al bijzonder veiligheidsbewust is, omdat ze regelmatig beveiligingstests van hun applicaties uitvoeren. Het werkelijke aantal kwetsbare applicaties voor XSS ligt daarom waarschijnlijk nog hoger. Het is dus geen overbodige luxe om een goede CSP in te stellen. Het kan net dat extra beetje beveiliging bieden dat je nodig hebt om onbekende risico’s te beperken.

Hoe werkt CSP?

Zoals bij elke interessante vraag is het antwoord: het hangt ervan af. In dit geval van je applicatie en hoe deze is gestructureerd. We geven enkele voorbeelden van mogelijke CSP's die als HTTP-response headers worden teruggestuurd.

blocked

Laten we ons richten op de script-src directive, die verantwoordelijk is voor alle JavaScript-bronnen, zoals *.js bestanden, of inline, tussen <script> tags. Deze directive beschermt je tegen kwetsbaarheden met de grootste impact.

  • Als je applicatie (https://example.com) zo is opgezet dat al het gebruikte JavaScript wordt opgenomen vanaf een dedicated domein (https://js.example.com), dan zou een CSP die je beschermt tegen veel soorten XSS-aanvallen er eenvoudigweg zo uit kunnen zien:
1
  • Elk script dat vanaf een andere bron wordt geladen, wordt niet uitgevoerd. Hetzelfde geldt voor elk inline JavaScript. Als scripts ook moeten worden opgenomen vanaf hetzelfde domein waarop de applicatie wordt gehost, zou het er zo uit kunnen zien:
2
  • Als je inline JavaScript wilt toestaan, wordt het iets complexer. Een browser kan namelijk geen onderscheid maken tussen legitieme en kwaadaardig geïnjecteerde content. Toch is dit mogelijk door gebruik te maken van nonces of hashes. Een nonce, een voldoende willekeurige waarde, kan bijvoorbeeld in de CSP-header worden meegegeven.
3

Deze waarde moet overeenkomen met de waarde die is opgegeven in een <script> tag in dezelfde response.

4

Wanneer de juiste nonce niet is opgenomen, wordt de code niet uitgevoerd. De nonce-waarde verandert bij elke request en kan daarom niet vooraf door een aanvaller worden voorspeld. Dit zorgt ervoor dat een eventuele XSS-kwetsbaarheid niet misbruikt kan worden. Een alternatieve methode is het gebruik van een hash-waarde. Deze hash wordt berekend over de volledige inhoud van de <script> tag. Als de hashes niet overeenkomen, wordt er niets uitgevoerd. Dit voorkomt dat een aanvaller zijn eigen schadelijke code kan injecteren.

Heb je je applicatie niet ontwikkeld met een CSP in gedachten? Kies dan een oplossing die past bij je architectuur. Gelukkig zijn er libraries geschreven voor verschillende webapplicatieframeworks die kunnen helpen bij de implementatie.

De voorbeelden die we hier geven, laten natuurlijk niet alle mogelijkheden zien van een CSP. Het stelt je in staat om gedetailleerde instellingen te maken voor alle mogelijke bronnen die kunnen worden opgenomen in een HTML-pagina. Ben je nieuwsgierig geworden? De links onderaan deze blog bieden je meer leesmateriaal.

Implementatiefouten bij een CSP

Pas op, er kunnen ook dingen misgaan bij het implementeren van een CSP. Vooral als de getoonde whitelisting-benadering van bronnen wordt gebruikt, zijn er valkuilen. Bij Computest Security hebben we verschillende keren gezien dat een verkeerd geïmplementeerde CSP nutteloos wordt of een aanvaller in staat stelt deze eenvoudig te omzeilen. Enkele voorbeelden van zulke fouten zijn:

  • Als je 'unsafe-inline' opneemt in de script-src directive, staat dit al het inline JavaScript toe. Zoals de naam al doet vermoeden, brengt dit een groot risico met zich mee en kan het de meeste voordelen van een CSP tenietdoen.
  • Wanneer bestanden kunnen worden geüpload naar en gedownload van het applicatiedomein, is er een grote kans dat dit kan worden misbruikt om een CSP te omzeilen die ‘self’ toestaat in de script-src directive. Dit maakt je applicatie kwetsbaar.
  • Als je een CDN of een openbare bronhost zoals AWS S3 toestaat (bijvoorbeeld https://s3.eu-central-1.amazonaws.com), kan een aanvaller deze diensten gebruiken om zijn eigen schadelijke exploits te hosten. Aangezien iedereen een AWS-account kan aanmaken om bronnen op S3 te hosten, vormt dit een potentieel risico.
  • Als je nonces gebruikt, is het cruciaal dat deze voldoende willekeurig zijn en slechts één keer worden gebruikt. Anders kan een aanvaller de nonce hergebruiken voor zijn eigen aanvallen.
  • Als je inline JavaScript toestaat met een nonce-waarde, biedt de CSP geen bescherming tegen JavaScript-injectie direct in het script. Een <script> tag die is goedgekeurd met een nonce-waarde, zal namelijk altijd worden uitgevoerd, ongeacht de inhoud ervan.
  • Toegestane hosts met JSONP-eindpunten kunnen door aanvallers worden gebruikt om (deels) een CSP te omzeilen. Dit gebeurt door misbruik te maken van de callback-functionaliteit, waardoor mogelijk willekeurig JavaScript kan worden uitgevoerd.

Vanwege deze veelvoorkomende misconfiguraties wordt een op nonce- of hash-gebaseerde CSP in combinatie met 'strict-dynamic' over het algemeen als de meest veilige aanpak beschouwd [4]. Dit heeft als voordeel dat je heel precies kunt aangeven welke scripts mogen worden uitgevoerd, zonder dat je de hele host hoeft te whitelisten. Een voorbeeld van hoe dit eruit zou kunnen zien:

5

Aanvullende content kan dan binnen de HTML worden opgenomen:

6

Een goed doordachte en strikte Content Security Policy bepaalt precies wat er in de browser mag gebeuren wanneer je applicatie wordt geladen. Hoewel een sterke CSP niet betekent dat je applicatie volledig beschermd is tegen alle aanvallen van buitenaf, zet het je wel op het juiste pad naar een veiligere online omgeving.

Ben je benieuwd of jouw organisatie baat heeft bij een CSP? Wij staan voor je klaar! Neem contact op via info@computest.nl, bel +31 (0)88 733 13 37 of laat je gegevens achter in ons contactformulier en wij bellen je zo snel mogelijk terug.

Meer lezen over CSP:

[1] https://developer.mozilla.org/en-US/docs/Web/Security/Practical_implementation_guides/CSP

[2] https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html

[3] https://www.computest.nl/en/knowledge-platform/state-of-application-security-2024/download-state-of-application-security-2024/

[4] https://web.dev/articles/strict-csp

>> Download ons onderzoek 'De Staat van Applicatiebeveiliging 2024' met bevindingen en adviezen om de veiligheid van applicaties te verbeteren.

Deze website werkt het beste met JavaScript ingeschakeld