PHP : ajouter les directives "HttpOnly" et "Secure" aux cookies de session photo

PHP : sécuriser les cookies de session avec HttpOnly, Secure et SameSite

À l’heure où la grande majorité des sites web utilisent HTTPS, il n’est pas rare de constater que PHP sert encore ses cookies de session sans les attributs HttpOnly, Secure ou SameSite.

Pourtant, ces attributs sont essentiels pour durcir les cookies de session. Ils ne transforment pas une application vulnérable en coffre-fort suisse, mais ils réduisent plusieurs risques classiques : vol de cookie via JavaScript, transmission sur une connexion non chiffrée, ou envoi trop permissif dans certains contextes cross-site.

Heureusement, PHP permet de configurer ces directives directement depuis le fichier php.ini, depuis un pool PHP-FPM, depuis un fichier .user.ini, ou même depuis le code avec session_set_cookie_params().

À quoi servent HttpOnly, Secure et SameSite ?

Un cookie de session PHP ressemble souvent à ceci :

Set-Cookie: PHPSESSID=7d5h81tfiuna3p2p00o1v7b13q; path=/Code language: JavaScript (javascript)

Cette version fonctionne, mais elle reste trop permissive. On peut la renforcer avec plusieurs attributs :

  • HttpOnly empêche l’accès au cookie via JavaScript, notamment via document.cookie ;
  • Secure indique au navigateur de n’envoyer le cookie que via HTTPS ;
  • SameSite limite l’envoi du cookie dans les requêtes cross-site.

MDN recommande d’utiliser Secure pour que le cookie ne soit envoyé que sur HTTPS, et HttpOnly pour les cookies qui n’ont pas besoin d’être lus par JavaScript, notamment les identifiants de session.

Avec ces attributs, le cookie devient par exemple :

Set-Cookie: PHPSESSID=7d5h81tfiuna3p2p00o1v7b13q; path=/; secure; HttpOnly; SameSite=LaxCode language: JavaScript (javascript)

Activer les directives dans php.ini

La méthode la plus directe consiste à modifier le fichier php.ini utilisé par PHP-FPM.

Selon votre version de PHP, le chemin peut varier. Par exemple :

sudo nano /etc/php/8.3/fpm/php.ini

Ou, pour PHP 8.4 :

sudo nano /etc/php/8.4/fpm/php.ini

Recherchez ensuite les directives liées aux cookies de session :

session.cookie_httponly = 1
session.cookie_secure = 1
session.use_only_cookies = 1
session.cookie_samesite = "Lax"Code language: JavaScript (javascript)

Ces valeurs indiquent à PHP de servir le cookie de session avec HttpOnly, Secure et SameSite=Lax. La directive session.use_only_cookies force PHP à utiliser uniquement les cookies pour transmettre l’identifiant de session, plutôt que de l’accepter dans l’URL.

La documentation PHP précise que session.cookie_secure limite les cookies de session aux connexions HTTPS, et que session.cookie_httponly ajoute l’attribut HttpOnly au cookie de session.

Redémarrez ensuite PHP-FPM :

sudo systemctl restart php8.3-fpmCode language: CSS (css)

Ou adaptez selon votre version :

sudo systemctl restart php8.4-fpmCode language: CSS (css)

Avec les anciennes distributions, on voyait souvent cette syntaxe :

sudo service php7.2-fpm restartCode language: CSS (css)

Elle fonctionne encore dans certains environnements, mais systemctl est généralement préférable sur les distributions Linux récentes.

Vérifier le fichier php.ini réellement utilisé

Avant de modifier un fichier au hasard, vérifiez toujours quel fichier php.ini est réellement chargé.

En ligne de commande :

php --ini

Attention toutefois : la CLI et PHP-FPM n’utilisent pas forcément le même fichier php.ini. Pour un site web servi par Nginx ou Apache via PHP-FPM, il faut modifier la configuration FPM, pas seulement la configuration CLI.

Vous pouvez aussi créer temporairement un fichier de test :

<?php
phpinfo();Code language: HTML, XML (xml)

Puis cherchez les valeurs suivantes dans la page :

  • Loaded Configuration File ;
  • session.cookie_httponly ;
  • session.cookie_secure ;
  • session.cookie_samesite ;
  • session.use_only_cookies.

Supprimez ce fichier dès que le test est terminé. Un phpinfo() laissé en ligne, c’est une invitation à fouiller vos entrailles serveur. Peu élégant.

Configuration via un pool PHP-FPM

Sur un serveur qui héberge plusieurs sites, il peut être plus propre de configurer ces valeurs au niveau du pool PHP-FPM du site concerné.

Par exemple :

sudo nano /etc/php/8.3/fpm/pool.d/www.conf

Ajoutez ou adaptez ces directives :

php_admin_value[session.cookie_httponly] = 1
php_admin_value[session.cookie_secure] = 1
php_admin_value[session.use_only_cookies] = 1
php_admin_value[session.cookie_samesite] = Lax

Puis testez la configuration et redémarrez PHP-FPM :

sudo php-fpm8.3 -t
sudo systemctl restart php8.3-fpmCode language: CSS (css)

L’avantage de cette méthode : elle évite d’appliquer une règle globale à toutes les applications PHP du serveur. Elle convient donc mieux aux environnements multi-sites ou aux hébergements avec plusieurs pools dédiés.

Configuration via .user.ini

Si vous n’avez pas accès au php.ini, certains hébergeurs permettent d’utiliser un fichier .user.ini à la racine du site.

Dans ce cas, créez ou modifiez le fichier :

nano .user.iniCode language: CSS (css)

Et ajoutez :

session.cookie_httponly = 1
session.cookie_secure = 1
session.use_only_cookies = 1
session.cookie_samesite = "Lax"Code language: JavaScript (javascript)

Cette méthode dépend de la configuration de PHP-FPM et de l’hébergeur. Elle peut aussi mettre quelques minutes à être prise en compte, selon la valeur de user_ini.cache_ttl.

Définir les attributs depuis PHP

Si vous contrôlez le code de l’application, vous pouvez aussi définir les paramètres du cookie de session avant l’appel à session_start().

Depuis PHP 7.3, session_set_cookie_params() accepte un tableau d’options, dont secure, httponly et samesite.

<?php

session_set_cookie_params(
    [
        'lifetime' => 0,
        'path'     => '/',
        'domain'   => '',
        'secure'   => true,
        'httponly' => true,
        'samesite' => 'Lax',
    ]
);

session_start();Code language: HTML, XML (xml)

Cette méthode est pratique dans une application maison, car elle rend la configuration explicite dans le code. En revanche, elle doit impérativement être appelée avant session_start(), sinon elle arrive trop tard.

Pour une application existante, je préfère généralement configurer PHP-FPM ou php.ini, afin de durcir le comportement par défaut.

Quelle valeur choisir pour SameSite ?

La valeur SameSite mérite un peu d’attention.

  • SameSite=Lax convient à la majorité des sites classiques ;
  • SameSite=Strict est plus restrictif, mais peut casser certains parcours ;
  • SameSite=None autorise les contextes cross-site, mais exige Secure.

Pour un site web classique, un espace membre, un blog ou un back-office simple, SameSite=Lax est souvent le meilleur compromis.

SameSite=Strict peut empêcher l’envoi du cookie après un clic depuis un site externe. C’est parfois souhaitable, mais cela peut aussi surprendre les utilisateurs.

SameSite=None doit être réservé aux cas qui en ont réellement besoin : iframe cross-site, SSO, paiement embarqué, application découplée, intégration externe, ou cookie volontairement partagé dans un contexte tiers. Les navigateurs exigent alors aussi l’attribut Secure.

Tester les cookies avec curl

Après modification, on peut tester les en-têtes HTTP avec curl :

curl -I https://www.example.com/Code language: JavaScript (javascript)

Ou filtrer directement les cookies :

curl -sI https://www.example.com/ | grep -i '^set-cookie'Code language: JavaScript (javascript)

On cherche alors une ligne de ce type :

set-cookie: PHPSESSID=7d5h81tfiuna3p2p00o1v7b13q; path=/; secure; HttpOnly; SameSite=LaxCode language: JavaScript (javascript)

Si vous ne voyez aucun cookie PHPSESSID, ce n’est pas forcément un problème. Cela peut simplement vouloir dire que la page testée ne démarre pas de session PHP.

Dans ce cas, testez une page qui utilise réellement une session, comme une page de connexion, un panier, un espace membre, ou une application PHP qui appelle session_start().

Tester avec les outils développeur du navigateur

On peut aussi vérifier les cookies dans le navigateur.

  1. Ouvrez les outils développeur.
  2. Allez dans l’onglet Application ou Storage.
  3. Ouvrez la section Cookies.
  4. Sélectionnez le domaine du site.
  5. Vérifiez les colonnes HttpOnly, Secure et SameSite.

C’est souvent plus lisible que curl, surtout lorsqu’un site définit plusieurs cookies à différents moments du parcours.

Attention aux sites derrière un reverse proxy ou Cloudflare

Si PHP se trouve derrière un reverse proxy, un load balancer ou Cloudflare, il faut vérifier que l’application détecte correctement HTTPS.

Sinon, certains scripts peuvent croire que la requête arrive en HTTP, même si le visiteur utilise bien HTTPS côté navigateur. Cela peut empêcher l’application de définir correctement les cookies sécurisés.

Dans une application PHP maison, on peut vérifier les en-têtes comme X-Forwarded-Proto, à condition de ne faire confiance qu’aux proxys contrôlés. Dans WordPress, la plupart des hébergeurs et configurations modernes gèrent déjà ce point, mais il reste à surveiller lors d’une migration.

Et pour WordPress ?

WordPress ne repose pas sur PHPSESSID pour son authentification principale. Il utilise ses propres cookies, notamment pour la connexion, l’administration et les commentaires.

Configurer session.cookie_httponly et session.cookie_secure durcit donc les sessions PHP classiques, mais ne modifie pas automatiquement tous les cookies créés par WordPress, WooCommerce ou les plugins.

En revanche, c’est utile si :

  • un plugin démarre une session PHP ;
  • une application PHP cohabite avec WordPress ;
  • un espace membre utilise session_start() ;
  • un développement maison crée une session PHP ;
  • un scanner de sécurité signale un PHPSESSID sans attributs.

Pour les cookies propres à WordPress ou aux plugins, il faut vérifier chaque cookie dans les en-têtes HTTP. Certains attributs doivent être définis dans le code de l’application, d’autres peuvent être ajustés au niveau du serveur selon le contexte.

Ajouter des attributs aux cookies via Nginx

Dans l’article original, je mentionnais le module nginx_cookie_flag_module. Aujourd’hui, il vaut mieux éviter de s’appuyer sur ce vieux module abandonné si l’on peut faire autrement.

Nginx propose désormais la directive native proxy_cookie_flags pour ajouter ou modifier des attributs sur les cookies provenant d’un upstream. La documentation officielle montre par exemple l’ajout de httponly ou samesite=strict via cette directive.

Exemple avec un reverse proxy :

proxy_cookie_flags ~ secure httponly samesite=lax;

Ou pour cibler un cookie précis :

proxy_cookie_flags PHPSESSID secure httponly samesite=lax;

Attention : cette directive s’applique surtout aux cookies reçus depuis un upstream proxifié. Pour PHP-FPM en FastCGI classique, la meilleure solution reste de corriger la configuration PHP ou le code qui crée le cookie.

Et avec Apache ?

Avec Apache, on peut parfois ajuster les en-têtes Set-Cookie via mod_headers. Par exemple :

Header always edit Set-Cookie ^(.*)$ "$1; HttpOnly; Secure; SameSite=Lax"Code language: JavaScript (javascript)

Cette approche doit être utilisée avec prudence. Elle peut ajouter des attributs en double, modifier des cookies qui ne devraient pas l’être, ou casser certains cookies cross-site qui exigent SameSite=None; Secure.

Quand c’est possible, définissez les attributs au moment où le cookie est créé. Le serveur web peut dépanner, mais l’application reste l’endroit le plus propre pour exprimer l’intention.

Créer un cookie sécurisé avec setcookie()

Pour les cookies créés manuellement dans une application PHP, utilisez la syntaxe moderne de setcookie() avec un tableau d’options :

<?php

setcookie(
    'example_cookie',
    'example_value',
    [
        'expires'  => time() + 3600,
        'path'     => '/',
        'domain'   => '',
        'secure'   => true,
        'httponly' => true,
        'samesite' => 'Lax',
    ]
);Code language: HTML, XML (xml)

Cette syntaxe est plus lisible que l’ancienne suite d’arguments positionnels. Elle évite aussi les erreurs bêtes de type “j’ai mis true au mauvais endroit”, grand classique du PHP vintage.

Cas particulier : SameSite=None

Si un cookie doit fonctionner dans un contexte tiers, par exemple dans une iframe, une intégration externe, un SSO ou certains flux de paiement, vous aurez peut-être besoin de SameSite=None.

Dans ce cas, il faut impérativement ajouter Secure :

session.cookie_secure = 1
session.cookie_samesite = "None"Code language: JavaScript (javascript)

Sans Secure, les navigateurs modernes peuvent refuser le cookie. MDN précise que les cookies avec SameSite=None doivent aussi spécifier l’attribut Secure.

Ne choisissez donc pas SameSite=None par habitude. Utilisez-le uniquement si votre application en a réellement besoin.

Mémo rapide

# Fichier php.ini PHP-FPM.
sudo nano /etc/php/8.3/fpm/php.ini

# Directives recommandées pour un site HTTPS classique.
session.cookie_httponly = 1
session.cookie_secure = 1
session.use_only_cookies = 1
session.cookie_samesite = "Lax"

# Tester la configuration PHP-FPM.
sudo php-fpm8.3 -t

# Redémarrer PHP-FPM.
sudo systemctl restart php8.3-fpm

# Tester les cookies HTTP.
curl -sI https://www.example.com/ | grep -i '^set-cookie'Code language: PHP (php)

Conclusion

Pour sécuriser les cookies de session PHP sur un site HTTPS, la base moderne consiste à activer ces directives :

session.cookie_httponly = 1
session.cookie_secure = 1
session.use_only_cookies = 1
session.cookie_samesite = "Lax"Code language: JavaScript (javascript)

HttpOnly limite l’accès JavaScript au cookie, Secure empêche son envoi en HTTP, et SameSite=Lax réduit l’exposition aux requêtes cross-site sans casser la majorité des parcours classiques.

Pour une application PHP maison, vous pouvez aussi définir ces options directement avec session_set_cookie_params() avant session_start(). Pour WordPress, cette configuration durcit surtout les sessions PHP classiques, mais elle ne remplace pas un audit des cookies créés par le cœur, le thème et les plugins.

Enfin, vérifiez toujours le résultat avec curl ou les outils développeur du navigateur. En matière de cookies, la configuration déclarée compte moins que l’en-tête réellement envoyé. Le navigateur, lui, ne lit pas vos intentions. Fâcheux, mais juste.

Silverchair - Anthem For The Year 2000  photo

Silverchair – Anthem For The Year 2000

The early years

Silverchair est un groupe de rock australien, formé en 1992 en tant que Innocent Criminals à Merewether, à Newcastle, avec Ben Gillies à la batterie, Daniel Johns au chant et à la guitare, et Chris Joannou à la guitare basse – alors qu’ils n’ont que 12 ans.

Le groupe obtient son grand succès au milieu de 1994 en remportant un concours de démonstration national dirigé par la chaîne de télévision SBS Nomad et la station de radio ABC Triple J. Le groupe signe chez Murmur et collectionne succès sur les scènes australiennes et internationales.

Dans une interview accordée au magazine Melbourne Buzz en 1994, le groupe affirmait le nom du groupe était tiré de “Sliver” de Nirvana et de “Berlin Chair” de You Am I, qui avait donné “Silver Chair”.

Il a ensuite été révélé qu’ils avaient été nommés d’après le roman The Silver Chair de la série The Chronicles of Narnia, écrit par C. Lewis.

Frogstomp (1995)

Le premier album de Silverchair, Frogstomp, est enregistré en neuf jours avec une production de Kevin Shirley (Lime Spiders, Peter Wells) et est sorti en mars 1995. Au moment de l’enregistrement, les membres du groupe ont 15 ans et fréquentent toujours le lycée.

Frogstomp devient album numéro un en Australie et en Nouvelle-Zélande et atteint le Top 10 du Billboard 200, faisant de Silverchair le premier groupe australien à le faire depuis INXS.

Alors que Frogstomp et “Tomorrow” continuent de gagner en popularité en 1995, le groupe effectue une tournée aux États-Unis où il assurent la première partie des Red Hot Chili Peppers en juin, The Ramones en septembre et jouent sur le toit du Radio City Music Hall aux MTV Music Awards.

