Правите толкова много правилно, че всъщност се чувствам виновен, като посоча, че правите нещо нередно! :)
Можете да използвате само подготвени изрази, за да параметризирате стойности на полета, а не SQL идентификатори като имена на колони или таблици. Следователно няма да можете да преминете A.x
, B.z
и т.н. във вашия JOIN
критерии чрез подготвени параметри на израза:трябва вместо това направете това, което се чувствате ужасно погрешно и ги свържете директно във вашия SQL низ.
Не всичко обаче е загубено. В някакъв неясен ред на предпочитание можете:
-
Представете на потребителя списък с опции, от който впоследствие сглобявате отново 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>
След това вашият манипулатор на формуляри:
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";
Този подход има предимството, че освен компрометирането на PHP (в този случай ще имате много по-големи притеснения от SQL инжектирането), произволният SQL абсолютно не може намери своя път във вашата RDBMS.
-
Уверете се, че въведеното от потребителя отговаря на една от очакваните стойности:
<select name="join_a"> <option>x</option> <option>y</option> </select> <select name="join_b"> <option>z</option> <option>y</option> </select>
След това вашият манипулатор на формуляри:
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]";
Този подход разчита на
in_array
на PHP функция за безопасност (и също така излага на потребителя имената на основните ви колони, но предвид приложението ви се съмнявам, че това е проблем). -
Извършете известно почистване на входа, като например:
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']) . '`'
Докато тук цитираме въведеното от потребителя и заменяме всеки опит на потребителя да избяга от това цитиране, този подход може да бъде пълен с всякакви недостатъци и уязвимости (в
mb_ereg_replace
на PHP) функция или обработката на MySQL на специално изработени низове в идентификатор в кавички).Това е далече по-добре, ако изобщо е възможно, да използвате един от горните методи, за да избегнете вмъкването на дефинирани от потребителя низове в SQL като цяло.