Securing Laravel Horizon with CSP: A Case Study
When using Laravel Horizon, a queue monitoring tool, you might encounter issues with Content Security Policy (CSP) blocking inline scripts. Here's how to address it.
The Problem
Horizon serves its JavaScript and CSS inline using Horizon::js() and Horizon::css(). Without a proper nonce for CSP, browsers can block these inline scripts, even though Horizon's own authentication gate restricts access to super admins.
The Solution
The key is to exclude Horizon routes from CSP checks, allowing its inline scripts to load without browser intervention.
First, you'll need to identify the routes associated with Horizon. Then, you can adjust your CSP configuration to exclude these routes. A common approach is to modify the middleware that applies CSP rules.
Here's an example of how you might adjust your CSP middleware:
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class ContentSecurityPolicy
{
public function handle(Request $request, Closure $next): Response
{
if ($request->is('horizon/*')) {
return $next($request);
}
$response = $next($request);
$response->headers->set('Content-Security-Policy', "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';");
return $response;
}
}
This code snippet checks if the incoming request path starts with horizon/. If it does, the middleware skips adding the CSP headers, effectively excluding Horizon routes from CSP restrictions. This allows the inline scripts and styles served by Horizon to load correctly.
The Result
By excluding Horizon routes from CSP, you allow its inline scripts to load, ensuring the Horizon dashboard functions correctly while maintaining a secure CSP for the rest of your application.
The Takeaway
When using packages that rely on inline scripts, carefully evaluate whether to exclude their routes from CSP checks or implement a nonce-based solution. Always prioritize security while ensuring functionality.