NelmioSecurityBundle

repository·master·Indexed 20 days ago

https://github.com/nelmio/nelmiosecuritybundle

A security enhancement bundle for Symfony applications providing configuration for common security headers and protections. Key features include Content Security Policy (CSP), Clickjacking prevention via X-Frame-Options, signed cookies, external redirect detection, forced or flexible HTTPS/SSL handling with HSTS, Referrer-Policy, Permissions-Policy, and Cross-Origin Isolation (COEP, COOP, CORP). It also includes built-in PHPUnit assertions for verifying security headers.

Tokens
12K
Snippets
36
Records
45
Agent score
72%

What's inside NelmioSecurityBundle

  1. Overview of NelmioSecurityBundle features

    master

    NelmioSecurityBundle provides several security enhancements for Symfony applications, including:

    • Content Security Policy (CSP): Mitigates XSS by instructing browsers on which scripts and domains are trusted.
    • Signed Cookies: Ensures cookies cannot be modified by the user (note: contents remain visible, they are only signed, not encrypted).
    • Clickjacking Protection: Adds X-Frame-Options headers to prevent your site from being embedded in iframes. Supports per-URL configuration.
    • External Redirects Detection: Protects against malicious redirects to arbitrary URLs.
    • Forced HTTPS/SSL Handling: Forces all requests to use SSL and sends HSTS headers.
    • Flexible HTTPS/SSL Handling: Detects logged-in users and redirects them to secure URLs without making session cookies insecure for all users.
    • Disable Content Type Sniffing: Forces browsers to use the correct MIME type for scripts, preventing content sniffing.
    • Referrer Policy: Adds the Referrer-Policy header to control how much referrer information is sent with requests.
    • XSS Protection (Deprecated): Enables/disables Microsoft XSS Protection for older browsers (IE 8+).
  2. Configure HTTPS/SSL Handling

    master

    The bundle offers two modes for handling HTTPS:

    Forced HTTPS/SSL

    Forces all requests to go through SSL and sends HSTS headers. Warning: Ensure SSL is working correctly before enabling this.

    Configuration keys:

    • hsts_max_age: The duration (in seconds) the browser should remember to use HTTPS.
    • hsts_subdomains: Whether to include subdomains in the HSTS policy.
    • redirect_status_code: The HTTP status code used for the redirect (default is 302).

    Flexible HTTPS/SSL

    Used when you don't want to force all users to HTTPS, but want to ensure logged-in users are redirected to a secure URL and that session cookies are secure.

    Configuration keys:

    • cookie_name: The name of the authentication cookie.
    • unsecured_logout: Boolean determining if logout is allowed on non-HTTPS connections.
  3. XSS Protection (DEPRECATED)

    master

    The xss_protection feature enables or disables Microsoft XSS Protection on compatible browsers.

    Caution: This feature is non-standard and deprecated. It is highly recommended to use Content Security Policy (CSP) instead.

    # config/packages/nelmio_security.yaml
    nelmio_security:
        xss_protection:
            enabled: true
            mode_block: true
            report_uri: '%router.request_context.base_url%/nelmio/xss/report'
  4. Use browser adaptive CSP directives

    master

    To reduce noise in your reports, you can enable browser_adaptive mode. This ensures the bundle only sends directives that the specific user agent's browser understands.

    Note: This requires parsing the User-Agent, which can be CPU-intensive. It is highly recommended to provide a cached parser service.

    ```yaml
    # config/packages/nelmio_security.yaml
    nelmio_security:
        csp:
            enforce:
                browser_adaptive:
                    enabled: true
                    parser: my_own_parser

    <!-- Example service definition for a cached parser --> <service id="my_own_parser" class="Nelmio\SecurityBundle\UserAgent\UAFamilyParser\PsrCacheUAFamilyParser"> <argument type="service" id="app.my_cache.pool"/> <argument type="service" id="nelmio_security.ua_parser.ua_php"/> <argument>604800</argument> </service>

  5. Report Cross-Origin Isolation violations to an endpoint

    master

    You can configure the bundle to send security violation reports to a specific endpoint using the report_to option. This requires you to separately configure the Reporting API endpoints using the Report-To or Reporting-Endpoints headers (typically via a CSP directive or a separate listener).

    # config/packages/nelmio_security.yaml
    nelmio_security:
        cross_origin_isolation:
            enabled: true
            paths:
                '^/.*':
                    coep:
                        value: require-corp
                        report_to: "coi-endpoint"
                    coop:
                        value: same-origin
                        report_to: "coi-endpoint"
  6. Install NelmioSecurityBundle via Composer

    master

    To add security features to your Symfony application, require the nelmio/security-bundle package using Composer. If you are using Symfony Flex, the bundle will be automatically enabled. If you are not using Flex, you must enable the bundle manually in your application configuration.

    composer require nelmio/security-bundle
  7. Setup security header testing with SecurityHeadersAssertionsTrait

    master

    To test security headers in your functional tests, use the SecurityHeadersAssertionsTrait. This trait provides a set of helper assertions that can be used within any test case extending Symfony's WebTestCase.

    To use it, import the trait into your test class. It is recommended to initialize your client with HTTPS => 'on' to ensure HSTS and other secure headers are correctly triggered during the test.

    <?php
    
    use Nelmio\\SecurityBundle\\Test\\SecurityHeadersAssertionsTrait;
    use Symfony\\Bundle\\FrameworkBundle\\Test\\WebTestCase;
    use Symfony\\Component\\HttpFoundation\\Request;
    
    class HomepageTest extends WebTestCase
    {
        use SecurityHeadersAssertionsTrait;
    
        public function testHomepageHasSecurityHeaders(): void
        {
            $client = static::createClient([], ['HTTPS' => 'on']);
            $client->request(Request::METHOD_GET, '/');
    
            static::assertIsIsolated();
            static::assertFrameOptions('DENY');
            static::assertContentTypeOptions();
            static::assertReferrerPolicy(['no-referrer', 'strict-origin-when-cross-origin']);
            static::assertStrictTransportSecurity();
            static::assertCspHeader();
        }
    }
  8. Upgrade Cookie Hashing Algorithms safely

    master

    To upgrade your hashing algorithm (e.g., from sha256 to sha3-256) without breaking existing user cookies, use the legacy_hash_algo option. This allows the bundle to verify old cookies using the old algorithm while signing new ones with the new one.

    Caution: This should only be used temporarily to prevent downgrade attacks.

    # config/packages/nelmio_security.yaml
    nelmio_security:
        signed_cookie:
            hash_algo: sha3-256
            legacy_hash_algo: sha256
  9. Set up CSP violation reporting

    master

    To collect and handle CSP violations, you must define a route that points to the bundle's reporter controller. The browser will POST a JSON payload to this URI whenever a policy is violated.

    1. Define the route in config/routes.yaml: The controller nelmio_security.csp_reporter_controller::indexAction handles the incoming POST requests.

    2. Configure the report endpoint in config/packages/nelmio_security.yaml to filter noise:

      • log_level: The Monolog level to use (e.g., notice).
      • filters: Enable/disable noise reduction for domains, schemes, browser_bugs, and injected_scripts.
      • dismiss: A list of key-value pairs to ignore specific violations (e.g., ignoring certain domains or regex patterns).
    # config/routes.yaml
    nelmio_security:
        path:     /my-csp-report
        defaults: { _controller: nelmio_security.csp_reporter_controller::indexAction }
        methods:  [POST]
    # config/packages/nelmio_security.yaml
    nelmio_security:
        csp:
            report_endpoint:
                log_level: "notice"
                filters:
                    domains: true
                    browser_bugs: true
                dismiss:
                    '/^data:/': 'script-src'
  10. Use Report-Only mode for Cross-Origin Isolation

    master

    To test security policies without blocking resources, use the report_only: true option. This instructs the bundle to use the Cross-Origin-Embedder-Policy-Report-Only or Cross-Origin-Opener-Policy-Report-Only headers instead of the enforcement headers. This is highly recommended for production testing to identify resources that lack necessary CORP headers before enforcing strict policies.

    # config/packages/nelmio_security.yaml
    nelmio_security:
        cross_origin_isolation:
            enabled: true
            paths:
                '^/.*':
                    coep:
                        value: require-corp
                        report_only: true
                    coop:
                        value: same-origin
                        report_only: true
  11. Handle inline scripts/styles with Message Digests (Hashes)

    master

    If you want to avoid using 'unsafe-inline', you can use message digests (hashes). The bundle supports configuring the algorithm (default is sha256; options are sha256, sha384, sha512) in the csp.hash.algorithm config key.

    Using Twig

    Use the {% cspscript %} and {% cspstyle %} tags. These tags automatically compute the digest for the content inside them and include it in the CSP header.

    Using ContentSecurityPolicyListener

    If you are not using Twig, you can manually add content to the listener, which will compute the digest automatically:

    {% cspscript %}
    <script>
        window.api_key = '{{ api_key }}';
    </script>
    {% endcscript %}
    $listener->addScript("<script>window.api_key = '{{ api_key }}';</script>");
    $listener->addStyle("<style>body { background-color: '{{ bgColor }}'; }</style>");
  12. Configure Flexible SSL handling

    master

    If you want to use secure session cookies (cookie_secure: true) but don't want to force SSL across your entire site, you can use the flexible_ssl feature.

    This feature works by setting a secondary insecure cookie (defaulting to auth) when a user logs in. If a logged-in user accesses an insecure page, the bundle uses this cookie to identify them and redirects them to the secure version of the page. This ensures logged-in users always interact via HTTPS while allowing anonymous users to remain on HTTP.

    Requirements:

    1. Enable flexible_ssl in nelmio_security.yaml.
    2. Add the nelmio_security.flexible_ssl_listener to the logout handlers of every firewall in security.yaml to ensure the special auth cookie is cleared upon logout.
    # config/packages/nelmio_security.yaml
    nelmio_security:
        flexible_ssl:
            cookie_name: auth
            unsecured_logout: false
    
    # config/packages/security.yaml
    security:
        firewalls:
            somename:
                logout:
                    handlers:
                        - nelmio_security.flexible_ssl_listener