Freak Show (1996)

Silverchair commence à enregistrer son deuxième album studio, Freak Show, en mai 1996, alors qu’il connait le succès de Frogstomp en Australie et aux États-Unis. Il est produit par Nick Launay (Birthday Party, Models, Midnight Oil) et sort en février 1997.

Neon Ballroom (1999)

À la fin de 1997, le trio termine ses études secondaires et, à partir de mai 1998, il travaille sur son troisième album, Neon Ballroom, à nouveau produit par Launay.

L’album sort en mars 1999 et culmine au premier rang en Australie, avec trois singles du top 20 australien: “Anthem for the Year 2000”, “Ana’s Song (Open Fire)” et “Miss You Love”.

Diorama (2002)

En juin 2001, Silverchair entre en studio à Sydney avec le producteur David Bottrill (Tool, Peter Gabriel, King Crimson) pour commencer à travailler sur leur quatrième album, Diorama. Le nom de l’album signifie “un monde dans un monde”.

À la suite des ARIA Awards 2002, le groupe annonce un hiatus indéterminé. Johns a déclaré que c’était nécessaire “étant donné que le groupe était ensemble depuis plus de dix ans et n’avait que 23 ans en moyenne”.

Young Modern (2007)

Young Modern sort en mars 2007 et ils deviennent les premiers artistes à posséder cinq albums numéro un. En juin, Silverchair et le groupe de rock Powderfinger annoncent la tournée Across the Great Divide.

La tournée permet de promouvoir les efforts de Reconciliation Australia visant à combler l’écart de 17 ans d’espérance de vie entre enfants autochtones et non autochtones. Les acteurs de la tournée sont John Butler, Missy Higgins, Kev Carmody, Troy Cassar-Daley, Clare Bowditch et Deborah Conway.

Le 25 mai 2011, Silverchair announce un hiatus indéterminé:

We formed Silverchair nearly 20 years ago when we were just 12 years old. Today we stand by the same rules now as we did back then … if the band stops being fun and if it’s no longer fulfilling creatively, then we need to stop. […] Despite our best efforts over the last year or so, it’s become increasingly clear that the spark simply isn’t there between the three of us at the moment. Therefore after much soul searching we wanted to let you know that we’re putting Silverchair into “indefinite hibernation” and we’ve decided to each do our own thing for the foreseeable future.

— Daniel, Ben and Chris, chairpage.com (Silverchair Official Website), 25 May 2011.
Résoudre l'erreur "/var/cache/debconf/config.dat is locked by another process: Resource temporarily unavailable" photo

Résoudre l’erreur “/var/cache/debconf/config.dat is locked by another process: Resource temporarily unavailable”

Lors d’une mise à jour APT, il arrive qu’un installeur vous demande s’il faut écraser ou non un des fichiers de configuration existant. C’est le cas notamment de certaines versions de PHP qui requièrent une mise à jour du fichier php.ini.

Si vous êtes derrière votre terminal, pas de problème. Si par contre, vous ne prêtez pas attention à votre terminal, pensant que tout s’est mis à jour, ou si votre connexion SSH est rompue lors de l’installation, vous risquez d’avoir dpkg en vrac, avec une installation de paquet qui restera ‘en cours”.

Concrètement, vous obtiendrez un de ces messages:

debconf: DbDriver "config": /var/cache/debconf/config.dat is locked by another process: Resource temporarily unavailable
dpkg: error processing package XXXXX:amd64 (--configure):
 subprocess installed post-installation script returned error exit status 1
Errors were encountered while processing:
 XXXXX:amd64
needrestart is being skipped since dpkg has failed
E: Sub-process /usr/bin/dpkg returned an error code (1)Code language: PHP (php)

Mais pas de panique, il est très simple de résoudre le problème en quelques commandes.

Commencez par vérifiez quel est le processus responsable du fichier en question:

fuser -v /var/cache/debconf/config.datCode language: JavaScript (javascript)

Résultat :

USER        PID ACCESS COMMAND
/var/cache/debconf/config.dat:
root       8756 F.... frontendCode language: JavaScript (javascript)

Il ne nous reste plus qu’à tuer proprement le processus:

kill 8756

Il ne vous reste plus qu’à relancer vos commandes apt habituelles, tout est redevenu opérationnel.