sql >> Base de Datos >  >> RDS >> Mysql

Implementar un sistema de unión configurable, de forma segura

¡Estás haciendo tantas cosas bien que en realidad me siento culpable al señalar que estás haciendo algo mal! :)

Solo puede usar declaraciones preparadas para parametrizar valores de campo, no identificadores SQL como nombres de columnas o tablas. Por lo tanto, no podrá pasar A.x , B.z etc. en su JOIN criterios por medio de parámetros de declaraciones preparadas:usted debe en su lugar, haga lo que se sienta terriblemente mal y concatene directamente en su cadena SQL.

Sin embargo, no todo está perdido. En un orden vago de preferencia, puede:

  1. Presente al usuario una lista de opciones, a partir de la cual vuelva a ensamblar el 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>
    

    Entonces su controlador de formulario:

    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";
    

    Este enfoque tiene la ventaja de que, a menos que comprometa a PHP (en cuyo caso tendrá preocupaciones mucho mayores que la inyección de SQL), SQL arbitrario absolutamente no puede encuentre su camino en su RDBMS.

  2. Asegúrese de que la entrada del usuario coincida con uno de los valores esperados:

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

    Entonces su controlador de formulario:

    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]";
    

    Este enfoque se basa en in_array de PHP función por seguridad (y también expone al usuario los nombres de las columnas subyacentes, pero dada su aplicación, dudo que sea una preocupación).

  3. Realice alguna limpieza 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']) . '`'
    

    Si bien aquí citamos la entrada del usuario y reemplazamos cualquier intento del usuario de escapar de esa cita, este enfoque podría estar lleno de todo tipo de fallas y vulnerabilidades (ya sea en mb_ereg_replace de PHP función o el manejo de MySQL de cadenas especialmente diseñadas dentro de un identificador entrecomillado).

    Está lejos mejor, si es posible, usar uno de los métodos anteriores para evitar la inserción de cadenas definidas por el usuario en el propio SQL.