Duiken in Content Security Policy

In mijn tweede week bij Monkeyproof had ik de kans om me te verdiepen in Content Security Policy (CSP), een belangrijk aspect van webbeveiliging. Deze taak bracht me in contact met verschillende facetten van beveiliging en frontend-ontwikkeling, waarbij ik de volgende taken moest uitvoeren:

  • Het toevoegen van een nonce-token
  • Het opruimen van inline styling en JavaScript

Het uiteindelijke doel was om de implementatie van de unsafe-inline tag te elimineren en zo de beveiliging van de website te versterken.

Wat is Content Security Policy?

Content Security Policy (CSP) is een HTTP-response header die moderne browsers gebruiken om de beveiliging van webpagina’s te verbeteren. CSP helpt te controleren welke bronnen, zoals JavaScript, CSS, afbeeldingen, enz., mogen worden geladen en van welke URL’s ze afkomstig mogen zijn.

Hoewel CSP in de meeste gevallen als een HTTP-response header wordt ingesteld, kun je het ook toepassen via een meta-tag in je HTML-code.

CSP werd oorspronkelijk ontwikkeld om Cross-Site Scripting (XSS) aanvallen tegen te gaan. In latere versies biedt het ook bescherming tegen andere dreigingen, zoals Clickjacking.

Hoe pas je CSP toe?

Tijdens mijn werk aan deze taak kwam ik veel in aanraking met het verwijderen van unsafe-inline tags en het toepassen van escape-filters in de HTML-code. Dit voorkomt dat kwaadaardige code wordt uitgevoerd.

Hier zijn enkele belangrijke escape-filters die ik heb gebruikt:

1. |escape (of |e)

Dit filter zorgt ervoor dat ingevoerde waarden veilig worden weergegeven door gevaarlijke tekens om te zetten in onschadelijke HTML-entities. Bijvoorbeeld:

{{ user_input|escape }}  {# of {{ user_input|e }} #}

Dit verandert <script>alert('XSS');</script> in &lt;script&gt;alert('XSS');&lt;/script&gt;, zodat het als gewone tekst wordt weergegeven en niet wordt uitgevoerd.

2. |escape('html_attr')

Dit filter zorgt ervoor dat waarden die in HTML-attributen worden gebruikt, veilig zijn en geen kwaadaardige code kunnen bevatten. Bijvoorbeeld:

<input type="text" value="{{ user_input|e('html_attr') }}">

3. |escape('js')

In een JavaScript-context is het belangrijk om tekens zoals ", ', en < goed te escapen. Dit voorkomt dat ze als code worden uitgevoerd. Bijvoorbeeld:

<script>
    let userInput = "{{ user_input|e('js') }}";
</script>

4. |escape('url')

Dit filter escapt waarden die in URL’s worden gebruikt, zodat ze veilig zijn. Bijvoorbeeld:

<a href="https://example.com?q={{ query|e('url') }}">Search</a>

Door deze escape-filters correct toe te passen, zorg je ervoor dat je code veilige uitvoer genereert en minder kwetsbaar is voor XSS-aanvallen.

Mijn aanpassingen

In de code die ik heb aangepast, heb ik ervoor gezorgd dat de escape-filters op de juiste plekken werden toegepast en heb ik unsafe-inline tags verwijderd waar dat nodig was. Dit verhoogt niet alleen de beveiliging, maar zorgt er ook voor dat de website voldoet aan de Content Security Policy.

Door deze CSP-aanpassingen heb ik niet alleen de veiligheid van de website versterkt, maar ook een dieper begrip van beveiligingsprincipes opgedaan. 🚀

Code in index.html

In de volgende code zie je hoe ik gebruik heb gemaakt van een nonce-token om JavaScript veilig te laden zonder de risico’s van inline scripts (die vaak een doelwit zijn voor XSS-aanvallen):

<script type="text/javascript" nonce="<?php echo NONCE_TOKEN; ?>">
    var script = document.createElement("SCRIPT");
    script.type = "text/javascript";
    script.src = "/assets/js/main.js";
    script.setAttribute("nonce", "<?php echo NONCE_TOKEN; ?>");
    document.body.appendChild(script);
</script>

<script type="text/javascript" nonce="<?php echo NONCE_TOKEN; ?>">
    console.log("Dit script heeft de juiste nonce.");
</script>

<script type="text/javascript" nonce="<?php echo NONCE_TOKEN; ?>">
    var no_results = "<?php echo $general_no_matches; ?>";
    var language = "<?php echo $language; ?>";
</script>

In deze code voeg ik een nonce-waarde toe aan elk <script>-element in de HTML. Deze nonce wordt gegenereerd door de server en komt overeen met de Content-Security-Policy (CSP) header die we hebben ingesteld. Alleen inline scripts die deze geldige nonce bevatten, worden door de browser goedgekeurd, waardoor kwaadaardige scripts niet kunnen worden uitgevoerd.

Code in globals.php

In globals.php heb ik de volgende code toegevoegd om het nonce-token te genereren en de Content-Security-Policy (CSP) header in te stellen:

session_start();

// Genereer nonce als het nog niet bestaat
if (!isset($_SESSION['NONCE_TOKEN'])) {
    $_SESSION['NONCE_TOKEN'] = bin2hex(random_bytes(16));  // Genereer een nieuwe nonce
}

define("NONCE_TOKEN", $_SESSION['NONCE_TOKEN']);

// Voeg de Content-Security-Policy header toe
header("Content-Security-Policy: 
    default-src 'self' https://fonts.googleapis.com; 
    script-src 'self' 'unsafe-eval' 'nonce-" . NONCE_TOKEN . "' ;
    style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
    font-src 'self' https://fonts.gstatic.com https://fonts.googleapis.com data:;
    img-src 'self' data: ;
    connect-src 'self';
    object-src 'none';
    frame-ancestors 'none';
    base-uri 'self';
    form-action 'self';
    upgrade-insecure-requests;
    report-to mailto:logs@monkeyproof.be;
");

Deze code doet het volgende:

  • Nonce genereren: Als er nog geen nonce-token bestaat, genereert de code een nieuw nonce-token en slaat het op in de sessie.
  • CSP header toevoegen: De Content-Security-Policy header wordt aan de HTTP-response toegevoegd. Dit bepaalt welke bronnen de website mag laden, met restricties op scripts, stijlen en andere content. De header maakt gebruik van de gegenereerde nonce, zodat alleen goedgekeurde inline scripts geladen kunnen worden.

Door deze aanpak te volgen, verhoog je de veiligheid van de website aanzienlijk en verminder je de kans op XSS-aanvallen en andere vormen van kwaadwillige injecties.

Het implementeren van een Content-Security-Policy (CSP) en nonce-tokens is cruciaal voor het versterken van de beveiliging van websites. Door unsafe-inline tags te verwijderen en escape-filters toe te passen, verklein je de risico’s van XSS-aanvallen en andere kwetsbaarheden. Deze aanpassingen hebben niet alleen de veiligheid van de website verhoogd, maar me ook een beter begrip van beveiligingsprincipes gegeven.

Dit project was een waardevolle ervaring in mijn rol als frontend developer bij Monkeyproof, en het heeft de websites waaraan ik werk beter beschermd tegen online bedreigingen.

Bron: Content-Security-Policy

Afbeeldingscredits: CSP

Leave a Comment

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *