Headers, CSP en nonces

CSP headers en script tags genereren met een nonce
CSP headers via functions.php

In het bericht over beveiliging van de website hebben we het gehad over het toevoegen van content security policy (CSP) headers via het htaccess bestand. Er is ook een andere manier om headers toe te voegen. Dit kan door wijzigingen aan te brengen in het functions.php bestand. Dit kun je vinden onder de thema map van de wordpress installatie (wordpress/wp-content/themes). Maar waarom zou je dat doen als het ook werkt via htaccess? Dat is een goede vraag.

Ik heb jarenlang het CSP beleid voor deze site toegevoegd via htaccess. Daarin kun je sha256 hash waarden opnemen en eigenlijk is dit niet veel werk. De scripts veranderen nauwelijks waardoor de hash waarden hooguit eens per jaar wijzigen. Als je toch regelmatig aan je site werkt, is dit geen enkel probleem. Vaak heb ik me afgevraagd hoe ik de toepassing van scripts kan toestaan via een nonce waarde.

Nonce-waarden

Scott Helme publiceert regelmatig over beveiliging van internet en is een groot voorstander van de toepassing van een strikt CSP beleid. Beveilig de toegang tot de website door alleen die scripts toe te staan die aantoonbaar ongewijzigd van de server van de site door de browser worden opgehaald. Een nonce is de samenvoeging van het woord ‘Number Only Used Once’ en dat is ook precies wat het is. Een nonce is namelijk een willekeurig getal dat wordt gebruikt in cryptografische algoritmen (bron: beursgids.nl). Een belangrijke eis voor het gebruik van een nonce is om het onmogelijk te maken een stuk informatie tweemaal te gebruiken.

In het bericht over CSP nonces beschrijft Helme wat een nonce is en hoe je een nonce waarde door de server kunt laten genereren. Deze noncewaarde wordt vervolgens aan de tag van het script toegevoegd. Bij het lezen van de script controleert de browser of dezelfde nonce-waarde in de CSP header onder de CSP-directive script-src aanwezig is. Indien dat zo is, dan staat de browser het lezen van het script toe. Indien niet, dan wordt het script geblokkeerd en verschijnt een foutmelding in de console. De webpagina wordt dan niet goed weergegeven omdat het script niet geladen wordt.

PHP code voor het genereren van een nonce waarde

Een eenvoudige manier om een nonce te genereren en deze toe te voegen aan de script tag, kan met de onderstaande code. Voeg deze toe aan het einde van het functions.php bestand. De nonce waarde die in de script tag wordt opgenomen, moet (bij voorkeur) base64 encoded zijn. Een vereiste die immuniweb heeft opgenomen bij het waarderen van de beveiliging van een website.

// GENEREER EEN NONCE WAARDE EN DEFINIEER DEZE WAARDE
add_action( 'run_custom_nonce_value', 'custom_nonce_value' );
function custom_nonce_value () {
$created_nonce = wp_create_nonce();
define( 'NONCE_RANDVALUE', $created_nonce );
}

// VOEG NONCE TOE AAN DE SCRIPT TAG
add_filter( 'script_loader_tag', 'add_nonce_to_script', 10, 3 );
function add_nonce_to_script( $tag, $handle, $source ) {
custom_nonce_value();
$val_nonce = NONCE_RANDVALUE;
$search = "<script";
$replace = "<script type='text/javascript' nonce='".$val_nonce."'";
$subject = $tag;

$output = str_replace($search, $replace, $subject);
return $output;
}

Nu de nonce waarde gegenereerd is, is de volgende stap om deze toe te voegen aan de header met de informatie over het CSP beleid. Ook in de header moet de nonce waarde base64 encoded zijn.

// VOEG NONCE WAARDEN TOE AAN CSP EN VOEG CSP HEADERS IN
function CSP_headers($CSP) {
custom_nonce_value();
$val_nonce = NONCE_RANDVALUE;
$val_nonce = base64_encode($val_nonce);
$CSP['Content-Security-Policy'] = "....; script-src 'self' https://umami.adagia.eu https://hcaptcha.com https://*.hcaptcha.com 'nonce-" . $val_nonce . "' ....";
return $CSP;
}
add_filter( 'wp_headers', 'CSP_headers' );

In de bron-weergave van de webpagina kun je vaststellen dat een nonce waarde is gegenereerd en toegevoegd aan de script tag.

schermafbeelding paginabron script nonce
Figuur Schermafbeelding paginabron script met nonce NGU2..

De headers van de webpagina laten ook zien dat de CSP headers de nonce waarde bevatten. Open de webontwikkelaarsconsole in de browser en ga naar het tabje netwerk. Selecteer de (bovenste) regel met de hoofdlink van de webpagina en blader naar de CSP informatie. Hieronder heb ik deze opgenomen voor de CSP header van adagia.eu.

schermafbeelding knipsel csp header
Figuur Schermafbeelding knipsel van de csp header met nonce NGU2…
Tags voor stylesheets uitbreiden met een nonce

Naast de te laden scripts kunnen ook de te laden stylesheets worden voorzien van een nonce. In plaats van de functie 'script_loader_tag' maak ik hier gebruik van de functie style-loader-tag van WordPress.

// VOEG NONCE TOE AAN DE LINK STYLESHEET TAG
add_filter( 'style_loader_tag', 'add_nonce_to_stylesheet', 10, 3 );
function add_nonce_to_stylesheet( $tag, $handle ) {
custom_nonce_value();
$val_nonce = NONCE_RANDVALUE;
$val_nonce = base64_encode($val_nonce);
$search = "<link rel='stylesheet'";
$replace = "<link rel='stylesheet' nonce='".$val_nonce."'";
$subject = $tag;
$output = str_replace($search, $replace, $subject);
return $output;
};

Overige http headers toevoegen via functions.php

Naast de CSP header kun je zo ook andere security http headers toevoegen. Op deze site had ik eerst de configuratie van de http headers ingesteld in het .htaccess configuratiebestand. In de vernieuwde versie van adagia.eu heb ik de koppeling aangebracht via het thema bestand functions.php. Zie onderstaand voorbeeld voor de code in php om de headers toe te voegen, waaronder de CSP headers. De syntaxis is net iets anders maar de inhoud is gelijk.

// VOEG OVERIGE HEADERS TOE
header("Strict-Transport-Security: max-age=63072000; includeSubDomains; preload");
header("Permissions-Policy: camera=(),clipboard-read=(),clipboard-write=(),geolocation=(),microphone=(),publickey-credentials-get=(),sync-xhr=(self)");
header("Cross-Origin-Embedder-Policy: 'require-corp'");
header("Cross-Origin-Opener-Policy: 'same-origin'");
header("X-Permitted-Cross-Domain-Policies: 'none'");
header("X-Content-Type-Options: nosniff");
header("X-Frame-Options: SAMEORIGIN");
header("X-XSS-Protection: 0");
header("X-DNS-Prefetch-Control: on");
header("Referrer-Policy: strict-origin");

 

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *