Nazwy tabel i kolumn NIE MOGĄ zostać zastąpione parametrami w PDO.
W takim przypadku wystarczy po prostu ręcznie przefiltrować i zdezynfekować dane. Jednym ze sposobów jest przekazanie parametrów skróconych do funkcji, która wykona zapytanie dynamicznie, a następnie za pomocą switch()
instrukcji utworzy białą listę prawidłowych wartości, które będą używane dla nazwy tabeli lub nazwy kolumny. W ten sposób żadne dane wejściowe użytkownika nigdy nie trafiają bezpośrednio do zapytania. Na przykład:
function buildQuery( $get_var )
{
switch($get_var)
{
case 1:
$tbl = 'users';
break;
}
$sql = "SELECT * FROM $tbl";
}
Nie pozostawiając domyślnej wielkości liter lub używając domyślnej wielkości liter, która zwraca komunikat o błędzie, upewniasz się, że zostaną użyte tylko te wartości, które chcesz użyć.
array('u'=>'users', 't'=>'table', 'n'=>'nonsensitive_data')
Itp.)default
. Jeśli używasz tego wzorca, powinieneś albo oznaczyć jedną ze swoich litercase
jakodefault
, albo dodać wyraźny przypadek błędu, taki jakdefault: throw new InvalidArgumentException;
if ( in_array( $tbl, ['users','products',...] ) { $sql = "SELECT * FROM $tbl"; }
. Dzięki za pomysł.mysql_real_escape_string()
. Może tutaj mogę to powiedzieć bez kogoś, kto wskoczy i nie powie „Ale nie potrzebujesz tego z PDO”Aby zrozumieć, dlaczego wiązanie nazwy tabeli (lub kolumny) nie działa, musisz zrozumieć, jak działają symbole zastępcze w przygotowanych instrukcjach: nie są one po prostu podstawiane jako (odpowiednio poprzedzone) ciągi, a wynikowy SQL jest wykonywany. Zamiast tego DBMS, proszony o „przygotowanie” instrukcji, przedstawia kompletny plan zapytań, w jaki sposób wykona to zapytanie, w tym jakie tabele i indeksy zastosuje, które będą takie same bez względu na to, jak wypełnisz symbole zastępcze.
Plan
SELECT name FROM my_table WHERE id = :value
będzie taki sam, niezależnie od tego, co zastąpisz:value
, ale pozornie podobnychSELECT name FROM :table WHERE id = :value
nie da się zaplanować, ponieważ DBMS nie ma pojęcia, z której tabeli wybierzesz.To nie jest coś, co biblioteka abstrakcyjna, taka jak PDO, może lub powinna obejść, ponieważ zniweczyłaby 2 kluczowe cele przygotowanych instrukcji: 1) aby baza danych mogła z wyprzedzeniem zdecydować, w jaki sposób zostanie uruchomione zapytanie, i użyć tego samego planuj wiele razy; oraz 2) w celu uniknięcia problemów bezpieczeństwa poprzez oddzielenie logiki zapytania od zmiennej wejściowej.
źródło
TOP
/LIMIT
/OFFSET
, więc byłoby to trochę nie na miejscu jako funkcja.Widzę, że to stary post, ale uznałem go za przydatny i pomyślałem, że podzielę się rozwiązaniem podobnym do sugerowanego przez @kzqai:
Mam funkcję, która odbiera dwa parametry, takie jak ...
Wewnątrz sprawdzam tablice, które skonfigurowałem, aby upewnić się, że dostępne są tylko tabele i kolumny z tabelami „błogosławionymi”:
Następnie sprawdzenie PHP przed uruchomieniem PDO wygląda jak ...
źródło
$pdo->query($sql)
Korzystanie z tego pierwszego nie jest z natury bezpieczniejsze niż drugie, musisz oczyścić dane wejściowe, niezależnie od tego, czy są one częścią tablicy parametrów, czy prostej zmiennej. Więc nie widzę nic złego w korzystaniu z tego ostatniego formularza
$table
, pod warunkiem, że upewnisz się, że zawartość$table
jest bezpieczna (alphanum plus podkreślenia?) Przed użyciem.źródło
(Późna odpowiedź, sprawdź moją notatkę dodatkową).
Ta sama zasada obowiązuje przy próbie utworzenia „bazy danych”.
Nie można użyć przygotowanej instrukcji do powiązania bazy danych.
To znaczy:
nie będzie działać. Zamiast tego użyj bezpiecznej listy.
Uwaga dodatkowa: dodałem tę odpowiedź (jako wiki społeczności), ponieważ często zamykała pytania, w których niektóre osoby zamieszczały podobne pytania, próbując powiązać bazę danych, a nie tabelę i / lub kolumnę.
źródło
Część mnie zastanawia się, czy możesz udostępnić własną niestandardową funkcję odkażania tak prostą:
Nie zastanawiałem się nad tym, ale wydaje się, że usunięcie czegokolwiek oprócz postaci i znaków podkreślenia może działać.
źródło
MyLongTableName
łatwo ją poprawnie odczytać, ale jeśli sprawdzisz zapisaną nazwę, to (prawdopodobnie)MYLONGTABLENAME
nie będzie ona bardzo czytelna, więcMY_LONG_TABLE_NAME
jest bardziej czytelna.Select * From $table
. Bardzo ważna jest tutaj biała lista lub ścisłe dopasowanie wzorca (np. „Nazwiska zaczynające się na raporcie_, a następnie tylko od 1 do 3 cyfr”).Jeśli chodzi o główne pytanie w tym wątku, pozostałe posty wyjaśniły, dlaczego nie możemy wiązać wartości z nazwami kolumn podczas przygotowywania instrukcji, więc oto jedno rozwiązanie:
Powyższe to tylko przykład, więc nie trzeba dodawać, że kopiuj-> wklej nie zadziała. Dostosuj do swoich potrzeb. Teraz może to nie zapewniać 100% bezpieczeństwa, ale pozwala na pewną kontrolę nad nazwami kolumn, gdy „przychodzą” jako ciągi dynamiczne i mogą być zmieniane po stronie użytkownika. Ponadto nie ma potrzeby budowania tablicy z nazwami i typami kolumn tabeli, ponieważ są one wyodrębniane ze schematu_informacyjnego.
źródło