Zdravím.
Jen bych si chtěl ujasnit, jak že to je s výpisem proměnné podle její hodnoty.
Pokud je hodnota řetězec, mělo by to být v uvozovkách nebo apostrofech.
Pokud je to číslo, tak bez.
Když chci třeba vyhledat v DB podle proměnné, jejíž hodnota je řetězec, pak to sepíšu takto:
$prom = "nejaky_retezec";
mysql_query("SELECT ... FROM ... WHERE neco = '".$prom."'");
Když chci vyhledat to samé, ovšem když hodnota je číslo
$prom = 100;
mysql_query("SELECT ... FROM ... WHERE neco = ".$prom."");
Rozdíl mezi příkladem 1 a 2 je ten, že v prvním mám proměnnou vloženou do apostrofů, v druhém příkladě ne (právě proto, že je to číslo).
Je má myšlenka správná ?
Děkuji za každou odpověď.
Myšlenka to sice je správná, ale v daném případě hrozí SQL injection, pokud nejsou vstupní hodnoty správně ošetřeny. Pokud by ve vstupním řetězci byly apostrofy, útočník by mohl manipulovat s databází.
Obrana viz např. http://php.vrana.cz/obrana-proti-sql-injection.php
Proti SQL injection používám pouze funkci mysql_real_escape_string(), která, mám dojem, že jsem to někde četl, stačí.
Každopádně děkuji za rychlou odpověď.
Ty injection jsou mozne v obou pripadech :)
string: ' or 1=1
cislo: 1 or 1=1
jinak nechapu, na co se ptas. cislo nemusi byt v uvozovkach, protoze jeho znaky jsou jednoznacne a nenarusi sql dotaz 09., pokud je tam opravdu cislo osetrene mysql_real... Ve stringu se muze byt ale i text '\'OR 1=1', shodou okolnosti zapis mysql prikazu, treba. Takze musi byt jednoznacne ohranicen zleva i zprava. To je logicke. Proto mi nedochazi smysl dotazu :)
<HTML>Milý nekromante peto, tazatel se ptal na to, zda je v SQL syntaxi správně, když numerické hodnoty píše v dotazu bez uvozovek a řetězcové píše s uvozovkami. Bylo mu již zcela správně zodpovězeno, že je to správně. To je celé, víc v tom nehledej.</HTML>
Jenže v tomto případě peta1 výjimečně není nekromant. Je to ze včerejška a je to k věci. Poukázal na to, že i neošetřená číselná proměnná může být zneužita k SQL injection.
Proto je lepší používat parametrizované dotazy, u kterých SQL injection nehrozí.
<HTML><small>OT:
Kite, znáš princip vyšší moci kombinované s neviditelnou rukou trhu? Peta je nekromant, i když ne v tomto vlákně.</small></HTML>
Nípal: Všichni víme, že peta rád vyhrabává mrtvoly, zejména ty, jejichž problémy mezitím vyhnily. Víme, že občas odpoví duplicitně a často zcestně. Snažím se to však vyhodnotit případ od případu. Až mě to přestane bavit, přestanu jeho příspěvky číst. Zrovna v tomto vlákně bych ho kritizovat nechtěl.
http://middleage.xf.cz/ běží na serveru s PHP5. Použitím parametrizovaných dotazů je možné zbavit se otázek, zda je někde v SQL dotazu nutné použít uvozovky či nikoli.
<HTML>Kit: Však jej taky nechávám, když není mrtvola uleželá. Zbytek nelítostně mažu. Parametrizované dotazy jsou fajn věc, možná bys mohl doporučit nějaký dobrý návod (i když my, techničtější lidé, jsme na to časem přišli sami a ani ten způsob nijak zvlášť nenazýváme).</HTML>
Stačí do Googla zadat "php mysql prepare" a na prvním místě vyleze dokumentace
http://php.net/manual/en/mysqli.prepare.php
i s příklady použití ve verzi procedurální i objektové. Ovšem s použitím PDO je to ještě pohodlnější:
http://php.net/manual/en/pdo.prepare.php
PDO je výhodné i proto, že se v dobře napsané aplikaci dá velmi snadno přejít na SQLite.
Dle mých měření jsou parametrizované dotazy v mnoha případech rychlejší. Zejména tam, kde jsou nachystané dotazy použity opakovaně.
Pokud lze udělat SQL injection i s pomocí čísel, měl bych poté dotaz, jak se proti tomu bránit ?
Znám a používám pouze funkce mysql (mysql_query(), ...), mysqli je mi, alespoň prozatím, neznámé.
Na čísla je v PHP jednoduchý trik. Zkus třeba tohle:
<?php echo "45' or 1=1"+0; ?>
K proměnné přičteš 0 a máš jistotu, že výsledkem bude číslo.
V MySQLi si nejprve zkompiluješ dotaz
$dotaz=$databaze->prepare("SELECT Jmeno FROM tabulka WHERE ID=?");
Potom do toho dotazu nastrkáš hodnoty, které se umístí místo znaku "?". Ošetřeny jsou automaticky.
$dotaz->bind_param('i',$id);
viz http://www.php.net/manual/en/mysqli-stmt.bind-param.php
Nakonec dotaz provedeš
$dotaz->execute();
Poslední 2 příkazy můžeš klidně opakovat dle potřeby (i když u SELECTu zpravidla stačí 1 dotaz). Pokud je otazníků víc, musí mít i metoda bind_param() víc parametrů.
Skvělé, díky moc. Jen se ještě naposled zeptám, je lepší užívat mysqli, než mysql ?
MySQLi je novější knihovna, než MySQL a obsahuje víc funkcí. WZ ji podporuje na serverech s PHP5.
Ještě lepší je třída PDO, na WZ je však možné ji používat jen pro SQLite. Pokud potřebuješ rychlou SQL databázi s podporou transakcí na WZ, použij místo MySQL raději SQLite.
A co se týče ochrany DB, můžu v klidu používat knihovnu MySQL ? + s funkcí mysql_real_escape_string() proti injection.
Nějak jsem si na to už zvykl a nechce se mi to měnit. :-)
Beru zpět. MySQLi mi na WZ nejede. MySQLi mi jede na domácím serveru i v práci a tak jsem se spletl.
Můžeš klidně používat i starší knihovnu MySQL s mysql_real_escape_string(), jen bys neměl ty knihovny kombinovat. Můžeš však kombinovat různé databáze.
Ještě jednou chci poděkovat za rady a pomoc!
Můžeš používat co chceš. Jen je třeba si pamatovat, že vstupem nemusí být vždy to, co bys očekával a podle toho jednat a ošetřovat.
Třeba pokud očekáváš jen číslo, pak můžeš použít místo mysql_real_escape_string() i obyčejné is_numeric().
<?php
$cislo = 10; // projde
$cislo = "10"; // projde
$cislo = "dfdfdfd"; // neprojde
$cislo = "' OR 1=1"; // neprojde
if ( is_numeric($cislo) ) {
$res = mysql_query("SELECT ... FROM ... WHERE neco = ".$cislo);
} else {
echo "Nelze provest. Vstupni hodnota neni cislo";
}
?>
Pokud jde o neurčitou hodnotu (může být řetězec i číslo), pak se použiji uvozovky a je třeba vstup ošetřit univerzálně mysql_real_escape_string().
Když už se tady tak řeší kontrola čísel, za zmínku určitě stojí i funkce intval(), floatval() a případně strval(). Samozřejmě jsou to spíš sanitizační funkce než validační, ale pro kontrolu ve vytvářených dotazech se někdy hodí.