Diskuze: SQL injection a dotaz WHERE LIKE
V předchozím kvízu, Online test znalostí PHP, jsme si ověřili nabyté zkušenosti z kurzu.

Člen

Zobrazeno 10 zpráv z 10.
//= Settings::TRACKING_CODE_B ?> //= Settings::TRACKING_CODE ?>
V předchozím kvízu, Online test znalostí PHP, jsme si ověřili nabyté zkušenosti z kurzu.
Co jsi vycetl prikladu a komentaru v manualu? https://www.php.net/…nd-param.php
Co jsi vycetl z prikladu nalezenych googlem, jak to pouzivaji?
Vis, otazkou je, zda to nekdo pouziva podobne jako ty nebo je vsechno jinak a prikaz jen prevadi cely string tak, aby jej bylo mozna pouzit jako jednu value pro sql prikaz
// string, number
$stmt = mysqli_prepare($link, "INSERT INTO CountryLanguage VALUES (?, ?, ?, ?)");
$stmt->bind_param($stmt, 'sssd', $code, $language, $official, $percent);
// array
$stmt = $mysqli->prepare("SELECT Language FROM CountryLanguage WHERE CountryCode IN (?, ?)");
$stmt->bind_param('ss', ...['DEU', 'POL']);
// kousek sql prikaz
// takova moznost tam neni
// --- takze mas 2 moznosti
$Podminka = "(nazev LIKE '%ermo%' OR kod LIKE '%ermo%' OR informace LIKE '%ermo%' OR rozsirene_info LIKE '%ermo%') AND (nazev LIKE '%kr%' OR kod LIKE '%kr%' OR informace LIKE '%kr%' OR rozsirene_info LIKE '%kr%')";
$query = 'SELECT COUNT(*) FROM table WHERE %s AND zobraz="1"';
$query = sprintf($query, $Podminka );
//$pocet_celkem->bind_param('s', $Podminka);
$query = 'SELECT COUNT(*) FROM table WHERE $Podminka AND zobraz="1"';
//$pocet_celkem->bind_param('s', $Podminka);
Chces docilit obycejne spojeni retezcu, ne? Nebo se ma pri to stat jeste neco
jineho?
To je prave otazka, co jineho by se mohlo stat, co tam delas? Jestli se tam da
propasovat nejaky nezadouci string.
Vis, ty funkce nedelaji parsovani sql dotazu, pouze doplnuji znaky tak, aby text
nenarusil sql dotaz. Proste, doplni znaky k urcitym znakum.
Na parsovani dotazu bys asi potreboval nejakou umelou inteligenci, aby si
dokazala tipnout, co tam chces proti tomu, co tam je napsane.
$stmt = mysqli_prepare($link, "INSERT INTO CountryLanguage VALUES (?, ?, ?, ?)");
// ulozi sql dotaz do promene
$stmt->bind_param('sssd', $code, $language, $official, $percent);
// prevede data z $code, $language, $official, $percent na string, string, string, digit (sssd)
// escapuje hodnoty pro stringy, tj, prida uzovozku pred a za a escapuje uvozovky uprostred stringu
// $language -> (string) $language -> escape($language) -> "escape($language)"
// jaz"yk -> (string) jaz"yk -> escape(jaz\"yk) -> "jaz\"yk" // escape se trochu lisi u ruznych sql, obvykle se znak zdvojuje
// a jeste ta funkce escapuje vuci stringu v php (ale, to prave delat nemusi, to se deje pri ukladani)
// "INSERT INTO CountryLanguage VALUES (?, ?, ?, ?)"
// "INSERT INTO CountryLanguage VALUES (?, \"jaz\\\"yk\", ?, ?)" // takhle bys to musel zapsat do sql prikazu primo, pokud php string zacnes dvojitymi uvozovkami
Právě, že jsem nic nevyčetl. Ten příkaz ještě vypadá nad tím takto. Doplňuje LIKE podle toho kolik je slov. Je to input pro hledání, takže se tam teoreticky dá zavléct škodlivý kód.
$nazev = $_GET["vstupni_input"];
$array_like = Explode(" ", $nazev);
$Podminka = null;
$pole_like = [];
for($i = 0; $i <= Count($array_like) - 1; $i++){
$pole_like[] = "(nazev LIKE '%".$array_like[$i]."%' OR kod LIKE '%".$array_like[$i]."%' OR informace LIKE '%".$array_like[$i]."%' OR rozsirene_info LIKE '%".$array_like[$i]."%')";
}
$Podminka .= ' '.Implode(' AND ',$pole_like);
Takže těch prvků v poli může být hned několik podle toho kolik je tam slov. Jestliže to doplňuje znaky, tedy nějak escapuje, tak proč ten příkaz poté nefunguje skrz ten bind_param? Kdyby šlo jen o jen řetezěc nazev, kod, informace a rozsirene_info, tak to by šlo doplnit, ale vzhledem k tomu, že nevím kolik jich bude, tak mě nenapadá jak by to šlo...
Je nějaká bezpečná cesta jak odstranit z $Podminka školivý kód nebo jak jinak to provést?
$pole_like = [];
for($i = 0; $i <= Count($array_like) - 1; $i++){
$pole_like[] = "(nazev LIKE ? OR kod LIKE ? OR informace LIKE ? OR rozsirene_info LIKE ?)";
}
$where = implode(' AND ', $pole_like);
$query = 'SELECT COUNT(*) FROM table WHERE $where AND zobraz="1"';
$stmt = mysqli_prepare($link, $query);
$i_end = Count($array_like);
for($i = 0; $i < $i_end ; $i++) // zasadne nepouzivej funkce do podminky pro cykly, pokud se hodnota nemeni
// to "<=" zase ma svuj vyznam, kdyz nechces prekrocit rozsah nejake promene, tak to si tam klidne nech
{
$value = $array_like[$i];
// musis se zbavit vseho, co muze narusit vyraz pro like
// ted s nejsem jisty, bud \znak (escapovat) nebo znakznak (zdvojit)
$value = str_replace(array('\\', '_', '%'), array('\\\\', '\\_', '\\%'), $value);
$value = '%'.$value.'%';
$stmt->bind_param('ssss', $value, $value, $value, $value);
}
To mi nefunguje, protože bind_param nemá stejný počet prvků jako ten dotaz.
Udělal jsem to následovně:
$array_like = Explode(" ", $Nazev);
$Podminka = null;
$nic_hledej_order = "";
$pole_like = [];
$i_end = Count($array_like);
$qArray = array();
$refs = array();
$type = array();
$string = null;
function arrayToRef(&$rawArray)
{
$refArray = array();
foreach($rawArray as $key => $value)
{
$refArray[$key] = &$rawArray[$key];
}
return $refArray;
}
for($i = 0; $i <= $i_end - 1; $i++){
$pole_like[] = "(nazev LIKE ? OR kod LIKE ? OR informace LIKE ? OR rozsirene_info LIKE ?)";
$value = $array_like[$i];
$value = str_replace(array('\\', '_', '%'), array('\\\\', '\\\_', '\\\%'), $value);
$value = '%'.$value.'%';
$qArray[] = $pole_like[0];
$b = $i * 4;
for($a = $b; $a < 4+$b ; $a++){
$string .= "s";
$refs[$a] = $value;
}
}
$query = 'SELECT COUNT(*) FROM table WHERE ';
$data = arrayToRef($refs);
$type[] = $string;
$result_params = array_merge($type,$data);
$query .= implode(' AND ', $qArray).' AND zobraz_eshop="1"';
$stmt = $mysqli->prepare($query);
call_user_func_array(array($stmt, 'bind_param'), $result_params);
$stmt->execute();
$stmt->bind_result($celkem);
$stmt->store_result();
$stmt->fetch();
musel jsem ted použít funkci call_user_func_array. Je to ok? Výsledky mi to dává správné.
Urcite to musi jit i nejak sikovneji. Ale mysqli nepouzivam, tak nevim. Dneska se pouziva pdo driver.
Toto bych resil jinak
//$query .= implode(' AND ', $qArray).' AND zobraz_eshop="1"';
$qArray[] = 'zobraz_eshop="1"';
$query .= implode(' AND ', $qArray);
Muze se totiz stat, ze qArray bude prazdny, implode tam da "" a pak mas sql dotaz
SELECT COUNT(*) FROM table WHERE AND zobraz_eshop="1"
coz je nesmysl a vypise error
google = mysqli bind dynamic params bind_param
https://stackoverflow.com/…cally-in-php
if (strnatcmp(phpversion(),'5.3') >= 0) //Reference is required for PHP 5.3+
{
$refs = array();
foreach($arr as $key => $value)
$array_of_param[$key] = &$arr[$key];
call_user_func_array(array(&$stmt, 'bind_params'), $array_of_params);
}
---
public function get_result($sql,$types = null,$params = null) {
$stmt = $this->mysqli->prepare($sql);
$stmt->bind_param($types, ...$params);
if(!$stmt->execute()) return false;
return $stmt->get_result();
}
$res = $output->get_result($sql, 'ss',array('1','Tk'));
-----
$stmt->bind_param(str_repeat("s", count($data)), ...$data);
-----
call_user_func_array(
array($stmt, "bind_param"),
array_merge(array(str_repeat("s", count($data))), $data));
----
$references_to_data = array();
foreach ($data as &$reference) { $references_to_data[] = &$reference; }
unset($reference);
call_user_func_array(
array($stmt, "bind_param"),
array_merge(array(str_repeat("s", count($data))), $references_to_data));
Jasně, to se stát může, ale to je ošetřeno ještě před dotazem, takže se do této části hledání vůbec nedostane. Pokud je $_GET['input'] prázdný, tak to hodí hlášku.
K tomu PDO. Kdybych to přepsal, tak by se asi dalo to tam opakovat a lépe "pojmenovat" jednotlivé vstupy, dle příkladu.
// prepare sql and bind parameters
$stmt = $conn->prepare("INSERT INTO MyGuests (firstname, lastname, email)
VALUES (:firstname, :lastname, :email)");
$stmt->bindParam(':firstname', $firstname);
$stmt->bindParam(':lastname', $lastname);
$stmt->bindParam(':email', $email);
Mrknu se na to. PDO má výrazné výhody oproti klasice? má smysl, abych do toho hrabal?
No, php7 myslim vypisuje, ze mysqli je deprecated, nepodporovane. Jinak o tom nic moc nevim. Jen mi bylo doporuceno pouzivat pdo pred X lety a nemam s tim problem. Ja mam napsane nejake vlastni sql class, ve ktere to pdo pouzivam. Vyuzivam escapovani pres vlastni funkce, odkazuji na pdo. S Bindem jsem se nikdy nezkamaradil, protoze jsem zvykly skladat sql dotaz jako text.
Zobrazeno 10 zpráv z 10.