Content Security Policy
=
« Politique de Sécurité des Contenus »
<?php
header("Content-Security-Policy: <vos directives>");
?>
Si aucune directive de définie pour un type de contenu
=> utilise cette valeur
default-src 'self' ;
# self = même port, nom de domaine, protocole => OK
Autoriser un nom de domaine
script-src 'self' www.google-analytics.com ;
# fichiers JS sur ce domaine => OK
Autoriser des contenus embarqués
img-src 'self' data: ;
# img en Data-Uri => OK
style-src => styles CSS
connect-src => AJAX, WebSocket, EventSource
font-src => webfonts
object-src => plugins (<object>, <embed>, <applet>)
media-src => <audio>, <video>
etc.
frame-src, form-action, frame-ancestors, manifest-src…
strict-dynamic…
Un exemple
<?php
header("content-security-policy: default-src 'none';
script-src 'self' www.google-analytics.com ;
style-src 'self' ;
img-src 'self' www.google-analytics.com data: ;
font-src 'self';
frame-ancestors 'none' ; ");
// Pas autorisé JS/CSS inline
// (<script>, onclick, <style> etc.) => ✖
?>
Tout ce qui n’est pas expressément autorisé dans les directives CSP… sera interdit.
Interdit = Bloqué, non affiché, non exécuté.
Et ça ne fait pas dans la demi-mesure…
Élément | Autorisé ? |
---|---|
styles_mini.css, jquery-mini.js | ☑ |
analytics.js (google-analytics.com) | ☑ |
evil.js (nicolas-hoffmann.net)
styles/JS inline |
NIET |
Plusieurs façons de faire…
Faut pas y craindre = bourrin => IDIOT
report-uri /csp-parser.php ;
# envoie les erreurs sur cette adresse
<?php
$data = file_get_contents('php://input');
if ($data = json_decode($data, true)) {
$data = json_encode(
$data,
JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES
);
mail(EMAIL, SUBJECT, $data);
}
?>
Voir CSP Report URI, exemples
Très verbeux, pensez à filtrer/utiliser report-uri.io
<?php
header("Content-Security-Policy-Report-Only: <vos directives>");
?>
Faire « comme si » pour tester des directives
<script>alert('Hello, world.');</script>
script-src …
'sha256-qznLcsROx4GACP2dm0UCKCzCG-HiZ1guq6ZZDob_Tng=' ;
<?php
echo base64_encode(hash('sha256', "alert('Hello, world.');", true));
?>
Nonce: Number used once
script-src …
'nonce-12345666789' ;
<script nonce="12345666789">alert('coucou.');</script>
Doit être non trivial, non devinable, unique, regénéré à chaque fois :)
Conclusion :
Pour votre attention.
Pour discuter :
Nicolas Hoffmann / @Nico3333fr