Laravel Security Headers
David Carr
Posted on June 4, 2022
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 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:
Once I finished I have an A rating:
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
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
<?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);
}
}
}
Posted on June 4, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 30, 2024
November 30, 2024