Miért NE használj ezSQL-t - kritika egy twitt-re
Az alábbi bejegyzésre szeretnék reagálni, amely a weblabor twitt box-ában jelent meg ma:
Szeretném a vitát nyílt vizekre vinni, mert szakmai (semmiképp nem személyes) meggyőződésem, hogy mind a hivatkozott bejegyzés, mind az onnan továbbhivatkozott oldalon található leírás olyan adatbázis kezelési, biztonsági, szakmai bakiktól hemzseg, amely ellen évek óta küzd a közösség egy jókora (és egyre növekvő) része.
Példaként említeném:
- PREPARE statement-ek támogatásának/példáinak totális hiánya, ehelyett a jóval kevésbé hatékony és biztonságtalanabb ismételten elküldött INSERT lekérések használata
- SQL injection elleni védelemnek nyoma nincs, ellenben tucatnyi példa szerepel a hivatkozott leírásban arra, hogyan lehet mindezt lehetővé tenni könnyen a külső személyek számára (a hivatkozott cikkből is hiányzik az erre való igény).
Konkrét példákat kiemelve a leírásból:
Example 10:
1. SHOW TABLES? Ne már. Az INFORMATION_SCHEMA mire való?
2. Változónév a lekérésben??? Escape-elni majd a magic_quotes_gpc fog?! (legújabban deprecated...)
Example 3 – Return results as numerical array:
Vajon a szerzőnek van halovány sejtelme arra nézvést, hogy a fenti kódrészlet hányszor több opkódra fordul le annál, mint ha konkatanálást használna? (zárójeles megjegyzés: nem ellenőriztem, de gyaníthatóan még akkor is kevesebb opkód lenne a végeredmény, ha a konkatanált változókra külön-külön hívnánk valamilyen escape függvényt - és akkor még SQL injectet se lehetne csak úgy belenyomni)
$db->escape:
Költői kérdés: ha az escape függvény formázásra való, és nem escape-elésre, akkor miért ez a neve?
Lírai válasz:
Tehát biztonságossá teszi a lekérést, de azért nem igazán használható az SQL injection ellen. Ééééértem... o.O
A bizonyosság kedvéért ellenőriztem: az ezSQL_pdo osztály kódjában a 110-es sorban található tökéletes sületlenség - konkrétan: $str = addslashes(stripslashes($str)) - végez valamiféle escape-elést, de arra még véletlenül sem a PDO::quote() metódusát használja. Ezzel szemben az ezSQL_mysql osztály már legalább mysql_real_escape_string() hívást tartalmaz. Érthetetlen.
Egyébként ugyanebben a PDO-ra épülő implementációban találtam még egy érdekességet:
Befizetem egy sörre azt a kollégát, aki elmagyarázza nekem (és alátámasztja), hogy miért jobb PDO::FETCH_ASSOC-cal lekérni egy sort a resultset-ből, majd utána a kapott array-t object-té cast-olni, mint egyszerűen PDO::FETCH_OBJ-ot használni. Azon túl persze, hogy miért jó PHP-ban végigiterálni a sorokat, ahelyett, hogy a nyilván sokkal gyorsabb PDOStatement::fetchAll()-t hívná meg (akkor ráadásul nem kéne N-szer elnyeletni a hibakimenetet sem, a @ operátor pedig tudjuk, mennyire "szélsebes")...
Ezen problémák nekem pont elegek voltak ahhoz, hogy SENKINEK ne ajánljam az ezSQL használatát, a kódon a fenti (hol kisebb, hol nagyobb) trehányságok, következetlenségeken túlmenően is ezernyi helyen lehetne optimalizálni.
Végkövetkeztetésem:
- Kezdőknek nem ajánlom, mert egész egyszerűen rosszra tanít. (de az egyértelmű legalábbis, hogy jóra nem)
- Haladóbbaknak nem ajánlom, mert semmiféle teljesítmény-optimalizálásnak nyomát sem találni benne, picit terheltebb oldalak APC vagy hasonló nélkül valószínűleg nyögni fogják a fícsörként emlegetett cache-t (több regex futtatás lekérésenként + tárolás + egyéb ehhez kapcsolódó mechanizmusok - hogy lehet ez gyorsabb egy normálisan konfigolt RDBMS natív, belső query cache-énél?)
Kérdésem tehát a twittelőhöz: Te kinek ajánlod ezt a lib-et?
Mégegyszer: nem a személyed, a bejegyzésed, vagy a hivatkozott blog ellen keltem ki - hanem a jelenség ellen, amit az ezSQL képvisel. Kérlek ne vedd ezt ellened irányuló offenzívának ezért.
■ tikaszvince "PHP: Fast and easy SQL queries using ezSQL | http://t.co/QTw7jY0i http://t.co/iOpHK1VN #weblabor"
Szeretném a vitát nyílt vizekre vinni, mert szakmai (semmiképp nem személyes) meggyőződésem, hogy mind a hivatkozott bejegyzés, mind az onnan továbbhivatkozott oldalon található leírás olyan adatbázis kezelési, biztonsági, szakmai bakiktól hemzseg, amely ellen évek óta küzd a közösség egy jókora (és egyre növekvő) része.
Példaként említeném:
- PREPARE statement-ek támogatásának/példáinak totális hiánya, ehelyett a jóval kevésbé hatékony és biztonságtalanabb ismételten elküldött INSERT lekérések használata
- SQL injection elleni védelemnek nyoma nincs, ellenben tucatnyi példa szerepel a hivatkozott leírásban arra, hogyan lehet mindezt lehetővé tenni könnyen a külső személyek számára (a hivatkozott cikkből is hiányzik az erre való igény).
Konkrét példákat kiemelve a leírásból:
Example 10:
foreach ( $db->get_col("SHOW TABLES",0) as $table_name )
{
$db->debug();
$db->get_results("DESC $table_name");
}
{
$db->debug();
$db->get_results("DESC $table_name");
}
1. SHOW TABLES? Ne már. Az INFORMATION_SCHEMA mire való?
2. Változónév a lekérésben??? Escape-elni majd a magic_quotes_gpc fog?! (legújabban deprecated...)
Example 3 – Return results as numerical array:
if ( $results = $db->(“SELECT $animal[$type] FROM $type”,ARRAY_N))
{
foreach ( $results as $result )
{
echo “$result[0]<br>”;
}
}
else
{
echo “No $animal\s!”;
}
{
foreach ( $results as $result )
{
echo “$result[0]<br>”;
}
}
else
{
echo “No $animal\s!”;
}
Vajon a szerzőnek van halovány sejtelme arra nézvést, hogy a fenti kódrészlet hányszor több opkódra fordul le annál, mint ha konkatanálást használna? (zárójeles megjegyzés: nem ellenőriztem, de gyaníthatóan még akkor is kevesebb opkód lenne a végeredmény, ha a konkatanált változókra külön-külön hívnánk valamilyen escape függvényt - és akkor még SQL injectet se lehetne csak úgy belenyomni)
$db->escape:
$db->escape – Format a string correctly in order to stop accidental mal formed queries under all PHP conditions.
Költői kérdés: ha az escape függvény formázásra való, és nem escape-elésre, akkor miért ez a neve?
Lírai válasz:
makes any string safe to use as a value in a query under all PHP conditions. [...] Note: Should not be used by itself to guard against SQL injection attacks[...]
Tehát biztonságossá teszi a lekérést, de azért nem igazán használható az SQL injection ellen. Ééééértem... o.O
A bizonyosság kedvéért ellenőriztem: az ezSQL_pdo osztály kódjában a 110-es sorban található tökéletes sületlenség - konkrétan: $str = addslashes(stripslashes($str)) - végez valamiféle escape-elést, de arra még véletlenül sem a PDO::quote() metódusát használja. Ezzel szemben az ezSQL_mysql osztály már legalább mysql_real_escape_string() hívást tartalmaz. Érthetetlen.
Egyébként ugyanebben a PDO-ra épülő implementációban találtam még egy érdekességet:
while ( $row = @$sth->fetch(PDO::FETCH_ASSOC) )
{
// Store relults as an objects within main array
$this->last_result[$num_rows] = (object) $row;
$num_rows++;
}
{
// Store relults as an objects within main array
$this->last_result[$num_rows] = (object) $row;
$num_rows++;
}
Befizetem egy sörre azt a kollégát, aki elmagyarázza nekem (és alátámasztja), hogy miért jobb PDO::FETCH_ASSOC-cal lekérni egy sort a resultset-ből, majd utána a kapott array-t object-té cast-olni, mint egyszerűen PDO::FETCH_OBJ-ot használni. Azon túl persze, hogy miért jó PHP-ban végigiterálni a sorokat, ahelyett, hogy a nyilván sokkal gyorsabb PDOStatement::fetchAll()-t hívná meg (akkor ráadásul nem kéne N-szer elnyeletni a hibakimenetet sem, a @ operátor pedig tudjuk, mennyire "szélsebes")...
Ezen problémák nekem pont elegek voltak ahhoz, hogy SENKINEK ne ajánljam az ezSQL használatát, a kódon a fenti (hol kisebb, hol nagyobb) trehányságok, következetlenségeken túlmenően is ezernyi helyen lehetne optimalizálni.
Végkövetkeztetésem:
- Kezdőknek nem ajánlom, mert egész egyszerűen rosszra tanít. (de az egyértelmű legalábbis, hogy jóra nem)
- Haladóbbaknak nem ajánlom, mert semmiféle teljesítmény-optimalizálásnak nyomát sem találni benne, picit terheltebb oldalak APC vagy hasonló nélkül valószínűleg nyögni fogják a fícsörként emlegetett cache-t (több regex futtatás lekérésenként + tárolás + egyéb ehhez kapcsolódó mechanizmusok - hogy lehet ez gyorsabb egy normálisan konfigolt RDBMS natív, belső query cache-énél?)
Kérdésem tehát a twittelőhöz: Te kinek ajánlod ezt a lib-et?
Mégegyszer: nem a személyed, a bejegyzésed, vagy a hivatkozott blog ellen keltem ki - hanem a jelenség ellen, amit az ezSQL képvisel. Kérlek ne vedd ezt ellened irányuló offenzívának ezért.
Hibák
Éppen ezért örülök a Node.js-beli adatbázis moduloknak, mivel azokat már eleve úgy fejlesztették ki, hogy könnyű legyen átadni a paramétereket. Kényelmesebb őket átadni a szabványos módon, mint mindenfajta string machinálással.
$nid
nem jelent semmit, főleg stringben, mivel nincs automatikus behelyettesítés (majd lesz az ES.next-ben)miért jó PHP-ban
Erre van ötletem: bizonyos mennyiség fölött esetleg kifutna a rendelkezésére álló memóriából.
A memóriából a jelenlegi
@ használatáról érdemes
A csiripek 90%-át tikaszvince
én ott hagytam abba, hogy...
na ennél a mondatnál hagytam abba az olvasást. Egy ilyen adatbázis-absztrakciós rétegnek a következőket kell tudnia (szerintem):
Na ebből a listából az ezSQL csak az 1. követelményt teljesíti. Teljesen felejtős a dolog, kicsit fel is húztam magam rajta, hogy minek ír valaki dbms wrapper libet, ha ennyire nem megy neki. Vagy legalább dugná el az asztalfiókba -.-
minek ír valaki dbms wrapper
Minek? Unatkozik, tanulni
Nem veszem ;)
Kinek ajánlom a lib-et? Senkinek.
Kinek ajánlottam a hivatkozott postot? A weblabor közönségének.
Szinte soha nem szoktam véleményezni egy ajánlott linket. Nem véleményezek, mert a twitter 140 karakterébe nem fér bele a hivatkozás (még ha rövidített is) és a post címe mellé egy-egy komment. És nem véleményezek, mert általában tartózkodom az azonnali véleményt nyilvánítástól.
Általában ezek a linkek, amiket #weblabor címkével twittere küldök, GoogleReader-ben jönnek velem szembe. Ezeket elolvasom és ha a weblabor profiljába vág és engem érdekel akkor megy twitterre. És igen, néha becsúszik egy kevésbé minőségi dolog is.
Személy szerint a csiripek beküldésével nem az oktatás a célom, hanem a tartalom ajánlás, ezen keresztül pedig az olyan fórum témák kiprovokálása itt, a weblabor fórumán, mint ez a téma is.
De ha gondolod, akkor néha a CSI:PHP blogról küldhetek #weblabor #horror címkékkel egy-egy bejegyzést külön neked címezve ;)
--
@tikaszvince
Tikász Vince
Köszi a választ :)
Ha a provokáció volt a célod a twittel, akkor most komolyan örülök neki, hogy szokásommal ellentétben "felültem" neki :)
Örülök annak is, hogy sok az azonosság a véleményekben, örömteli, hogy egyre többen figyelnek oda arra (valamint adják tovább és mintegy őrködnek fölötte), hogy körültekintően válasszunk eszközt és lehetőség szerint igényes megoldásokat alkalmazzunk.
Semmi baj az ezSQL célkitűzésével, bizonyos helyzetekben akár még indokolt is lehetne a használata - de semmi képp sem a jelenlegi állapotában, mert az egyszerűen veszélyes. Kontributálni kéne hozzá, de félő, hogy akkor alig maradna valami az eredeti kódból, annyi benne a cserélni/optimalizálni való.
Szerintem
Rendben, igyekszem és örülök,
Mit legyen helyette?
A cikk után így el is ment a kedvem tőle rendesen, viszont így felmerült bennem az a kérdés, hogy akkor ti mit ajánlotok? Van valami favorit wrapper vagy csak egyszerűen a PDO-t használjátok?
Nem szeretem
Túl okos?
Nekem inkább az (volt) a bajom vele, hogy megpróbál nagyon általános lenni, emiatt sok olyan funkció használatát problémássá teszi/teheti, ami nem lenne gond, ha közvetlenül az alá tolt adatbázis kezelő driverét használnád. (nem tudok konkrét példát, ahhoz túl rég játszottam vele – nem feltétlenül mysqlről beszélek)
Ugyanaz
Adatbázis kezeléshez én a
Több adatbázis motort is támogat, elméletileg lehet köztük váltani menet közben is megkötésekkel. Biztonság szempontjából a maximumot nyújtja, nehéz benne úgy átadni paramétert, hogy az ne legyen escepelve, szószerint akarni kell. Háttérben statementeket készít és van benne cahce is (apc, memcache).
Doctrine
Behaviors részben: nested set, soft delete, i18n, csak hogy egy párat említsek, plusz ott vannak benne az eventek, a pager stb.
Doctrine-en kívül még egy másik jó orm a propel, de minőségben szerintem veri a doctrine (használom mindkettőt).
Köszönöm a tippet. A Doctrine
A Doctrine nevet láttam már leírva, de nem ismerem. Most akkor majd egy kicsit elmélyülök benne.
Ahogy így elnézegetem a példákat meg a beleolvastam a doksiba látom, hogy leginkább MVC-re van ez kitalálva, amivel jelenleg még hadilábon állok, de időtől és feladattól függően megpróbálom a kettőt összehozni.
Nincsmit, ha doctrinben