Situation actuelle : PHP2Shell. Deux failles PHP critiques (CVSS 9.2) permettent d'exécuter du code malveillant sans authentification. Correctifs disponibles depuis le 21 octobre 2026.Ce qu'il faut faire maintenant →

Les fonctions de sécurité intégrées de PHP

PHP fournit des briques sûres pour les mots de passe, les valeurs aléatoires, l'échappement, la cryptographie et les sessions. Qui les utilise systématiquement évite les erreurs d'application les plus courantes.

État 6 min de lectureSavoir PHP

En bref : pour les tâches de sécurité les plus courantes, PHP fournit des fonctions toutes prêtes et éprouvées : password_hash() pour les mots de passe, random_bytes() et random_int() pour les jetons, htmlspecialchars() contre le cross-site scripting, les requêtes préparées avec PDO contre l'injection SQL, hash_equals() pour des comparaisons sûres et l'extension Sodium pour la cryptographie. Qui utilise systématiquement ces briques évite la plupart des failles d'application. Contre les erreurs de l'interpréteur PHP lui-même, comme avec PHP2Shell, elles n'aident pas ; seule la mise à jour y remédie.

Pourquoi des fonctions de sécurité intégrées à PHP ?

Écrire soi-même du code de sécurité est source d'erreurs. Un hachage de mot de passe maison, un générateur de jetons bricolé ou un filtre artisanal pour les sorties HTML semblent souvent corrects et ne le sont pourtant pas. Les fonctions intégrées sont documentées, testées et maintenues avec les mises à jour de PHP.

Pour les décideurs, cela signifie : ne demandez pas à votre agence ou à votre équipe de développement si des fonctions de sécurité ont été développées en interne, mais si les fonctions standard du langage sont utilisées. Le tableau en donne un aperçu.

Tâche Fonction Disponible depuis Remarque importante
Stocker des mots de passe password_hash(), password_verify() PHP 5.5 colonne jusqu'à 255 caractères ; bcrypt tronque à 72 octets
Jetons aléatoires random_bytes(), random_int() PHP 7.0 jamais rand() ni mt_rand() pour des secrets
Aléa orienté objet Random\Randomizer PHP 8.2 même sécurité, interface plus flexible
Échapper la sortie HTML htmlspecialchars() depuis toujours les drapeaux par défaut depuis 8.1 échappent aussi les apostrophes
Comparaison à temps constant hash_equals() PHP 5.6 saisie de l'utilisateur en second argument
Cryptographie moderne Sodium (sodium_*) PHP 7.2 plutôt qu'un chiffrement maison
Secrets dans les traces d'appels #[\SensitiveParameter] PHP 8.2 la valeur n'apparaît pas dans la trace
Vérifier les saisies filter_var() PHP 5.2 vérifie le format, ne remplace pas l'échappement

Mots de passe et jetons

password_hash() produit un hachage salé, password_verify() le vérifie. Avec PASSWORD_DEFAULT, PHP utilise actuellement bcrypt ; depuis PHP 8.4, le facteur de coût par défaut est, selon le manuel, de 12 au lieu de 10. Comme l'algorithme par défaut peut changer, le manuel recommande une colonne de base de données de 255 caractères. Avec bcrypt, les mots de passe sont tronqués après 72 octets, ce qu'il faut garder à l'esprit pour de très longues phrases de passe.

<?php
// Inscription
$hash = password_hash($passwort, PASSWORD_DEFAULT);

// Connexion, avec mise à niveau automatique des anciens hachages
if (password_verify($eingabe, $hash)) {
    if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
        $hash = password_hash($eingabe, PASSWORD_DEFAULT); // enregistrer à nouveau
    }
}

// Jeton pour un lien de réinitialisation du mot de passe
$token = bin2hex(random_bytes(32));

Pour comparer des secrets, par exemple une signature, il faut utiliser hash_equals(). Une comparaison normale avec === peut, selon le manuel, révéler par son temps d'exécution à partir de quel endroit deux valeurs diffèrent. Plus de détails : Stocker les mots de passe en PHP en toute sécurité et nombres aléatoires et jetons sûrs.

Échapper les sorties et interroger la base de données en sécurité

Le cross-site scripting naît lorsque des saisies d'utilisateurs aboutissent sans filtre dans du HTML. htmlspecialchars() convertit les caractères spéciaux en entités HTML. Depuis PHP 8.1, les drapeaux par défaut sont ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 ; auparavant, les apostrophes n'étaient pas converties. Qui doit prendre en charge des versions plus anciennes indique les drapeaux explicitement.

L'injection SQL est empêchée par les requêtes préparées. Les valeurs sont transmises séparément du texte SQL et ne peuvent pas modifier la requête :

<?php
$stmt = $pdo->prepare('SELECT id, name FROM kunden WHERE email = :email');
$stmt->execute(['email' => $email]);
$kunde = $stmt->fetch();

echo htmlspecialchars($kunde['name'] ?? '', ENT_QUOTES, 'UTF-8');

Les détails figurent sous Empêcher le cross-site scripting en PHP et dans la page consacrée à l'injection SQL.

Vérifier les saisies est une seconde étape, distincte. filter_var() détermine si une valeur a un format valide, par exemple une adresse e-mail ou un entier dans une plage autorisée. Cela ne remplace toutefois ni l'échappement à la sortie ni une requête préparée, car des valeurs formellement valides peuvent aussi contenir des caractères spéciaux.

Garder les secrets hors des messages d'erreur

Les traces d'appels sont une fuite de données sous-estimée. Lorsqu'une erreur survient dans une fonction, PHP consigne la chaîne d'appels avec les arguments. Si un mot de passe ou une clé d'API s'y trouve, il aboutit dans le log. Depuis PHP 8.2, l'attribut #[\SensitiveParameter] marque de tels paramètres ; leur valeur n'apparaît alors dans la trace que sous la forme d'un objet SensitiveParameterValue.

<?php
function anmelden(string $benutzer, #[\SensitiveParameter] string $passwort): bool
{
    // ... vérification ...
    throw new RuntimeException('Datenbank nicht erreichbar');
}

Selon une remarque du manuel, l'attribut n'agit que sur l'implémentation concrète, non sur la méthode d'une interface. Placez-le donc là où le code s'exécute réellement.

Sessions : réglages sûrs et nouvelles valeurs par défaut

Les sessions sont une cible fréquente d'attaque. Trois réglages sont centraux : session.use_strict_mode=1 rejette les identifiants de session que le serveur n'a pas générés lui-même ; session.cookie_httponly=1 empêche l'accès au cookie de session par JavaScript ; session.cookie_samesite=Lax rend plus difficile son envoi depuis des sites tiers. Selon la RFC adoptée, ces trois valeurs deviendront précisément la valeur par défaut avec PHP 8.6. Définissez-les vous-même d'ici là, et aussi ensuite de façon explicite, afin que la configuration ne dépende pas de la valeur par défaut.

session.use_strict_mode = 1
session.cookie_httponly = 1
session.cookie_samesite = Lax
session.cookie_secure = 1

Plus de détails sous Sécuriser les sessions en PHP.

Ce que les fonctions intégrées ne font pas

Le projet PHP est clair dans sa politique de sécurité : PHP n'est pas un bac à sable. Les contournements de open_basedir ou de disable_functions, les entrées malveillantes transmises à unserialize() et les arguments non vérifiés passés à des fonctions comme mysqli_query() ne sont pas considérés comme des failles de sécurité de PHP. Pour les exploitants, cela signifie : ces réglages sont un durcissement utile, mais pas une frontière de sécurité, et unserialize() n'a rien à faire avec des données externes.

Le second point concerne PHP2Shell. Selon php.net, CVE-2026-109618 et CVE-2026-109619 permettent l'exécution de code avant ou pendant l'exécution de votre application ; avec mod_php, un exploit a été démontré avant même que le code de l'application ne s'exécute. Aucune fonction de votre code ne peut intercepter cela. Une programmation sûre et une version de PHP à jour sont deux obligations distinctes, et toutes deux doivent être remplies.

Comment PHP SOS aide-t-il concrètement ?

Dans l'audit de sécurité des applications PHP, nous vérifions de façon ciblée :

  • Gestion des mots de passe et des jetons : password_hash() et random_bytes() sont-ils utilisés, ou existe-t-il des développements maison ?
  • Sorties et requêtes : où des saisies aboutissent-elles sans filtre dans du HTML, du SQL ou des commandes shell ?
  • Configuration des sessions : le mode strict, HttpOnly, SameSite et Secure sont-ils définis et non redéfinissables ?
  • Exécution : une version de PHP prise en charge tourne-t-elle avec les corrections du 21 octobre 2026 ?

Questions fréquentes

Comment stocker correctement les mots de passe en PHP ?

Avec password_hash() et PASSWORD_DEFAULT ; la vérification se fait avec password_verify(). Selon le manuel, la colonne de la base de données devrait pouvoir contenir jusqu'à 255 caractères, car l'algorithme par défaut peut changer à l'avenir.

rand() convient-il pour des jetons ?

Non. Pour les jetons, les clés et les liens de mot de passe, il faut utiliser random_bytes() ou random_int(). Selon le manuel, elles fournissent des valeurs aléatoires cryptographiquement sûres.

Depuis quand Sodium est-il inclus dans PHP ?

L'extension Sodium pour la cryptographie moderne fait partie de PHP depuis PHP 7.2.0. Les versions plus anciennes ne pouvaient l'ajouter qu'après coup via PECL.

Ces fonctions protègent-elles contre PHP2Shell ?

Non. Elles protègent contre les erreurs de votre application. PHP2Shell se trouve dans l'interpréteur lui-même et ne se comble que par une mise à jour de PHP, suivie du redémarrage de tous les processus PHP.

Les valeurs par défaut des sessions changent-elles dans PHP 8.6 ?

Oui, selon la RFC adoptée, session.use_strict_mode et session.cookie_httponly sont activés par défaut et session.cookie_samesite est défini sur Lax. Vous devriez néanmoins définir vous-même explicitement les configurations existantes.

Sources

Contact immédiat

Chaque heure compte. Écrivez-nous maintenant.

Décrivez brièvement votre système, votre version de PHP et ce que vous avez observé. Nous vous répondons, faisons le point et travaillons à distance jusqu'à la clôture et la documentation de l'incident.

Aide immédiate