Aller au contenu
Patrick Junod

← Blog

Gestion des CORS sur Laravel via un Middleware

· 1 min

En bref

  • Un middleware Laravel ContentSecurityPolicy définit les en-têtes Content-Security-Policy et CORS de l'application.
  • Il est enregistré dans le groupe de middleware web.
  • La directive script-src autorise unsafe-eval pour Alpine.js ; chaque domaine externe (ex. une iframe OpenStreetMap) doit être ajouté explicitement.

La sécurité est un aspect crucial du développement web moderne, particulièrement lorsqu'il s'agit de gérer les requêtes cross-origin (CORS). Dans cet article, nous allons explorer comment implémenter une solution robuste de gestion des CORS sur Laravel à l'aide d'un middleware personnalisé.

Qu'est-ce que les CORS ?

Les CORS (Cross-Origin Resource Sharing) sont un mécanisme qui permet à un serveur web d'indiquer les origines autorisées à accéder à ses ressources. Cette sécurité est essentielle pour protéger vos applications contre les accès non autorisés.

Implémentation du Middleware

Notre solution s'articule autour de deux fichiers principaux : le Kernel.php et un middleware personnalisé ContentSecurityPolicy.php.

1. Configuration du Kernel

Dans le fichier Kernel.php, nous déclarons notre middleware dans le groupe 'web' :

protected $middlewareGroups = [
    'web' => [
        // Autres middlewares...
        \App\Http\Middleware\ContentSecurityPolicy::class,
    ],
];

2. Le Middleware ContentSecurityPolicy

Le middleware ContentSecurityPolicy est le cœur de notre solution. Il définit les politiques de sécurité et les en-têtes CORS nécessaires.

Créez un fichier “ContentSecurityPolicy.php” dans votre dossier Middleware :

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Config;

class ContentSecurityPolicy
{
    public function handle(Request $request, Closure $next)
    {
        $response = $next($request);

        // Content Security Policy (CSP)
        $cspDirectives = [
            "default-src" => "'self'",
            "script-src" => "'self' 'unsafe-inline' 'unsafe-eval'",
            "style-src" => "'self' 'unsafe-inline'",
            "img-src" => "'self' data: https:",
            "font-src" => "'self' data:",
            "connect-src" => "'self'",
            "media-src" => "'self'",
            "object-src" => "'none'",
            "frame-src" => "'self'",
            "frame-ancestors" => "'self'",
            "base-uri" => "'self'",
            "form-action" => "'self'",
            "upgrade-insecure-requests" => null
        ];

        $cspHeader = implode('; ', array_map(
            function ($key, $value) {
                return $value === null ? $key : "$key $value";
            },
            array_keys($cspDirectives),
            $cspDirectives
        ));

        // Set security headers
        $response->headers->set('Content-Security-Policy', $cspHeader);
        $response->headers->set('X-Content-Type-Options', 'nosniff');
        $response->headers->set('Referrer-Policy', 'strict-origin-when-cross-origin');
        $response->headers->set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');

        // Set Permissions-Policy header with commonly restricted features
        $response->headers->set('Permissions-Policy',
            'accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=(), interest-cohort=()'
        );

        $response->headers->remove('X-Powered-By');
        $response->headers->remove('server');

        return $response;
    }
}

Dans notre exemple, nous autorisons le script-src à “unsafe-eval” pour AlpineJS. Si vous souhaitez tout de fois être plus stricte et ne pas l’inclure, vous pouvez vous rendre ici pour une version d’AlpineJS plus stricte en matière d’eval: https://alpinejs.dev/advanced/csp

Bien entendu, ajoutez les domaines autorisés pour chacun des cas de votre application. Si vous souhaitez par exemple ajouter une iframe openstreetmap, modifiez vos CSP comme cela:

// Content Security Policy (CSP)
$cspDirectives = [
    // autres directives ...
    "frame-src" => "'self' https://www.openstreetmap.org/",
];

Écrit par Patrick Junod, développeur fullstack à Neuchâtel. Une question ou une remarque : contact@patrickjunod.dev