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.allyouneedislove.org ;
# fichiers JS sur ce domaine => OK
Autoriser des contenus embarqués
img-src 'self' data: ;
# img en Data-Uri => OK
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 |
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
{
"csp-report": {
"blocked-uri": "",
"document-uri": "https://van11y.net/",
"original-policy": "default-src 'none'; script-src https://van11y.net; style-src https://van11y.net; img-src https://van11y.net; font-src https://van11y.net; connect-src https://van11y.net; child-src https://van11y.net; frame-ancestors 'none'; manifest-src https://van11y.net; report-uri https://van11y.net/csp-parser.php",
"referrer": "https://material.io/resizer/",
"violated-directive": "frame-ancestors 'none'"
}
}
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-123424242' ;
// $nonce_script = hash('sha512', random_bytes(42));
<script nonce="123424242">alert('coucou.');</script>
Doit être non trivial, non devinable, unique, regénéré à chaque fois :)
Content-Security-Policy:
default-src * data: ;
script-src * 'unsafe-inline' 'unsafe-eval' ;
style-src * 'unsafe-inline' data: ;
frame-ancestors 'none' ;
Équivalent de X-Frame-OptionsContent-Security-Policy:
default-src 'self' data: ;
script-src 'self' www.foo.com 'unsafe-inline' 'unsafe-eval' ;
style-src 'self' www.coincoin.com 'unsafe-inline' data: ;
frame-ancestors 'none' ;
Indiquez vos sources, plus de sélecteur wildcard (*)
Content-Security-Policy:
default-src 'self' data: ;
script-src 'self' www.foo.com 'unsafe-inline' 'unsafe-eval' ;
style-src 'self' www.coincoin.com data: ;
frame-ancestors 'none' ;
Plus d’unsafe-inline
pour les styles, data:
pour le JS
Content-Security-Policy:
default-src 'self' ;
script-src 'self' www.foo.com ;
style-src 'self' www.coincoin.com data: ;
frame-ancestors 'none' ;
Plus d’'unsafe-inline' 'unsafe-eval'
pour le JS
Content-Security-Policy:
default-src 'none' ;
script-src 'self' www.foo.com ;
style-src 'self' www.coincoin.com data: ;
frame-ancestors 'none' ;
report-uri /csp-parser.php
default-src 'none'
=> directives toutes définies
Une triade impossible à éviter
require-sri-for
)Bref :
Pour votre attention.
Pour discuter :
Nicolas Hoffmann / @Nico3333fr