Een uitgebreide gids voor het versterken van frontend-beveiliging met Content Security Policy (CSP) en Cross-Origin Resource Sharing (CORS), om uw webapplicaties te beschermen tegen moderne dreigingen.
Frontend Beveiliging Versterken: Content Security Policy en CORS
In het huidige onderling verbonden digitale landschap is frontend-beveiliging van het grootste belang. Webapplicaties zijn steeds vaker het doelwit van geavanceerde aanvallen, waardoor robuuste beveiligingsmaatregelen essentieel zijn. Twee kritieke componenten van een veilige frontend-architectuur zijn Content Security Policy (CSP) en Cross-Origin Resource Sharing (CORS). Deze uitgebreide gids biedt een diepgaande kijk op deze technologieën, met praktische voorbeelden en bruikbare inzichten om u te helpen uw webapplicaties te versterken tegen moderne dreigingen.
Wat is Content Security Policy (CSP)?
Content Security Policy (CSP) is een extra beveiligingslaag die helpt bij het detecteren en beperken van bepaalde soorten aanvallen, waaronder Cross-Site Scripting (XSS) en data-injectieaanvallen. CSP wordt geïmplementeerd doordat de webserver een Content-Security-Policy HTTP-responseheader naar de browser stuurt. Deze header definieert een witte lijst van bronnen waaruit de browser resources mag laden. Door de bronnen van content die een browser kan laden te beperken, maakt CSP het voor aanvallers aanzienlijk moeilijker om kwaadaardige code in uw website te injecteren.
Hoe CSP Werkt
CSP werkt door de browser te instrueren om alleen resources (bijv. scripts, stylesheets, afbeeldingen, lettertypen) van goedgekeurde bronnen te laden. Deze bronnen worden gespecificeerd in de CSP-header met behulp van richtlijnen. Als een browser probeert een resource te laden van een bron die niet expliciet is toegestaan, zal het verzoek worden geblokkeerd en wordt er een schending gerapporteerd.
CSP-richtlijnen: Een Uitgebreid Overzicht
CSP-richtlijnen bepalen welke soorten resources van specifieke bronnen geladen kunnen worden. Hier volgt een overzicht van enkele van de belangrijkste richtlijnen:
- default-src: Specificeert de standaardbron voor alle contenttypes. Dit is een terugvalrichtlijn die van toepassing is wanneer andere, meer specifieke richtlijnen niet aanwezig zijn.
- script-src: Specificeert de bronnen waarvandaan scripts geladen kunnen worden. Dit is cruciaal voor het voorkomen van XSS-aanvallen.
- style-src: Specificeert de bronnen waarvandaan stylesheets geladen kunnen worden.
- img-src: Specificeert de bronnen waarvandaan afbeeldingen geladen kunnen worden.
- font-src: Specificeert de bronnen waarvandaan lettertypen geladen kunnen worden.
- media-src: Specificeert de bronnen waarvandaan audio en video geladen kunnen worden.
- object-src: Specificeert de bronnen waarvandaan plug-ins (bijv. Flash) geladen kunnen worden. Dit wordt vaak ingesteld op 'none' om plug-ins volledig uit te schakelen vanwege hun inherente veiligheidsrisico's.
- frame-src: Specificeert de bronnen waarvandaan frames (bijv. <iframe>) geladen kunnen worden.
- connect-src: Specificeert de URL's waarmee de user-agent verbinding kan maken via scriptinterfaces zoals XMLHttpRequest, WebSocket en EventSource.
- base-uri: Specificeert de URL's die gebruikt kunnen worden in het <base>-element van een document.
- form-action: Specificeert de URL's waarnaar formulierinzendingen kunnen worden verzonden.
- upgrade-insecure-requests: Instrueert de user-agent om onveilige verzoeken (HTTP) automatisch te upgraden naar veilige verzoeken (HTTPS).
- report-uri: Specificeert een URL waar de browser rapporten over CSP-schendingen naartoe moet sturen. Deze richtlijn is verouderd ten gunste van `report-to`.
- report-to: Specificeert een naam van een rapportagegroep die is gedefinieerd in de `Report-To`-header, waar de browser rapporten over CSP-schendingen naartoe moet sturen.
Trefwoorden voor CSP-bronnenlijsten
Binnen CSP-richtlijnen kunt u trefwoorden voor bronnenlijsten gebruiken om toegestane bronnen te definiëren. Hier zijn enkele veelvoorkomende trefwoorden:
- 'self': Staat resources toe van dezelfde origin (schema en host) als het document.
- 'none': Weigert resources van alle bronnen.
- 'unsafe-inline': Staat het gebruik van inline scripts en styles toe (bijv. <script>-tags en style-attributen). Gebruik met uiterste voorzichtigheid, omdat dit de CSP-bescherming tegen XSS aanzienlijk verzwakt.
- 'unsafe-eval': Staat het gebruik van dynamische code-evaluatiefuncties zoals
eval()enFunction()toe. Gebruik met uiterste voorzichtigheid, omdat dit aanzienlijke veiligheidsrisico's met zich meebrengt. - 'unsafe-hashes': Staat specifieke inline event handlers of <style>-tags toe die overeenkomen met een gespecificeerde hash. Vereist browserondersteuning. Gebruik met voorzichtigheid.
- 'strict-dynamic': Specificeert dat het vertrouwen dat expliciet aan een script in de markup is gegeven (door het te vergezellen van een nonce of hash) moet worden doorgegeven aan alle scripts die door dat hoofdscript worden geladen.
- data: Staat data: URI's toe (bijv. inline afbeeldingen gecodeerd als base64). Gebruik met voorzichtigheid.
- https:: Staat toe dat resources via HTTPS van elk domein worden geladen.
- [hostname]: Staat resources van een specifiek domein toe (bijv. example.com). U kunt ook een poortnummer specificeren (bijv. example.com:8080).
- [scheme]://[hostname]:[port]: Een volledig gekwalificeerde URI, die resources van het gespecificeerde schema, de host en de poort toestaat.
Praktische CSP-voorbeelden
Laten we enkele praktische voorbeelden van CSP-headers bekijken:
Voorbeeld 1: Basis-CSP met 'self'
Dit beleid staat alleen resources van dezelfde origin toe:
Content-Security-Policy: default-src 'self'
Voorbeeld 2: Scripts van een Specifiek Domein Toestaan
Dit beleid staat scripts van uw eigen domein en een vertrouwd CDN toe:
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com
Voorbeeld 3: Inline Scripts en Styles Uitschakelen
Dit beleid verbiedt inline scripts en styles, wat een sterke verdediging tegen XSS is:
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self'
Belangrijk: Het uitschakelen van inline scripts vereist dat u uw HTML refactort om inline scripts naar externe bestanden te verplaatsen.
Voorbeeld 4: Nonces Gebruiken voor Inline Scripts
Als u toch inline scripts moet gebruiken, gebruik dan nonces (cryptografisch willekeurige, eenmalig te gebruiken tokens) om specifieke inline scriptblokken op een witte lijst te zetten. Dit is veiliger dan 'unsafe-inline'. De server moet voor elk verzoek een unieke nonce genereren en deze zowel in de CSP-header als in de <script>-tag opnemen.
Content-Security-Policy: default-src 'self'; script-src 'nonce-r4nd0mN0nc3'; style-src 'self'
<script nonce="r4nd0mN0nc3"> console.log('Inline script'); </script>
Let op: Vergeet niet om voor elk verzoek een nieuwe nonce te genereren. Hergebruik nonces niet!
Voorbeeld 5: Hashes Gebruiken voor Inline Styles
Net als nonces kunnen hashes worden gebruikt om specifieke inline <style>-blokken op een witte lijst te zetten. Dit wordt gedaan door een SHA256-, SHA384- of SHA512-hash van de style-inhoud te genereren.
Content-Security-Policy: default-src 'self'; style-src 'sha256-HASHEDSTYLES'
<style sha256="HASHEDSTYLES"> body { background-color: #f0f0f0; } </style>
Let op: Hashes zijn minder flexibel dan nonces, omdat elke wijziging in de style-inhoud de hash ongeldig maakt.
Voorbeeld 6: CSP-schendingen Rapporteren
Om CSP-schendingen te monitoren, gebruikt u de report-uri- of report-to-richtlijn:
Content-Security-Policy: default-src 'self'; report-to csp-endpoint;
U moet ook de Report-To-header configureren. De Report-To-header definieert een of meer rapportagegroepen, die specificeren waar en hoe rapporten moeten worden verzonden.
Report-To: {"group":"csp-endpoint","max_age":10886400,"endpoints":[{"url":"https://example.com/csp-report"}]}
CSP Testen en Implementeren
Het implementeren van CSP vereist zorgvuldige planning en testen. Begin met een restrictief beleid en maak het geleidelijk losser indien nodig. Gebruik de Content-Security-Policy-Report-Only-header om uw beleid te testen zonder resources te blokkeren. Deze header rapporteert schendingen zonder het beleid af te dwingen, zodat u problemen kunt identificeren en oplossen voordat u het beleid in productie implementeert.
Content-Security-Policy-Report-Only: default-src 'self'; report-to csp-endpoint;
Analyseer de rapporten die door de browser worden gegenereerd om eventuele schendingen te identificeren en pas uw beleid dienovereenkomstig aan. Zodra u er zeker van bent dat uw beleid correct werkt, implementeert u het met de Content-Security-Policy-header.
Best Practices voor CSP
- Begin met een default-src: Definieer altijd een
default-srcom een basisbeleid vast te stellen. - Wees specifiek: Gebruik specifieke richtlijnen en trefwoorden voor bronnenlijsten om de reikwijdte van uw beleid te beperken.
- Vermijd 'unsafe-inline' en 'unsafe-eval': Deze trefwoorden verzwakken CSP aanzienlijk en moeten waar mogelijk worden vermeden.
- Gebruik nonces of hashes voor inline scripts en styles: Als u toch inline scripts of styles moet gebruiken, gebruik dan nonces of hashes om specifieke codeblokken op een witte lijst te zetten.
- Monitor CSP-schendingen: Gebruik de
report-uri- ofreport-to-richtlijn om CSP-schendingen te monitoren en uw beleid dienovereenkomstig aan te passen. - Test grondig: Gebruik de
Content-Security-Policy-Report-Only-header om uw beleid te testen voordat u het in productie implementeert. - Itereer en verfijn: CSP is geen eenmalige configuratie. Monitor en verfijn uw beleid voortdurend om u aan te passen aan veranderingen in uw applicatie en het dreigingslandschap.
Wat is Cross-Origin Resource Sharing (CORS)?
Cross-Origin Resource Sharing (CORS) is een mechanisme dat webpagina's van de ene origin (domein) toestaat om toegang te krijgen tot resources van een andere origin. Standaard dwingen browsers een Same-Origin Policy af, wat voorkomt dat scripts verzoeken doen naar een andere origin dan die waar het script vandaan kwam. CORS biedt een manier om deze beperking selectief te versoepelen, waardoor legitieme cross-origin verzoeken worden toegestaan terwijl wordt beschermd tegen kwaadaardige aanvallen.
Het Same-Origin Policy Begrijpen
Het Same-Origin Policy is een fundamenteel beveiligingsmechanisme dat voorkomt dat een kwaadaardig script van de ene website toegang krijgt tot gevoelige gegevens op een andere website. Een origin wordt gedefinieerd door het schema (protocol), de host (domein) en de poort. Twee URL's hebben dezelfde origin als en alleen als ze hetzelfde schema, dezelfde host en dezelfde poort hebben.
Bijvoorbeeld:
https://www.example.com/app1/index.htmlenhttps://www.example.com/app2/index.htmlhebben dezelfde origin.https://www.example.com/index.htmlenhttp://www.example.com/index.htmlhebben verschillende origins (ander schema).https://www.example.com/index.htmlenhttps://sub.example.com/index.htmlhebben verschillende origins (andere host).https://www.example.com:8080/index.htmlenhttps://www.example.com:80/index.htmlhebben verschillende origins (andere poort).
Hoe CORS Werkt
Wanneer een webpagina een cross-origin verzoek doet, stuurt de browser eerst een "preflight"-verzoek naar de server. Het preflight-verzoek gebruikt de HTTP OPTIONS-methode en bevat headers die de HTTP-methode en headers aangeven die het daadwerkelijke verzoek zal gebruiken. De server antwoordt vervolgens met headers die aangeven of het cross-origin verzoek is toegestaan.
Als de server het verzoek toestaat, voegt het de Access-Control-Allow-Origin-header toe aan het antwoord. Deze header specificeert de origin(s) die toegang hebben tot de resource. De browser gaat dan verder met het daadwerkelijke verzoek. Als de server het verzoek niet toestaat, voegt het de Access-Control-Allow-Origin-header niet toe en blokkeert de browser het verzoek.
CORS-headers: Een Gedetailleerde Blik
CORS is afhankelijk van HTTP-headers om te communiceren tussen de browser en de server. Hier zijn de belangrijkste CORS-headers:
- Access-Control-Allow-Origin: Specificeert de origin(s) die toegang hebben tot de resource. Deze header kan een specifieke origin bevatten (bijv.
https://www.example.com), een wildcard (*), ofnull. Het gebruik van*staat verzoeken van elke origin toe, wat over het algemeen om veiligheidsredenen niet wordt aanbevolen. Het gebruik van `null` is alleen geschikt voor "ondoorzichtige responsen", zoals wanneer de resource wordt opgehaald met het `file://`-protocol of een data-URI. - Access-Control-Allow-Methods: Specificeert de HTTP-methoden die zijn toegestaan voor het cross-origin verzoek (bijv.
GET, POST, PUT, DELETE). - Access-Control-Allow-Headers: Specificeert de HTTP-headers die zijn toegestaan in het cross-origin verzoek. Dit is belangrijk voor het afhandelen van aangepaste headers.
- Access-Control-Allow-Credentials: Geeft aan of de browser credentials (bijv. cookies, autorisatieheaders) moet opnemen in het cross-origin verzoek. Deze header moet op
trueworden ingesteld om credentials toe te staan. - Access-Control-Expose-Headers: Specificeert welke headers aan de client kunnen worden blootgesteld. Standaard wordt slechts een beperkte set headers blootgesteld.
- Access-Control-Max-Age: Specificeert de maximale tijd (in seconden) dat de browser het preflight-verzoek kan cachen.
- Origin: Dit is een request-header die door de browser wordt verzonden om de origin van het verzoek aan te geven.
- Vary: Een algemene HTTP-header, maar belangrijk voor CORS. Wanneer
Access-Control-Allow-Origindynamisch wordt gegenereerd, moet deVary: Origin-header in het antwoord worden opgenomen om caching-mechanismen te instrueren dat het antwoord varieert op basis van deOrigin-request-header.
Praktische CORS-voorbeelden
Laten we enkele praktische voorbeelden van CORS-configuraties bekijken:
Voorbeeld 1: Verzoeken van een Specifieke Origin Toestaan
Deze configuratie staat alleen verzoeken van https://www.example.com toe:
Access-Control-Allow-Origin: https://www.example.com
Voorbeeld 2: Verzoeken van Elke Origin Toestaan (Niet Aanbevolen)
Deze configuratie staat verzoeken van elke origin toe. Gebruik met voorzichtigheid, omdat dit veiligheidsrisico's kan introduceren:
Access-Control-Allow-Origin: *
Voorbeeld 3: Specifieke Methoden en Headers Toestaan
Deze configuratie staat GET-, POST- en PUT-methoden toe, en de Content-Type- en Authorization-headers:
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type, Authorization
Voorbeeld 4: Credentials Toestaan
Om credentials (bijv. cookies) toe te staan, moet u Access-Control-Allow-Credentials op true instellen en een specifieke origin specificeren (u kunt geen * gebruiken bij het toestaan van credentials):
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Credentials: true
U moet ook credentials: 'include' instellen in uw JavaScript fetch/XMLHttpRequest-verzoek.
fetch('https://api.example.com/data', {
credentials: 'include'
})
CORS Preflight-verzoeken
Voor bepaalde soorten cross-origin verzoeken (bijv. verzoeken met aangepaste headers of andere methoden dan GET, HEAD, of POST met een Content-Type van application/x-www-form-urlencoded, multipart/form-data, of text/plain), stuurt de browser een preflight-verzoek met de OPTIONS-methode. De server moet op het preflight-verzoek reageren met de juiste CORS-headers om aan te geven of het daadwerkelijke verzoek is toegestaan.
Hier is een voorbeeld van een preflight-verzoek en -respons:
Preflight-verzoek (OPTIONS):
OPTIONS /data HTTP/1.1
Origin: https://www.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type, Authorization
Preflight-respons (200 OK):
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400
De Access-Control-Max-Age-header specificeert hoe lang de browser de preflight-respons kan cachen, waardoor het aantal preflight-verzoeken wordt verminderd.
CORS en JSONP
JSON with Padding (JSONP) is een oudere techniek om het Same-Origin Policy te omzeilen. JSONP brengt echter aanzienlijke veiligheidsrisico's met zich mee en moet worden vermeden ten gunste van CORS. JSONP is afhankelijk van het injecteren van <script>-tags in de pagina, die willekeurige code kunnen uitvoeren. CORS biedt een veiligere en flexibelere manier om cross-origin verzoeken af te handelen.
Best Practices voor CORS
- Vermijd het gebruik van *: Vermijd het gebruik van de wildcard (*) in de
Access-Control-Allow-Origin-header, omdat dit verzoeken van elke origin toestaat. Specificeer in plaats daarvan de specifieke origin(s) die toegang hebben tot de resource. - Wees specifiek met methoden en headers: Specificeer de exacte HTTP-methoden en -headers die zijn toegestaan in de
Access-Control-Allow-Methods- enAccess-Control-Allow-Headers-headers. - Gebruik Access-Control-Allow-Credentials met voorzichtigheid: Schakel
Access-Control-Allow-Credentialsalleen in als u credentials (bijv. cookies) in cross-origin verzoeken moet toestaan. Wees u bewust van de veiligheidsimplicaties van het toestaan van credentials. - Beveilig uw preflight-verzoeken: Zorg ervoor dat uw server preflight-verzoeken correct afhandelt en de juiste CORS-headers retourneert.
- Gebruik HTTPS: Gebruik altijd HTTPS voor zowel de origin als de resources waartoe u cross-origin toegang heeft. Dit helpt te beschermen tegen man-in-the-middle-aanvallen.
- Vary: Origin: Als u de
Access-Control-Allow-Origin-header dynamisch genereert, neem dan altijd deVary: Origin-header op om cachingproblemen te voorkomen.
CSP en CORS in de Praktijk: Een Gecombineerde Aanpak
Hoewel CSP en CORS beide veiligheidsproblemen aanpakken, werken ze op verschillende lagen en bieden ze complementaire bescherming. CSP richt zich op het voorkomen dat de browser kwaadaardige content laadt, terwijl CORS zich richt op het controleren welke origins toegang hebben tot resources op uw server.
Door CSP en CORS te combineren, kunt u een robuustere beveiligingshouding voor uw webapplicaties creëren. U kunt bijvoorbeeld CSP gebruiken om de bronnen te beperken waarvandaan scripts kunnen worden geladen, en CORS om te bepalen welke origins toegang hebben tot uw API-eindpunten.
Voorbeeld: Een API Beveiligen met CSP en CORS
Stel, u heeft een API die wordt gehost op https://api.example.com en u wilt dat deze alleen toegankelijk is vanaf https://www.example.com. U kunt uw server configureren om de volgende headers te retourneren:
API Response Headers (https://api.example.com):
Access-Control-Allow-Origin: https://www.example.com
Content-Type: application/json
En u kunt uw website (https://www.example.com) configureren om de volgende CSP-header te gebruiken:
Website CSP Header (https://www.example.com):
Content-Security-Policy: default-src 'self'; script-src 'self'; connect-src 'self' https://api.example.com;
Dit CSP-beleid staat de website toe om scripts te laden en verbinding te maken met de API, maar voorkomt dat het scripts laadt van of verbinding maakt met andere domeinen.
Conclusie
Content Security Policy (CSP) en Cross-Origin Resource Sharing (CORS) zijn essentiële tools voor het versterken van de beveiliging van uw frontend-applicaties. Door CSP en CORS zorgvuldig te configureren, kunt u het risico op XSS-aanvallen, data-injectieaanvallen en andere beveiligingskwetsbaarheden aanzienlijk verminderen. Onthoud om te beginnen met een restrictief beleid, grondig te testen en uw configuratie voortdurend te monitoren en te verfijnen om u aan te passen aan veranderingen in uw applicatie en het evoluerende dreigingslandschap. Door prioriteit te geven aan frontend-beveiliging, kunt u uw gebruikers beschermen en de integriteit van uw webapplicaties waarborgen in de steeds complexere digitale wereld van vandaag.