Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Implementando um sistema de junção configurável, com segurança


Você está fazendo tanto certo que eu realmente me sinto culpado por apontar que você está fazendo algo errado! :)

Você só pode usar instruções preparadas para parametrizar valores de campo — não identificadores SQL, como nomes de colunas ou tabelas. Portanto, você não poderá passar A.x , B.z etc. em seu JOIN critérios por meio de parâmetros de instrução preparados:você deve em vez disso, faça o que parece terrivelmente errado e concatene-os diretamente em sua string SQL.

No entanto, nem tudo está perdido. Em alguma ordem vaga de preferência, você pode:

  1. Apresente ao usuário uma lista de opções, da qual você posteriormente remonta o 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>
    

    Em seguida, seu manipulador de formulários:
    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";
    

    Essa abordagem tem a vantagem de que, além de comprometer o PHP (nesse caso, você terá preocupações muito maiores do que a injeção de SQL), o SQL arbitrário absolutamente não pode encontrar seu caminho em seu RDBMS.

  2. Certifique-se de que a entrada do usuário corresponda a um dos valores esperados:
    <select name="join_a">
      <option>x</option>
      <option>y</option>
    </select>
    <select name="join_b">
      <option>z</option>
      <option>y</option>
    </select>
    

    Em seguida, seu manipulador de formulários:
    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]";
    

    Esta abordagem depende do in_array do PHP função para segurança (e também expõe ao usuário seus nomes de coluna subjacentes, mas, devido ao seu aplicativo, duvido que isso seja uma preocupação).

  3. Execute alguma limpeza de entrada, como:
    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']) . '`'
    

    Embora aqui citemos a entrada do usuário e substituamos qualquer tentativa do usuário de escapar dessa citação, essa abordagem pode estar cheia de todos os tipos de falhas e vulnerabilidades (no mb_ereg_replace do PHP função ou manipulação do MySQL de strings especialmente criadas dentro de um identificador entre aspas).

    É longe melhor, se possível, usar um dos métodos acima para evitar a inserção de strings definidas pelo usuário no SQL.