Mysql
 sql >> Database >  >> RDS >> Mysql

Implementazione di un sistema di giunzione configurabile, in sicurezza

Stai facendo così tanto bene che in realtà mi sento in colpa a far notare che stai facendo qualcosa di sbagliato! :)

È possibile utilizzare solo istruzioni preparate per parametrizzare i valori dei campi, non identificatori SQL come nomi di colonne o tabelle. Pertanto non sarai in grado di superare A.x , B.z ecc. nel tuo JOIN criteri mediante parametri di istruzione preparati:devi invece fai ciò che sembra terribilmente sbagliato e concatenali direttamente nella tua stringa SQL.

Tuttavia, non tutto è perduto. In un vago ordine di preferenza, puoi:

  1. Presenta all'utente un elenco di opzioni, da cui successivamente riassemblare l'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>
    

    Quindi il tuo gestore del modulo:

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

    Questo approccio ha il vantaggio che, a meno di compromettere PHP (nel qual caso avrai problemi molto più grandi di SQL injection), SQL arbitrario assolutamente non può trova la sua strada nel tuo RDBMS.

  2. Assicurati che l'input dell'utente corrisponda a uno dei valori previsti:

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

    Quindi il tuo gestore del modulo:

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

    Questo approccio si basa su in_array di PHP funzione di sicurezza (ed espone anche all'utente i nomi delle colonne sottostanti, ma data la tua applicazione dubito che sia un problema).

  3. Esegui una pulizia dell'input, come:

    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']) . '`'
    

    Anche se qui citiamo l'input dell'utente e sostituiamo qualsiasi tentativo dell'utente di sfuggire a tale citazione, questo approccio potrebbe essere pieno di tutti i tipi di difetti e vulnerabilità (in mb_ereg_replace di PHP funzione o la gestione da parte di MySQL di stringhe appositamente predisposte all'interno di un identificatore tra virgolette).

    È lontano meglio se possibile utilizzare uno dei metodi precedenti per evitare di inserire del tutto stringhe definite dall'utente nel proprio SQL.