Juin 16 2010

[PHP] PDO et les injections SQL

Peut-être n’avez vous jamais entendu parler des injections SQL ? Pourtant ce sont des failles bien réelles qui peuvent permettre à n’importe quelle personne mal intentionnée d’accéder aux ressources privées de votre site (comme un panel admin par exemple).

Comment faire une injection SQL ?

Imaginons qu’un pirate veuille se connecter sous votre nom. Vous vous dîtes sûrement qu’il lui faut connaître votre pseudo et votre mot de passe mais seul votre pseudo peut lui suffire. Imaginons que vous avez 2 champs de formulaire (ou input) dont un pour entrer le pseudo et l’autre pour entrer le mot de passe. La requête générée sera de ce type:

SELECT * FROM utilisateur
WHERE pseudo = 'jbplay' AND mot_de_passe = '(mot de passe crypté en MD5)';

Le pirate a 2 possibilités. Injecter dans le pseudo ou dans le mot de passe.

  • Attaque sur le pseudo:
    • Pseudo : jbplay ‘–
    • Mot de passe: ce que vous voulez
Voici la requête générée:
SELECT * FROM utilisateur
WHERE pseudo = 'jbplay' --' AND mot_de_passe = '(mot de passe crypté en MD5)';

Les tirets – – indiquent un début de commentaire. La partie en vert devient donc un commentaire. La   requête doit juste vérifier le pseudo et non plus le pseudo ET le mot de passe.

  • Attaque sur le mot de passe:
    • Pseudo : jbplay
    • Mot de passe: ‘OR 1=1
Voici la requête générée:
SELECT * FROM utilisateur
WHERE pseudo = 'jbplay' AND mot_de_passe = '' OR 1=1 --(mot de passe crypté en MD5)';

Ainsi le script programmé pour vérifier si ce que l’utilisateur tape est vrai, il verra que 1=1 est vrai, et le pirate sera connecté.

Comment remédier à ce problème ?

Il suffit d’ajouter des antislashs “\” (ou backslashes en anglais) devant chaque apostrophe. On peut le faire avec la fonction mysql_real_escape_string() mais on peut également utiliser PDO en “préparant” les requêtes, c’est à dire on démarre une transaction, on échappe les caractères et on envoi les données ensuite.

Pour cela nous allons avoir besoin de 2 méthodes, prepare() et execute().
Il existe 2 façons de faire: avec les ? ou les opérateurs.

  • Avec les ?
// Préparation de la requête
$sql = $bdd->prepare("SELECT * FROM utilisateur WHERE pseudo = ? AND mot_de_passe = ?");
$donnees = array($pseudo, $mot_de_passe);
$sql->execute($donnees); // On envoi un tableau avec les données
$resultat = $sql->fetch();
Les données sont envoyées dans l’ordre du tableau et remplacent au fur et à mesure les ?.
  • Avec les opérateurs
// Préparation de la requête
$sql = $bdd->prepare("SELECT * FROM utilisateur WHERE pseudo = :pseudoEnvoye AND mot_de_passe = :mdpEnvoye");
$donnees = array('pseudoEnvoye' => $pseudo, 'mdpEnvoye' => $mot_de_passe);
$sql->execute($donnees); // On envoi un tableau avec les données
$resultat = $sql->fetch();

Cette fois notre tableau possède des noms de colonne. Pour associer ces noms de colonnes à la requête SQL, on utilise les : devant le nom. L’ordre du tableau est donc libre mais assurez-vous que les noms correspondent. (rappelons que PHP est un langage sensible à la casse).

Voilà vous savez tout sur les injections SQL ! 🙂

– Plus d’informations sur la méthode prepare()
– Plus d’informations sur la méthode execute()

Petite astuce:

PDO ajoute systématiquement un antislash devant chaque apostrophe.
Exemple: si vous rentrez “Rue de l’arc”, voilà ce que cela donnera dans la base de données: “Rue de l\’arc”.
Si vous souhaitez afficher les noms de rues sans les antislashes sur votre site, utilisez la fonction stripslashes().
– Plus d’informations sur la fonction stripslashes()

Articles similaires:

Lien Permanent pour cet article : http://jbvigneron.fr/2010/06/16/php-pdo-et-les-injections-sql/

(4 commentaires)

Passer au formulaire de commentaire

  1. Hello!
    Super blog, merci pour l’article, codant à mes heures perdues, j’avais entendu parler de ces attaques mais pour le moment je n’avais pas trouvé d’article aussi clair sur l’injection php.
    A+
    Anthony.

      • rihanna on 14 juin 2016 at 11 h 48 min
      • Répondre

      alert(« ahahahahahah »)

  2. Bonjour,

    Même si le poste est assez ancien, juste un oublie je pense dans le code :

    – Il manque un « $sql =  » devant « $bdd->prepare(….) » sinon $sql->execute() n’existe pas!

    Que pensez-vous du « bindParam » qui permet de « typer » les variables? Moi je trouve ça plus sécuritaire, mais bon c’est peut-être dû à mon amour pour les langages typés ;).

    Franck AUVINET.

  3. Bonjour,
    Merci beaucoup pour cette remarque ! J’ai mis à jour l’article de ce fait 🙂

    En effet, je suis également plus « accro » aux langages typés également donc il est vrai que le « bindParam » est intéressant également 🙂

Laisser un commentaire

Your email address will not be published.

css.php