Laravel Security Headers
Published: 2022-06-04 21:13:17

---
title: Laravel Security Headers
published: true
date: 2022-06-04 07:50:00 UTC
tags: 
canonical_url: https://dcblog.dev/laravel-security-headers
---

 ![Laravel Security Headers](https://dcblog.dev/images/posts/laravel-security-headers.png) 

This weekend, I changed the design of this blog whilst doing so I wanted to add the security headers for content security policies, these tell the application what it can and cannot run, There's a great website called [https://securityheaders.com](https://securityheaders.com/) which will scan a URL and tell you what your level is.

If you have no headers set up you'll get an F grade, which is bad! 

Before I started my rating:

![an F grade website](https://dcblog.dev/assets/images/blog/development/security-headers/security-headers-fail.png)

Once I finished I have an A rating:

![A rating](https://dcblog.dev/assets/images/blog/development/security-headers/security-headers-pass.png)

For detailed information about security headers read Daniel Dušek blog that explains this really well [https://danieldusek.com/enabling-security-headers-for-your-website-with-php-and-laravel.html](https://danieldusek.com/enabling-security-headers-for-your-website-with-php-and-laravel.html) 

Still here? great I'll go over what I've done.

I created a middleware class called SecurityHeaders.php inside **App\Http\Middleware** of my Laravel application

Add this middleware to the Middleware group inside App\Http\Kernal.php 

```

protected $middleware = [
    // \App\Http\Middleware\TrustHosts::class,
    \App\Http\Middleware\TrustProxies::class,
    \Fruitcake\Cors\HandleCors::class,
    \App\Http\Middleware\PreventRequestsDuringMaintenance::class,
    \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
    \App\Http\Middleware\TrimStrings::class,
    \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
    \App\Http\Middleware\SecurityHeaders::class,
];
```

Set the headers to be turned off, this provide would be attackers information about the server, you don't need to advertise these to better to turn them off.

```

private $unwantedHeaders = ['X-Powered-By', 'server', 'Server'];
```

## Referrer Policy

Sets how much information should be sent with requests, in my case I chose the option to not send the referer header for requests to less secure destinations.

```

$response->headers->set('Referrer-Policy', 'no-referrer-when-downgrade');
```

## XSS Protection

Stops loading of pages when they detect reflected cross-site scripting (XSS) attacks

I set: Enables XSS filtering. Rather than sanitizing the page, the browser will prevent rendering of the page if an attack is detected.

```

$response->headers->set('X-XSS-Protection', '1; mode=block');
```

## Strict Transport Security

informs browsers that the site should only be accessed using HTTPS

```

$response->headers->set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
```

## Content Security Policy

The content security policy sets weather a browser can run JS / CSS on page load.

You will want to either det a URL specifically or a wildcard like \*.domain to allow the subdomain of the given domain to run

```

$response->headers->set('Content-Security-Policy', "default-src 'self'; script-src 'self' platform.twitter.com 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' * data:; font-src 'self' data: ; connect-src 'self'; media-src 'self'; frame-src 'self' platform.twitter.com github.com *.youtube.com *.vimeo.com; object-src 'none'; base-uri 'self'; report-uri ");
```

## Expect-CT

The Expect-CT header lets sites opt in to reporting and/or enforcement of Certificate Transparency requirements

```

$response->headers->set('Expect-CT', 'enforce, max-age=30');
```

## Permissions-Policy

Sets what permissions the device load the page is given

```

$response->headers->set('Permissions-Policy', 'autoplay=(self), camera=(), encrypted-media=(self), fullscreen=(), geolocation=(self), gyroscope=(self), magnetometer=(), microphone=(), midi=(), payment=(), sync-xhr=(self), usb=()');
```

## The complete class:

With this class in place upload your changes to your server and re-run [https://securityheaders.com](https://securityheaders.com)

```

<?php

namespace App\Http\Middleware;

use Closure;

class SecurityHeaders
{
    private $unwantedHeaders = ['X-Powered-By', 'server', 'Server'];

    /**
     * @param $request
     * @param Closure $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        $response = $next($request);

        if (!app()->environment('testing')) {
            $response->headers->set('Referrer-Policy', 'no-referrer-when-downgrade');
            $response->headers->set('X-XSS-Protection', '1; mode=block');
            $response->headers->set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
            $response->headers->set('Content-Security-Policy', "default-src 'self'; script-src 'self' platform.twitter.com plausible.io utteranc.es *.cloudflare.com 'unsafe-inline' 'unsafe-eval' plausible.io/js/plausible.js utteranc.es/client.js; style-src 'self' *.cloudflare.com 'unsafe-inline'; img-src 'self' * data:; font-src 'self' data: ; connect-src 'self' plausible.io/api/event; media-src 'self'; frame-src 'self' platform.twitter.com plausible.io utteranc.es github.com *.youtube.com *.vimeo.com; object-src 'none'; base-uri 'self';");
            $response->headers->set('Expect-CT', 'enforce, max-age=30');
            $response->headers->set('Permissions-Policy', 'autoplay=(self), camera=(), encrypted-media=(self), fullscreen=(), geolocation=(self), gyroscope=(self), magnetometer=(), microphone=(), midi=(), payment=(), sync-xhr=(self), usb=()');
            $response->headers->set('Access-Control-Allow-Origin', '*');
            $response->headers->set('Access-Control-Allow-Methods', 'GET,POST,PUT,PATCH,DELETE,OPTIONS');
            $response->headers->set('Access-Control-Allow-Headers', 'Content-Type,Authorization,X-Requested-With,X-CSRF-Token');

            $this->removeUnwantedHeaders($this->unwantedHeaders);
        }

        return $response;
    }

    /**
     * @param $headers
     */
    private function removeUnwantedHeaders($headers): void
    {
        foreach ($headers as $header) {
            header_remove($header);
        }
    }
}

```