380aedb04e
Report-Only политика в middleware SecurityHeaders; Pest 6/6 GREEN. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
41 lines
1.7 KiB
PHP
41 lines
1.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* SecurityHeaders middleware — безопасные HTTP-заголовки на всех web-ответах.
|
|
* Закрывает ZAP Medium «Missing Anti-clickjacking Header» (go-live аудит 17.06.2026).
|
|
* Бьём по публичному / (welcome SPA) — auth и БД не нужны.
|
|
*/
|
|
|
|
test('публичный / отдаёт заголовок X-Frame-Options SAMEORIGIN', function () {
|
|
$this->get('/')->assertHeader('X-Frame-Options', 'SAMEORIGIN');
|
|
});
|
|
|
|
test('публичный / отдаёт X-Content-Type-Options nosniff', function () {
|
|
$this->get('/')->assertHeader('X-Content-Type-Options', 'nosniff');
|
|
});
|
|
|
|
test('публичный / отдаёт Referrer-Policy strict-origin-when-cross-origin', function () {
|
|
$this->get('/')->assertHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
|
|
});
|
|
|
|
test('публичный / отдаёт непустой Content-Security-Policy-Report-Only', function () {
|
|
$csp = $this->get('/')->headers->get('Content-Security-Policy-Report-Only');
|
|
|
|
expect($csp)->not->toBeNull()
|
|
->and($csp)->toContain("default-src 'self'");
|
|
});
|
|
|
|
test('CSP Report-Only выверен под Vuetify-инлайн-стили и шрифты Google', function () {
|
|
$csp = $this->get('/')->headers->get('Content-Security-Policy-Report-Only');
|
|
|
|
expect($csp)->toContain("frame-ancestors 'self'")
|
|
->and($csp)->toContain("style-src 'self' 'unsafe-inline' https://fonts.googleapis.com")
|
|
->and($csp)->toContain('https://fonts.gstatic.com');
|
|
});
|
|
|
|
test('на шаге Report-Only блокирующий Content-Security-Policy НЕ ставится', function () {
|
|
$this->get('/')->assertHeaderMissing('Content-Security-Policy');
|
|
});
|