softspring/response-headers

This component provides response headers configuration for Symfony projects


README

Latest Stable Latest Unstable License PHP Version Downloads CI Coverage

This component, made for Symfony, allows to set response headers defining them in configuration.

Installation

Applications that use Symfony Flex

Open a command console, enter your project directory and execute:

$ composer require softspring/response-headers

Basic configuration

Create a configuration file:

# config/packages/response_headers.yaml
parameters:
    response_headers:
        X-Frame-Options: "SAMEORIGIN"
        X-Content-Type-Options: "nosniff"

services:
    Softspring\Component\ResponseHeaders\EventListener\ResponseHeadersListener:
        tags: ['kernel.event_subscriber']
        arguments:
            $headers: '%response_headers%'

Use conditions

You can set some conditions to match before applying response headers.

Configure services

For this feature expression language component is required:

$ composer require symfony/expression-language

Then you must configure expression language service:

# config/packages/response_headers.yaml
parameters:
    response_headers_global_conditions: []
    response_headers:
        ...

services:
    softspring.response_headers.expression_language:
        class: Symfony\Component\ExpressionLanguage\ExpressionLanguage
        arguments:
            - '@?Psr\Cache\CacheItemPoolInterface'

    Softspring\Component\ResponseHeaders\EventListener\ResponseHeadersListener:
        tags: ['kernel.event_subscriber']
        arguments:
            $headers: '%response_headers%'
            $expressionLanguage: '@softspring.response_headers.expression_language'
            $globalConditions: '%response_headers_global_conditions%'

Define conditions

Now you can set a condition to be matched before applying a response header:

# config/packages/response_headers.yaml
parameters:
    response_headers:
        X-Frame-Options: 
            value: "SAMEORIGIN"
            condition: "request.getPathInfo() matches '^/admin'"
        Access-Control-Allow-Origin:
            value: "*"
            condition: "request.getPathInfo() matches '^/api'"

Define global conditions

Also you can set global conditions to be matched for every headers:

# config/packages/response_headers.yaml
parameters:
    response_headers_global_conditions:
        - 'isMainRequest'

This global condition is recommended, to avoid setting headers for sub-requests, but it's not mandatory.

Build conditions

For the conditions, request and response objects are available. Also a isMainRequest variable is defined.

Check Symfony expression-language documentation.

Headers configuration reference

There are several ways to define headers:

Single value header

# config/packages/response_headers.yaml
parameters:
    response_headers:
        X-Frame-Options: "SAMEORIGIN" 

This code generates a x-frame-options: "SAMEORIGIN" header.

Multiple value header

Multiple value headers, will be merged to a single string delimited by semicolons

# config/packages/response_headers.yaml
parameters:
    response_headers:
        Feature-Policy:
            - "geolocation 'self'"
            - "vibrate 'none'" 

This code generates a feature-policy: "geolocation 'self'; vibrate 'none'" header.

Value field

Also you can define the values into a value field:

# config/packages/response_headers.yaml
parameters:
    response_headers:
        X-Frame-Options: 
            value: "SAMEORIGIN" 
        Feature-Policy:
            value:
                - "geolocation 'self'"
                - "vibrate 'none'" 

This value field is mandatory if you want to set a condition or a replace behaviour.

Condition

As said before, headers could be restricted with conditions:

# config/packages/response_headers.yaml
parameters:
    response_headers:
        X-Frame-Options: 
            value: "SAMEORIGIN"
            condition: "request.getHost() == 'api.mydomain.com"

Replace behaviour

Symfony response allows to define if a header must replace a previous defined header value.

By default, this replace behaviour is defined as true. But you can disable it using:

# config/packages/response_headers.yaml
parameters:
    response_headers:
        X-Frame-Options: 
            value: "SAMEORIGIN"
            replace: false

Common security headers

This is an example witch defines common security headers:

# config/packages/response_headers.yaml
parameters:
    response_headers_global_conditions:
        - 'isMainRequest'
    response_headers:
        X-XSS-Protection:
            - "1"
            - "mode=block"
        X-Frame-Options: "SAMEORIGIN"
        X-Content-Type-Options: "nosniff"
        Strict-Transport-Security:
            - "max-age=31536000"
            - "includeSubDomains"
        Referrer-Policy: "same-origin"
        Feature-Policy:
            - "geolocation 'self'"
            - "vibrate 'none'"
            # ... include every feature the application uses.
        Content-Security-Policy:
            - "default-src 'none'"
            - "img-src 'self'"
            - "font-src 'self'"
            - "manifest-src 'self'"
            - "frame-src 'self'"
            - "script-src 'self' 'unsafe-inline'"
            - "style-src 'self' 'unsafe-inline'"
            - "connect-src 'self'"

Check Content-Security-Policy to include every base urls with services you use. Also try to avoid unsafe-inline configuration, this is up to your project.

License

This bundle is under the MIT license. See the complete license in the bundle LICENSE file.