libertjeremy / symfony-security-helpers
Package info
github.com/libertjeremy/symfony-security-helpers
pkg:composer/libertjeremy/symfony-security-helpers
Requires
- php: ^8.3
- symfony/event-dispatcher: ^6.4 || ^7.0 || ^8.0
- symfony/http-foundation: ^6.4 || ^7.0 || ^8.0
- symfony/http-kernel: ^6.4 || ^7.0 || ^8.0
- symfony/security-core: ^6.4 || ^7.0 || ^8.0
- symfony/string: ^6.4 || ^7.0 || ^8.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.64
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^12.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-11-03 07:45:03 UTC
README
Security helpers for Symfony 6.4, 7.x and 8.x applications: a voter helper trait and a configurable HTTP
security-headers listener. The wiring (configuration, services) lives in
symfony-security-helpers-bundle.
Security headers
SecurityHeadersPolicy is a readonly value object describing the headers to send;
SecurityHeadersListener (an event subscriber) adds them to every main-request response.
- A header already present on the response is never overridden.
Strict-Transport-Securityis sent on secure requests only.- Paths listed in
excludedPaths(prefix match on a path boundary, e.g./_profiler) get no header. - Every CSP source and Permissions-Policy entry is validated, so a value cannot inject another directive or header.
- CSP nonce (optional): list the directives that must receive it in
nonceDirectives; the listener generates one per request and stores it in the_csp_noncerequest attribute (SecurityHeadersListener::NONCE_ATTRIBUTE).
Example: a PWA that scans barcodes with WebAssembly
use LibertJeremy\Symfony\SecurityHelpers\EventListener\SecurityHeadersListener; use LibertJeremy\Symfony\SecurityHelpers\Header\ContentSecurityPolicy; use LibertJeremy\Symfony\SecurityHelpers\Header\Hsts; use LibertJeremy\Symfony\SecurityHelpers\Header\PermissionsPolicy; use LibertJeremy\Symfony\SecurityHelpers\Header\SecurityHeadersPolicy; $policy = new SecurityHeadersPolicy( hsts: new Hsts(maxAge: 31536000, includeSubDomains: true), contentSecurityPolicy: new ContentSecurityPolicy([ 'default-src' => ["'self'"], 'script-src' => ["'self'", "'wasm-unsafe-eval'"], 'style-src' => ["'self'"], 'img-src' => ["'self'", 'data:', 'blob:'], 'connect-src' => ["'self'", 'https://world.openfoodfacts.org'], 'font-src' => ["'self'"], 'manifest-src' => ["'self'"], 'worker-src' => ["'self'"], 'frame-ancestors' => ["'none'"], 'base-uri' => ["'self'"], 'form-action' => ["'self'"], ]), permissionsPolicy: new PermissionsPolicy([ 'camera' => ['self'], 'microphone' => ['self'], 'geolocation' => [], ]), referrerPolicy: 'strict-origin-when-cross-origin', frameOptions: 'DENY', excludedPaths: ['/_profiler', '/_wdt'], ); $dispatcher->addSubscriber(new SecurityHeadersListener($policy));
This sends Permissions-Policy: camera=(self), microphone=(self), geolocation=() and the CSP
default-src 'self'; script-src 'self' 'wasm-unsafe-eval'; style-src 'self'; img-src 'self' data: blob:; connect-src 'self' https://world.openfoodfacts.org; font-src 'self'; manifest-src 'self'; worker-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'.
Development
composer install
vendor/bin/phpunit
vendor/bin/phpstan analyse # level 10
vendor/bin/php-cs-fixer fix --dry-run --diff