49 lines
2 KiB
PHP
49 lines
2 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
use App\Models\Eleve;
|
||
|
|
|
||
|
|
function politique($reponse): array
|
||
|
|
{
|
||
|
|
return collect(explode(';', $reponse->headers->get('Content-Security-Policy')))
|
||
|
|
->mapWithKeys(function (string $d) {
|
||
|
|
$morceaux = preg_split('/\s+/', trim($d), 2);
|
||
|
|
|
||
|
|
return [$morceaux[0] => $morceaux[1] ?? ''];
|
||
|
|
})->all();
|
||
|
|
}
|
||
|
|
|
||
|
|
test("les pages de l'application ont une CSP stricte : pas de script en ligne sans le nonce", function () {
|
||
|
|
$eleve = Eleve::factory()->create();
|
||
|
|
$jeton = $eleve->demarreNouvelleSession();
|
||
|
|
|
||
|
|
$reponse = $this->withSession(['jeton_session_eleve' => $jeton])->actingAs($eleve, 'eleve')->get(route('eleve'));
|
||
|
|
$csp = politique($reponse);
|
||
|
|
|
||
|
|
expect($csp['script-src'])->toMatch("/^'self' 'nonce-[A-Za-z0-9+\\/=]+'$/")
|
||
|
|
->and($csp['script-src'])->not->toContain('unsafe-inline')
|
||
|
|
->and($csp['object-src'])->toBe("'none'")
|
||
|
|
->and($csp['frame-ancestors'])->toBe("'none'");
|
||
|
|
});
|
||
|
|
|
||
|
|
test('la page de connexion est stricte aussi, la vitrine tolère les scripts en ligne', function () {
|
||
|
|
expect(politique($this->get(route('login')))['script-src'])->not->toContain('unsafe-inline')
|
||
|
|
->and(politique($this->get(route('accueil')))['script-src'])->toContain("'unsafe-inline'");
|
||
|
|
});
|
||
|
|
|
||
|
|
test("chaque script de la page d'inscription porte le nonce de l'en-tête", function () {
|
||
|
|
$reponse = $this->get(route('register'));
|
||
|
|
preg_match("/'nonce-([^']+)'/", $reponse->headers->get('Content-Security-Policy'), $m);
|
||
|
|
|
||
|
|
preg_match_all('/<script\b[^>]*>/', $reponse->getContent(), $scripts);
|
||
|
|
expect($scripts[0])->not->toBeEmpty();
|
||
|
|
foreach ($scripts[0] as $balise) {
|
||
|
|
expect($balise)->toContain("nonce=\"{$m[1]}\"");
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
test('le rapport de violation est accepté sans jeton CSRF', function () {
|
||
|
|
$this->call('POST', route('csp.rapport'), [], [], [], ['CONTENT_TYPE' => 'application/csp-report'],
|
||
|
|
json_encode(['csp-report' => ['document-uri' => 'https://syllabuslab.fr/eleve?x=1', 'violated-directive' => 'script-src', 'blocked-uri' => 'inline']]))
|
||
|
|
->assertNoContent();
|
||
|
|
});
|