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:
-
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.
-
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). -
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.