Mysql
 sql >> Base de données >  >> RDS >> Mysql

Mettre en place un système d'assemblage paramétrable, en toute sécurité

Vous faites tellement de bien que je me sens coupable de souligner que vous faites quelque chose de mal ! :)

Vous ne pouvez utiliser que des instructions préparées pour paramétrer des valeurs de champ, et non des identificateurs SQL tels que des noms de colonne ou de table. Vous ne pourrez donc pas passer A.x , B.z etc. dans votre JOIN critères au moyen de paramètres d'instruction préparés :vous devez faites plutôt ce qui vous semble terriblement mal et concaténez-les directement dans votre chaîne SQL.

Cependant, tout n'est pas perdu. Dans un vague ordre de préférence, vous pouvez :

  1. Présentez à l'utilisateur une liste d'options, à partir de laquelle vous réassemblez ensuite le SQL :

    <select name="join_a">
      <option value="1">x</option>
      <option value="2">y</option>
    </select>
    <select name="join_b">
      <option value="1">z</option>
      <option value="2">y</option>
    </select>
    

    Ensuite, votre gestionnaire de formulaire :

    switch ($_POST['join_a']) {
      case 1:  $acol = 'x'; break;
      case 2:  $acol = 'y'; break;
      default: die('Invalid input');
    }
    switch ($_POST['join_b']) {
      case 1:  $bcol = 'z'; break;
      case 2:  $bcol = 'y'; break;
      default: die('Invalid input');
    }
    
    $sql .= "FROM A JOIN B ON A.$acol = B.$bcol";
    

    Cette approche a l'avantage que, à moins de compromettre PHP (auquel cas vous aurez des problèmes bien plus importants que l'injection SQL), SQL arbitraire ne peut absolument ne pas trouve sa place dans votre SGBDR.

  2. Assurez-vous que l'entrée de l'utilisateur correspond à l'une des valeurs attendues :

    <select name="join_a">
      <option>x</option>
      <option>y</option>
    </select>
    <select name="join_b">
      <option>z</option>
      <option>y</option>
    </select>
    

    Ensuite, votre gestionnaire de formulaire :

    if (!in_array($_POST['join_a'], ['x', 'y'])
     or !in_array($_POST['join_b'], ['z', 'y']))
       die('Invalid input');
    
    $sql .= "FROM A JOIN B ON A.$_POST[join_a] = B.$_POST[join_b]";
    

    Cette approche repose sur le in_array de PHP fonction pour la sécurité (et expose également à l'utilisateur vos noms de colonne sous-jacents, mais compte tenu de votre application, je doute que ce soit un problème).

  3. Effectuez un nettoyage des entrées, tel que :

    mb_regex_encoding($charset); // charset of database connection
    $sql .= 'FROM A JOIN B ON A.`' . mb_ereg_replace('`', '``', $_POST['join_a']) . '`'
                        . ' = B.`' . mb_ereg_replace('`', '``', $_POST['join_b']) . '`'
    

    Alors que nous citons ici l'entrée de l'utilisateur et remplaçons toute tentative de l'utilisateur d'échapper à cette citation, cette approche pourrait être pleine de toutes sortes de failles et de vulnérabilités (dans le mb_ereg_replace de PHP ou la gestion par MySQL des chaînes spécialement conçues dans un identifiant entre guillemets).

    C'est loin mieux vaut, si possible, utiliser l'une des méthodes ci-dessus pour éviter d'insérer complètement des chaînes définies par l'utilisateur dans son SQL.