veilletech.fr
27 août Feed du jour
#10 LARAVEL Article

Laravel 13.27 : vos données fuitent dans les logs

Vos logs en savent plus sur vos utilisateurs que vous ne croyez.

Laravel 13.27 ajoute une option par connexion qui masque les valeurs liées dans les messages de QueryException — jusqu'ici, une requête en échec écrivait les données insérées en clair dans les logs et dans failed_jobs. La version apporte aussi whereBinary() pour des comparaisons sensibles à la casse.

2 min de lecturevidéo 1:23
Partager
Sommaire5 sections
  1. Ce qui se passe
  2. Ce qui change
  3. whereBinary(), et le piège de la casse
  4. Deux correctifs à ne pas manquer
  5. À retenir

Ce qui se passe

QueryException interpole les valeurs liées dans son message. Un insert qui échoue place donc toutes les valeurs dans getMessage(), et ce message part partout où vont les exceptions : la table failed_jobs, les fichiers de journal, les traces de votre outil de supervision. Adresses e-mail, noms, tout ce qui était dans la requête.

Ce n'est pas une faille, c'est le comportement par défaut. Il est resté invisible parce que personne ne lit un message d'exception en se demandant ce qu'il contient.

Ce qui change

Une clé de configuration par connexion coupe l'interpolation et laisse les ? en place :

PHP
'mysql' => [
    'driver' => 'mysql',
    // ...
    'mask_bindings_in_exception_messages' => env('DB_MASK_BINDINGS', false),
],
TEXT
// par défaut
SQLSTATE[23000]: ... SQL: insert into `users` (`email`) values (foo@example.com)
// masqué
SQLSTATE[23000]: ... SQL: insert into `users` (`email`) values (?)

Deux points pratiques. La clé est livrée dans le config/database.php du framework : une application qui n'a jamais publié ce fichier l'active avec DB_MASK_BINDINGS=true seul. Et seul le message change — getBindings() retourne toujours les valeurs réelles, donc le débogage n'est pas dégradé.

whereBinary(), et le piège de la casse

Sous MySQL, une collation par défaut est insensible à la casse : chercher un nom égal à John retourne aussi john. Quatre méthodes apportent la comparaison octet à octet :

PHP
DB::table('queues')->whereBinary('name', $queueName)->first();
// select * from `queues` where `name` = binary ?
DB::table('queues')->whereNotBinary('name', $queueName)->get();

Avec orWhereBinary() et orWhereNotBinary(). MariaDB hérite de la grammaire MySQL, donc ça fonctionne aussi. Postgres, SQLite et SQL Server lèvent une RuntimeException — le même parti pris que whereLike() sur les moteurs déjà sensibles à la casse.

Deux correctifs à ne pas manquer

Request::merge(['*' => 226]) effaçait tout le tableau d'entrée au lieu d'y ajouter une clé *, parce que le réducteur passait les clés par data_set(), qui traite * comme un joker. Uri::withQuery() avait le même défaut un étage plus haut : ?role=user&tenant=10 devenait ?role=admin&tenant=admin. Les deux passent désormais par Arr::set().

MaintenanceModeBypassCookie::isValid() vérifiait que le mac du cookie était défini, pas qu'il était une chaîne. Un cookie laravel_maintenance portant un tableau le transmettait à hash_equals() et transformait un 503 attendu en 500 non authentifié. Le isset() est devenu is_string().

Source : Laravel News, Query Binding Masking and whereBinary() in Laravel 13.27 · masquage : PR #61326