Compléments sur PDO - Sécurité

Filtrage d’entrées

On peut vouloir nourrir une requête directement avec des données provenant d’un formulaire:

<?php
  $sql = sprintf(
    'SELECT id FROM CARNET WHERE email = "%s"',$_GET['email'])
  );

On voit bien que la valeur de l’entrée email dans le tableau _GET n’est absolument pas vérfifiée avant son utilisation !

On peut essayer dans ce cas d’utiliser un filtre PHP pour contrôler un peu les choses:

<?php
  $sql = sprintf(
      'SELECT id FROM CARNET WHERE email = "%s"',
      filter_input(INPUT_GET, 'email')
  );

Mais ceci constitue une manière peu sûre de procéder malgré l’utilisation du filtre PHP. Cela laisse en effet la possiblilité d’insertion de code malveillant non contrôlé.

L’exemple classique est la requête SQL construite dans la chaine suivante:

<?php
  $sql = "SELECT nom FROM USERS WHERE login='".
         $_REQUEST['login']."' AND PASSWD='".
         $_REQUEST['pass']."'";

Qui donne lors de son exécution avec $_REQUEST[“login”] = «  toto” –« :

SELECT nom FROM USERS WHERE login='toto'  -- ' AND PASSWD= '".$_REQUEST['pass']."' ";

Avertissement

Le - - constituant un début de commentaire SQL, ceci constitue une injection SQL qui est l’une des principales failles de sécurité exploitées par les Hackers. Pour s’en prémunir, il faut utiliser à la fois le filtrage des entrées et les requêtes préparées.

<?php
$sql = 'SELECT id FROM CARNET WHERE email = :email';
$statement = $pdo->prepare($sql);
$email = filter_input(INPUT_GET, 'email');
$statement->bindValue(':email', $email);

Il faut parfois préciser dans un troisième argument le type des paramètres attendus:

<?php
  $sql = 'SELECT email FROM CARNET WHERE id = :id';
  $statement = $pdo->prepare($sql);
  $userId = filter_input(INPUT_GET, 'id');
  $statement->bindValue(':id', $userId, PDO::PARAM_INT);