sql >> Databasteknik >  >> RDS >> Mysql

Implementera ett konfigurerbart sammanfogningssystem, säkert

Du gör så mycket rätt att jag faktiskt känner mig skyldig när jag påpekar att du gör något fel! :)

Du kan bara använda förberedda satser för att parametrisera fältvärden – inte SQL-identifierare som kolumn- eller tabellnamn. Därför kommer du inte att kunna skicka A.x , B.z etc. i din JOIN kriterier med hjälp av förberedda satsparametrar:du måste gör istället det som känns fruktansvärt fel och koppla dem direkt till din SQL-sträng.

Allt är dock inte förlorat. I någon vag preferensordning kan du:

  1. Ge användaren en alternativlista, från vilken du sedan återmonterar SQL:en:

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

    Sedan din formulärhanterare:

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

    Detta tillvägagångssätt har fördelen att, förutom att kompromissa med PHP (i vilket fall du kommer att ha mycket större bekymmer än SQL-injektion), kan godtycklig SQL absolut inte hitta in i ditt RDBMS.

  2. Se till att användarinmatningen matchar ett av de förväntade värdena:

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

    Sedan din formulärhanterare:

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

    Detta tillvägagångssätt förlitar sig på PHPs in_array funktion för säkerhet (och exponerar även för användaren dina underliggande kolumnnamn, men med tanke på din applikation tvivlar jag på att det är ett problem).

  3. Utför viss ingångsrensning, till exempel:

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

    Även om vi här citerar användarinmatningen och ersätter användarens alla försök att fly från det citatet, kan detta tillvägagångssätt vara fullt av alla möjliga brister och sårbarheter (i antingen PHPs mb_ereg_replace funktion eller MySQL:s hantering av specialgjorda strängar inom en citerad identifierare).

    Det är långt bättre om möjligt att använda någon av ovanstående metoder för att undvika att infoga användardefinierade strängar i sin SQL helt och hållet.



  1. Installera pdo för postgres Ubuntu

  2. Hur man övervakar PostgreSQL 12-prestanda med OmniDB – Del 1

  3. Få alla användare utom administratörer i många-till-många-relationer

  4. Double JOIN med samma bord två gånger