Ablakok.  Vírusok.  Jegyzetfüzetek.  Internet.  hivatal.  Segédprogramok.  Drivers


Kezdésnek egy kicsit arról, hogy egyáltalán miért van szükség ezekre a perjelekre.
Ha bármilyen adatot behelyettesítünk a lekérdezésben, akkor ahhoz, hogy ezeket az adatokat meg tudjuk különböztetni az SQL parancsoktól, idézni kell.
Például ha írsz
SELECT * FROM táblázat WHERE név = Számla
akkor az adatbázis úgy dönt, hogy Bill egy másik mező neve, nem találja meg, és hibát ad ki. Ezért a helyettesített adatok (in ez az eset név Bill) idézőjelbe kell tenni - akkor az alap karakterláncnak fogja tekinteni, amelynek értékét a név mezőhöz kell rendelni:
SELECT * FROM táblázat WHERE név = "Számla"
Magában az adatban azonban idézőjelek is találhatók. Például,
SELECT * FROM táblázat WHERE név = "D"Artagnan"
Itt az adatbázis úgy dönt, hogy "D" az adat, az Artagnan pedig egy parancs, amelyet nem ismer, és szintén hibát fog kiütni. Ezért minden adatot nyomon kell követni, hogy elmagyarázzuk az adatbázisnak, hogy a bennük található idézetek (és néhány más speciális karakter) az adatokra vonatkoznak.
Ennek eredményeként a megfelelő kérést kapjuk, amely nem okoz hibákat:
SELECT * FROM táblázat WHERE név = "D\"Artagnan"

Így azt találtuk, hogy amikor adatokat helyettesítünk egy lekérdezésben, két szabályt kell követni:
- a lekérdezésbe beszúrt összes adatot idézőjelek közé kell tenni (egyes vagy dupla, de kényelmesebb és gyakoribb az egyszeres idézőjel).
- minden karakterlánc-változóban a speciális karaktereket perjellel kell megszakítani.

Külön meg kell jegyezni: a hozzáadott perjelek NEM kerülnek be az adatbázisba. Csak a kérésben van rájuk szükség. Az alaphoz ütve a perjeleket el kell dobni. Ennek megfelelően gyakori hiba a perjelek használata az adatok adatbázisból való lekérésekor.

Valójában a fentiek mindegyike a karakterlánc típusú adatokra és dátumokra vonatkozik. A számok beszúrhatók vágás nélkül, vagy idézőjelek közé helyezhetők. Ha így tesz, akkor SZÜKSÉGSZERŰEN! erővel öntse az adatokat a kívánt típusba, mielőtt beszúrná a lekérdezésbe, például:
$id = intval($id );
Az egyszerűség (és a megbízhatóság) érdekében azonban a számokkal ugyanúgy dolgozhatunk, mint a karakterláncokkal (mivel a mysql továbbra is a kívánt típusra konvertálja őket). Ennek megfelelően nyomon követjük és idézzük a kérelemben szereplő adatokat.

Van még egy szabály - nem kötelező, de be kell tartani a hibák elkerülése érdekében:
A mezők és táblázatok nevét idézőjelek közé kell tenni - "`" (az ezzel a szimbólummal ellátott kulcs a szabványos billentyűzet az "1" billentyűtől balra) Végül is a mező neve megegyezhet a kulcsszavakat mysql, de ha visszaidézőt használunk, akkor a MySQL mindent helyesen ért:
SELECT * FROM `table` WHERE `date` = "2006-04-04"
Ezeket az idézeteket meg kell különböztetni, és nem szabad összetéveszteni egymással. Azt sem szabad elfelejteni, hogy a hátsó idézőjeleket nem kerülik el perjelek.

Tehát megtanultuk, hogyan kell helyesen behelyettesíteni az adatokat a kérésbe.
DE! A dinamikus lekérdezés nem korlátozódik az adatok helyettesítésére. A lekérdezésben gyakran SQL parancsokat és mezőneveket kell helyettesítenünk. És itt már át is megyünk a biztonság témájára:

Az SQL Injection egyfajta hackertámadás, amikor a szkriptnek továbbított adatokat úgy módosítják, hogy az ebben a szkriptben generált lekérdezés valami egészen mást kezd végrehajtani, mint amire szánták.
Az ilyen támadások elleni védekezés szabályai két pontra oszthatók:
1. Adatokkal való munka.
2. Lekérdezésvezérlőkkel való munka.

Az első pontot fentebb részletesen tárgyaltuk. Azt lehet mondani, hogy ez valójában nem védekezés. Az adatok lekérdezéshez való hozzáadására vonatkozó szabályok betartását mindenekelőtt az SQL SYNTAX követelményei határozzák meg. Mellékhatásként pedig van védelmünk a hackelés ellen is.

A második pont sokkal nehezebb, mivel nincs egyetlen univerzális szabály, mint az adatokra – a visszafelé mutató idézet semmiképpen sem védi meg a mezőnevet a hacker általi módosítástól. A táblázat nevét nem lehet idézni, SQL utasítások, LIMIT parancsbeállítások és egyéb operátorok.
Ezért a fő szabály a vezérlőelemek kérésben való helyettesítésekor a következő:
Ha dinamikusan szeretne SQL utasításokat vagy mezők, adatbázisok, táblák neveit behelyettesíteni a lekérdezésbe, semmi esetre se illessze be közvetlenül a lekérdezésbe.
Az ilyen kiegészítések minden beállítását ELŐRE kell írni a szkriptben, és a felhasználó által megadott adatok alapján kell kiválasztani.
Például, ha egy mezőnevet utasítással kell átadnia a rendelésnek, akkor semmi esetre se helyettesítse közvetlenül. Előbb meg kell nézni. Például hozzon létre egy érvényes értékek tömbjét, és csak akkor helyettesítse be a kérést, ha az átadott paraméter jelen van ebben a tömbben:
$orders =array("név" , "ár" , "mennyiség" );
$kulcs = array_search($_GET [ "rendezés" ], $rendek ));
$orderby = $rendelések [ $kulcs ];
$query = "SELECT * FROM `table` ORDER BY $orderby";
A korábban leírt opciók tömbjében keresünk egy, a felhasználó által beírt szót, és ha megtaláljuk, kiválasztjuk a tömb megfelelő elemét. Ha nem található egyezés, a tömb első eleme kerül kiválasztásra.
Így a kérést nem azzal helyettesítjük, amit a felhasználó beírt, hanem azzal, amit a szkriptünkben írtunk.
Minden más esetben ugyanezt kell tenni.
Például, ha a WHERE záradék dinamikusan jön létre:
if (!empty($_GET [ "ár" ])) $where .= "price="" .mysql_real_escape_string ($_GET [ "ár" ]).""" ;
$query = "SELECT * FROM `table` WHERE $hol";
Nehezen tudom elképzelni azt az esetet, amikor a tábla nevét dinamikusan be lehet illeszteni a lekérdezésbe, de ha ez megtörténik, akkor a nevet is csak a szkriptben korábban megírt halmazból kell beilleszteni.
A LIMIT utasítás paramétereit egész típusúra kell önteni a használatával aritmetikai műveletek vagy az intval() függvény.
Nem szabad azt gondolnia, hogy az itt felsorolt ​​példák kimerítik a dinamikus lekérdezés összes lehetőségét. Csak meg kell értened az elvet, és minden ilyen esetben alkalmazni kell.

A LIKE operátorral való munka jellemzői
Teljesen külön eset- LIKE operátor.
Először is, a szokásos zárójelek mellett a LIKE-ban behelyettesített változókban a perjeleket meg kell duplázni. Azaz, ha a változó tartalmazza a \ karaktert, akkor meg kell duplázni, majd végre kell hajtani a szokásos zárójelet a mysql_real_escape_stringen keresztül.
Például, ha a karakterláncot keressük
a \ karaktert "backslash"-nek hívják, és pontos egyezésre van szükségünk, csak a mysql_real_escape_string-et használjuk, és a lekérdezés szabványos:
SELECT * FROM teszt WHERE mező = "a \\ karakter neve \"backslash\"" Ha ezt a karakterláncot LIKE-ban akarjuk helyettesíteni, akkor először minden perjelet kettőre kell cserélnünk, majd alkalmazzuk a mysql_real_escape_string-et. Az eredmény az lesz
SELECT * FROM tábla WHERE mező, mint a "% szimbólum \\\\ neve \"backslash\"%"
Másodszor, vegye figyelembe, hogy a perjeleket hozzáadó függvények egyike sem adja hozzá őket a LIKE operátorban használt "%" és "_" keresési metakarakterekhez. Tehát ha ezt az operátort használja, és nem szeretné, hogy a _ és % karakterek helyettesítő karakterként legyenek használva, akkor kézzel adja hozzá a perjeleket. Ezt a paranccsal lehet megtenni
$data = addCslashes($data , "%_" ); Figyelem – ez nem okoz viszketést! Ennek a függvénynek a nevében egy extra "c" van.

Így kiderül, hogy a LIKE operátorban használt változókat külön kell feldolgoznunk.
először cserélje ki az egyik perjelet kettőre, például a következő kóddal:
$var = str_replace ("\\" , "\\\\" , $var ); majd (lehetséges, hogy a kérésbe kerülő összes többi adattal együtt) nyomon követjük:
$var = mysql_real_escape_string($var ); majd ha azt akarjuk, hogy a _ és % pontosan megegyezzen önmagunkkal, akkor megtesszük
$var = addCslashes ($var , "_%" );
Ennek eredményeként, ha keresünk például egy ilyen sort
a \ karaktert "fordított perjelnek", a _ karaktert "aláhúzásnak" hívják majd feldolgozás után a kérésben így kell kinéznie:
"A % szimbólum \\\\ \"fordított perjel\", a \_ szimbólum pedig \"aláhúzás\" Vagyis az eredetileg a sorban lévő perjel megnégyszereződött. A többi karaktert szokás szerint lenyomozták. Plusz - az aláhúzás karakterét nyomon követték.

A perjelekről. Hogyan lehet megszabadulni tőlük
A perjel vagy a fordított perjel az angol hátsó perjelből egy fordított perjel ("\"), amely hirtelen, érthetetlen módon jelenik meg a változóidban. Hozzáadják néhány speciális karakterhez, de leginkább az idézetek miatt veszik észre.
Ez speciális miatt történik PHP beállítások, általában alapértelmezés szerint engedélyezve van a tárhelyen. Elméletileg ezek a beállítások növelhetik az adatbázissal dolgozó szkriptek biztonságát. A gyakorlatban a perjelek automatikus hozzáadása gyakran zavart és kényelmetlenséget okoz mind az adatbázissal való munka során, mind annak hiányában.
Az alábbiakban mindkét esetet részletesen tárgyaljuk.

A perjelek automatikus hozzáadásáért a php.ini direktívák a felelősek, amelyeket összefoglaló néven "varázsidézeteknek" neveznek:
magic_quotes_gpc és magic_quotes_runtime Ha az első engedélyezve van, akkor a PHP automatikusan perjeleket ad a felhasználótól származó adatokhoz - a POST-ból, GET kéréseketés a cookie-t (valamint a HTTP-engedélyezésen keresztül kapott bejelentkezési névre és jelszóra).
Ha a második, akkor a szkript végrehajtása során kapott adatokhoz - például fájlból vagy adatbázisból - perjelek kerülnek.

Ha adatbázis nélkül dolgozol, vagy megfelelően dolgozol az adatbázissal (amiről alább lesz szó), a plusz perjelek csak zavarnak, és meg kell szabadulnod tőlük. A legegyszerűbb és leghelyesebb módja az automatikus hozzáadás letiltása a PHP beállításaiban.
Ezt megteheti a php.ini megfelelő direktíváinak kijavításával, ha van hozzáférése, vagy létrehozhat egy .htaccess fájlt a webhely gyökérkönyvtárában, és sorokat ad hozzá.
php_flag magic_quotes_gpc 0
php_flag magic_quotes_runtime 0

Ha nem tudja ily módon letiltani, akkor különböző bonyolultságú kódot kell írnia, hogy megtisztítsa a bejövő adatokat a perjelektől. (Ha azonban olyan hordozható alkalmazást akarsz írni, ami nem függ a PHP beállításoktól, akkor is meg kell írnod. És tedd bele egy külön blokkba a szkripteid elején).

A működés közben kapott adatokkal úgy kezelhető a legegyszerűbb, ha a szkript elejére írunk
set_magic_quotes_runtime(0); A felhasználótól kapott adatok esetében minden sokkal bonyolultabb. Ehhez a kódhoz két függvényre van szükségünk:

  • A get_magic_quotes_gpc függvénnyel ellenőrizheti, hogy a PHP hozzáadta-e.
  • a csíkozás funkció eltávolítja a perjeleket.
    Ennek megfelelően az első segítségével ellenőrizni kell, és ha a PHP hozzáadta, akkor az összes bejövő változót iterálja, és a második segítségével törölje.
    Ha jól csinálod, a register_globals = off beállítással, akkor elég, ha a böngészőből származó adatokat tartalmazó összes tömbre csíkot teszel.
    például a következő kódot beillesztheti az összes webhely-szkriptbe:
    függvénycsíkok (& $el ) (
    if (is_tömb ($el ))
    foreach($el mint $k => $v )
    csíkok($el[$k]);
    else $el = perjel($el );
    }
    if (get_magic_quotes_gpc()) (
    csíkok($_GET);
    csíkok($_POST);
    csíkok($_COOKIE);
    strips($_REQUEST);
    if (isset($_SERVER [ "PHP_AUTH_USER" ])) csíkok ($_SERVER [ "PHP_AUTH_USER" ]);
    if (isset($_SERVER [ "PHP_AUTH_PW" ])) csíkok ($_SERVER [ "PHP_AUTH_PW" ]);
    }
    Abban az esetben rossz beállítások register_globals nehéz lesz egyáltalán elfogadható megoldást találni, ezért jobb - ismétlem - azonnal dolgozni a megfelelő beállításokkal.

    Megjegyzések

    • Az okok között, amelyek miatt ne hagyatkozzon a "varázsidézetekre", van még egy. Nagyon valószínűtlen, de akkor is. A "varázsidézetek" valójában nem két irányelv, hanem három. A harmadik a magic_quotes_sybase. Nemcsak idézőjelet ad hozzá perjel helyett, de a magic_quotes_gpc hatását is megszünteti. Ha valami csoda folytán mindkét direktíva „be” állapotú, akkor az utolsó nem fog működni! Vagyis a "varázsidézetekre" támaszkodva ebben az esetben a helytelenül összeállított lekérdezések minden örömét megkapjuk. Általánosságban, pusztán elméletileg, ennek a direktívának a jelenlétét figyelembe kell venni, mivel olyan meglepetést is tartogat, mint ... megváltoztatja a perjel és a csíkos perjel függvények viselkedését! Ha magic_quotes_sybase = on, akkor ezek a függvények perjel helyett egyetlen idézőjel hozzáadását és eltávolítását kezdik meg.
    • Az összes példa csak a Mysql adatbázisra vonatkozik. A lekérdezések összeállításának konkrét szabályai eltérhetnek más DBMS-ek esetében, de általános elv ugyanaz marad:
      • ha az adatbázissal vagy egy harmadik féltől származó könyvtárral való munkavégzéshez szükséges API biztosítja speciális funkciókat kérések benyújtásához, és van lehetőség a használatukra, akkor mindenekelőtt ezeket kell használni.
      • Ha nincsenek ilyen függvények, akkor a dokumentációban kell keresni a speciális karakterek kihagyásának funkcióit ehhez a DBMS-hez.
    Megjegyzés: formák
    Amikor értéket adunk ki az űrlapbeviteli címkékben, a perjelek nem segítenek.
    A teljes szöveg megjelenítéséhez egy ilyen mezőben, az értéket idézőjelbe kell tenni, és a kimeneti adatokhoz alkalmazza a htmlspecialchars() függvényt
    Példa:

    Azt is meg kell jegyezni (bár ennek semmi köze az idézőjelekhez és perjelekhez), hogy általában a htmlspecialchars függvényt kell használni, amikor a böngészőbe írunk ki minden olyan adatot, amely nem ellenőrzött felhasználótól érkezik. Hogy miért kell ezt megtenni, a Google-ban kérésre elolvashatod, mi az XSS sebezhetőség
    készítette: phpfaq.ru
  • Munkám jellegéből adódóan a webalkalmazások forráskódjának biztonsági auditját kell végeznem.
    Rengeteg webes alkalmazás és sok kód...

    Nem titok, hogy az SQL injekciós sebezhetőségek a leggyakoribbak a webalkalmazás-szerverek sérülékenységei közül. Vannak olyan platformok és keretrendszerek, ahol az ilyesmi szinte teljesen ki van zárva, például az ORM "ohm és így tovább. De a statisztikák makacsul árulják el nekünk a webes alkalmazások abszolút túlsúlyát az interneten egyszerű összefűzött SQL lekérdezésekkel. Ezen kívül vannak esetek ahol az ORM általában alkalmazható, ha például nem csak a kifejezési paramétereknek, hanem magának a lekérdezési logikának is operátori szinten kell függnie a felhasználói adatoktól.

    Szóval, kezdjük.

    Haszontalan karakter menekülés
    Az SQL-befecskendezéssel szemben sebezhető PHP webalkalmazások 83%-ában megtalálható
    Egy karakteres escape függvény alkalmazása, mint pl
    mysql_escape_string
    mysql_real_escape_string
    szempillákat ad hozzá
    idézőjelek nélkül. Leggyakrabban numerikus paraméterekben nyilvánul meg (mindenféle * _id).
    Példa
    $sql = "FELHASZNÁLÓ KIVÁLASZTÁSA A felhasználói listából WHERE userid=".mysql_real_escape_string($_GET["uid"]);

    Biztonságos kódnak tűnik, de csak külsőre. A PHP SQL-befecskendezésének leggyakoribb mintája itt kúszott be. A biztonsági rés megtámadásához a támadónak egyszerűen nem kell használnia a " " \x00 \r \n \x1a karaktereket a támadási vektorban.
    Például:
    /index.php?uid=-777 UNION SELECT jelszó a felhasználói listából

    Keresés a kódban
    Bonyolítja a nyelv szemantikája. Az egyszerű kereséshez használhatja az egrep-et:
    egrep -Rin "(kiválasztás|frissítés|beszúrás|törlés|csere).*(from|set|into).*(mysql_escape_string|mysql_real_escape_string|addslashes)" . | grep -v "[\""]["\"]"

    A keresési kifejezés logikája az, hogy megtalálja az összes olyan karakterláncot, amely nem tartalmaz idézőjelek sorozatát ("", "", "", "") a szűrési függvények bal oldalán. A módszer természetesen messze nem 100%, de lehetetlen reguláris kifejezést megkövetelni a szemantikai elemzés elvégzéséhez.
    Az információk megjelenítésének kényelme érdekében a funkciót színnel kiemelheti a konzolon:
    egrep -Rin "(kiválasztás|frissítés|beszúrás|törlés|csere).*(from|set|into).*(mysql_escape_string|mysql_real_escape_string|addslashes)" . | grep -v "[\""]["\"]" | egrep --color "(mysql_escape_string|mysql_real_escape_string|addslashes)"

    A sablon sérülékenysége elleni védelem érdekében a legjobb a típusöntvény használata.
    Mindig gyorsabb és megbízhatóbb, mint mindenféle szűrés és árnyékolás.
    A fenti példában a javítás a következő lehet:
    $sql = "FELHASZNÁLÓ KIVÁLASZTÁSA A felhasználók listájából WHERE userid=".intval($_GET["uid"]);

    Ezzel zárjuk ezt a rövid esszét. Arra kérek minden webfejlesztőt, hogy próbálja meg ellenőrizni a forrásait az ilyen konstrukciókért. Még jobb, ha kiterjeszti a fenti keresési szkriptet az emberek számára.

    idézet karakterlánc (11)

    Megpróbálom megtalálni a kérések írásának legjobb módját. Megértem a következetesség fontosságát is. Eddig véletlenül használtam szimpla idézőjeleket, dupla idézőjeleket és hátlapokat minden komoly gondolkodás nélkül.

    $query = "INSERT INTO table (id, col1, col2) ÉRTÉKEK (NULL, érték1, érték2)";

    A fenti példában vegye figyelembe azt is, hogy a „tábla”, „oszlop[n]” és „érték[n]” változók lehetnek.

    Mi ennek a szabványa? Mit csinálsz?

    Körülbelül 20 perce olvasom a válaszokat hasonló kérdésekre, de úgy tűnik, hogy erre a kérdésre nincs végleges válasz.

    Válaszok

    Most tegyük fel, hogy közvetlen bejegyzés változót használ a MySQL lekérdezésben, majd használja a következőképpen:

    $query = "INSERT INTO `table` (`id`, `name`, `email`) VALUES (" ".$_POST["id"]." ", " ".$_POST["név"]." ", " ".$_POST["e-mail"]." ")";

    Ez a legjobb gyakorlat a PHP-változók használatához a MySQL-ben.

    Leginkább a Mysql-ben ezeket az azonosítótípusokat használják a ` , " , " és () lekérdezésekben.

      " vagy " használta a karakterláncot a "26-01-2014 00:00:00" vagy a "26-01-2014 00:00:00" értékként. Ez az azonosító csak a karakterlánc "26-01-2014 00:00:00" függvényében használatos, például a now() vagy a sum ,max .

      ` használja a tábla vagy táblatáblázat felvételéhez, például válassza az oszlop_nevet a táblázat_neve közül, ahol id="2"

      () csak a lekérdezés részeinek egyszerű bezárására szolgál, például válassza ki az oszlopnév értéket a táblanévből, ahol (id = "2" és gender = "férfi") vagy name = "rakesh".

    Az összes (jól kifejtett) válaszon kívül egyiket sem említettem az alábbiakban, és gyakran járok erre a kérdésre.

    Dióhéjban; A MySQL úgy gondolja, hogy matematikát szeretne végezni a saját táblázatában/oszlopában, és értelmezze az olyan kötőjeleket, mint az "e-mail", mint e-mail .

    A felelősség megtagadása. Ezért úgy gondoltam, hogy „Tájékoztatásul” választ adom hozzá azok számára, akik teljesen újak az adatbázisokkal való munkában, és esetleg nem értik a már leírt szakkifejezéseket.

    (Fentebb jó válaszok találhatók az SQL-kérdés természetére vonatkozóan, de ez akkor is releváns lehet, ha még nem ismeri a PHP-t.)

    Talán fontos megjegyezni, hogy a PHP eltérően kezeli az egy- és a dupla idézőjeleket...

    Az egy idézőjeles karakterláncok "literálok", és jó néhány WYSIWYG karakterláncot képviselnek. A dupla idézőjeles karakterláncokat a PHP értelmezi a lehetséges változók helyettesítésére (a PHP-ben a háttérhivatkozások nem pontosan karakterláncok, parancsot hajtanak végre a shellben, és eredményt adnak vissza).

    $foo = "bár"; echo "van egy $foo"; // Van egy $foo echo "van egy $foo"; // Van egy bár echo `ls -l`; // ... egy könyvtár lista

    Ha a táblázatok oszlopai és értékei változók, akkor két módja van:

    Idézőjelekkel "" a teljes lekérdezés:

    $query = "INSERT INTO $table_name (id, $col1, $col2) ÉRTÉKEK (NULL, "$érték1", "$érték2")";

    $query = "INSERT INTO ".$table_name." (id, ".$col1.", ".$col2.") ÉRTÉKEK (NULL, "".$érték1."", "".$érték2."" )";

    Egyetlen idézőjelekkel "" :

    $query = "INSERT INTO ".$table_name." (id, ".$col1.", ".$col2.") ÉRTÉKEK (NULL, ".$érték1.", ".$érték2.")";

    Ha az oszlop/érték neve hasonló egy MySQL lefoglalt kulcsszóhoz, használjon `` visszajelző jelölést.

    Jegyzet. Ha egy oszlopnevet táblázatnévvel ad meg, használja a következő visszajelzőket:

    `tábla_neve` . `oszlop_neve`<- Примечание: исключить. из задних клещей.

    A tábla- és oszlopazonosítókhoz kell használni a backtick-et, de csak akkor szükséges, ha az azonosító egy MySQL lefoglalt kulcsszó, vagy ha az azonosító szóköz karaktereket vagy a korlátozott halmazon kívüli karaktereket tartalmaz (lásd alább). Gyakran ajánlatos kerülni a foglalt kulcsszavak oszlop- vagy táblázatazonosítóként való használatát, ha lehetséges, az idézési probléma elkerülése érdekében.

    A karakterláncértékekhez szimpla idézőjeleket kell használni, például a VALUES() listában. A MySQL támogatja a dupla idézőjeleket a karakterlánc-értékeknél is, de az egyszeres idézőjeleket szélesebb körben elfogadják más RDBMS-ek, ezért célszerű szimpla idézőjeleket használni a dupla idézőjelek helyett.

    A MySQL azt is elvárja, hogy a szó szerinti DATE és DATETIME értékek egyszeres idézőjelek legyenek karakterláncként, például "2001-01-01 00:00:00". Tekintse meg a dátum és idő szakirodalmi dokumentációját további információkért, különösen a kötőjel használatának alternatíváiért - szegmenselválasztóként a dátum karakterláncokban.

    Tehát a példáddal kétszer idézném a PHP karakterláncot, és egyszeres idézőjeleket használnék a "val1", "val2" értékekhez. A NULL egy MySQL kulcsszó és egy speciális (nem) -érték, ezért nem használják.

    Ezen táblázat- vagy oszlopazonosítók egyike sem lefoglalt szó, és nem használ olyan karaktereket, amelyekhez idézni kell, de azért idéztem őket egymás után (erről később...).

    Az RDBMS-hez kapcsolódó függvényeket (mint például a NOW() a MySQL-ben) nem szabad idézni, bár argumentumaikra ugyanazok a szabályok vagy idézési szabályok vonatkoznak, amelyeket már említettünk.

    Backtick (`) táblázat és oszlop $query = " INSERT INTO `table` (`id`, `col1`, `col2`, `date`, `frissítve) ÉRTÉKEK (NULL, "érték1", "érték2", "2001-01-01", MOST())"; Idézet nélküli kulcsszó ─────┴┴┴┘ │ │ │ │ │ │ │││││ Egyszeres idézőjeles (") karakterláncok ││││││─── │││ Egyszeres idézőjel (") DÁTUM ────────┘ │││││ Idézet nélküli függvény ───────┴┴┴┴┘

    Változó interpoláció

    A változók idézési mintái nem változnak, bár ha a változókat közvetlenül egy karakterláncban kívánja interpolálni, akkor ennek dupla idézőjelnek kell lennie a PHP-ben. Csak győződjön meg arról, hogy az SQL-ben való használathoz megfelelően eltávolítja a változókat. (Ehelyett olyan API használata javasolt, amely támogatja az előkészített utasításokat az SQL-befecskendezés elleni védekezésként).

    // Ugyanez a helyzet néhány változó cseréjével // Itt a $table változó tábla neve visszahúzott idézőjel, és // az VALUES listában lévő változók egyszeres idézőjelek $query = "INSERT INTO `$tábla`(`id`, `col1`, `col2`, `date`) ÉRTÉKEK (NULL, "$val1", "$val2", "$date")";

    Elkészített nyilatkozatok

    Amikor előkészített alkalmazásokkal dolgozik, olvassa el a dokumentációt annak meghatározásához, hogy meg kell-e adni az alkalmazás helyőrzőit. A PHP-ben, PDO-ban és MySQLi-ben elérhető legnépszerűbb API-k magukban foglalják jogosulatlan helyőrzők, mint a legtöbb előkészített API utasítás más nyelveken:

    // PDO példa megnevezett paraméterekkel, idézőjel nélküli $query = "INSERT INTO `table` (`id`, `col1`, `col2`, `date`) VALUES (:id, :col1, :col2, :date)" ; // MySQLi példa a ? paraméterek, idézőjelek nélkül $query = "INSERT INTO `table` (`id`, `col1`, `col2`, `date`) ÉRTÉKEK (?, ?, ?, ?)";

    Visszautalást visszaadó szimbólumok az azonosítókban:

    Például:

    Ugyanezt meg lehet tenni a táblanevek és a mezőnevek esetében is. Ez nagyon jó szokás, ha visszaköti az adatbázis azonosítóját az ablakokhoz.

    Tekintse meg ezt a választ, ha többet szeretne megtudni a visszalépésről.

    Most a kettős idézőjelekről és az egyes idézetekről (Michael már említette).

    De az érték meghatározásához egyszeres vagy dupla idézőjeleket kell használni. Lássunk egy másik példát.

    INSERT INTO `táblanév` (`id, `title`) VALUES (NULL, title1);

    Itt szándékosan elfelejtettem idézőjelbe tenni a cím1-et. A szerver most elfogadja a title1-et oszlopnévként (azaz azonosítóként). Tehát annak jelzéséhez, hogy ez egy érték, dupla idézőjeleket vagy szimpla idézőjeleket kell használnia.

    INSERT INTO `táblanév` (`id, `title`) ÉRTÉKEK (NULL, "title1");

    Mostantól a PHP-vel kombinálva a dupla és szimpla idézőjelek sokkal könnyebbé teszik a lekérdezés írását. Nézzük meg a kérdésben szereplő lekérdezés módosított változatát.

    $query = "INSERT INTO `table" (`id`, `col1`, `col2`) ÉRTÉKEK (NULL, "$érték1", "$érték2")";

    Most a PHP-ben dupla idézőjelek használatával a $val1 és $val2 változók értékét használva, így érvényes lekérdezést készítve. mint

    $val1 = "értékem 1"; $val2 = "2. értékem"; $query = "INSERT INTO `table" (`id`, `col1`, `col2`) ÉRTÉKEK (NULL, "$érték1", "$érték2")";

    INSERT INTO `table` (`id`, `col1`, `col2`) ÉRTÉKEK (NULL, "saját érték 1", "saját érték 2")

    Sok hasznos válasz érkezett itt, amelyek összességében két pontban csúcsosodtak ki.

    1. A BACKTICKS (`) az azonosító nevek körül használatos.
    2. Az értékek körül az EGYES IDÉZETEK (") használatosak.

    És ahogy @MichaelBerkowski mondta

    A tábla- és oszlopazonosítókhoz kell használni a backtick-et, de csak akkor szükséges, ha az azonosító egy MySQL lefoglalt kulcsszó, vagy ha az azonosító szóköz karaktereket vagy a korlátozott halmazon kívüli karaktereket tartalmaz (lásd alább). Gyakran ajánlatos kerülni a foglalt kulcsszavak oszlop- vagy táblázatazonosítóként való használatát, ha lehetséges, az idézési probléma elkerülése érdekében.

    Van olyan eset, amikor az azonosító nem lehet fenntartott kulcsszó vagy tartalmazzák szóköz karakterek vagy karakterek a korlátozott készleten kívül, de szükségszerűen visszacsatolásokat igényelnek körülöttük.

    A 123E10 érvényes azonosító név, de érvényes INTEGER literál is.

    [Anélkül, hogy részletekbe mennék, hogyan kaphatna ilyen azonosító nevet], Tegyük fel, hogy szeretnék létrehozni egy 123456e6 nevű ideiglenes táblát.

    Nincs HIBA a backticken.

    DB > ideiglenes tábla létrehozása `123456e6` (`id` char(8)); Lekérdezés OK, 0 sor érintett (0,03 mp)

    HIBA, ha nem használ visszahívást.

    DB > ideiglenes tábla létrehozása 123451e6(`id` char(8)); 1064-es HIBA (42000): Hiba van az SQL szintaxisában; ellenőrizze a MariaDB kiszolgáló verziójának megfelelő kézikönyvben a megfelelő szintaxist az "123451e6 (`id` char (8)" közelében az 1. sorban

    Az 123451a6 azonban egy finom azonosító név (nincs hátsó pipa).

    DB > ideiglenes tábla létrehozása 123451a6(`id` char(8)); Lekérdezés OK, 0 sor érintett (0,03 mp)

    Ez teljes egészében azért van, mert az 1234156e6 is egy exponenciális szám.

    A karakterláncértékekhez szimpla idézőjeleket kell használni, például a VALUES() listában.

    A backtickeket általában az azonosító jelzésére használják, és biztonságosak lehetnek a fenntartott kulcsszavak véletlen használata miatt is.

    PHP-ben és MySQL-ben kombinálva a dupla és szimpla idézőjelek sokkal könnyebbé teszik a lekérdezések írását.

    A MySQL-ben kétféle idézet létezik:

    1. ", hogy belefoglalja a karakterlánc-literálokat
    2. ` azonosítók, például tábla- és oszlopnevek szerepeltetéséhez

    És akkor ott van: "Ez egy speciális eset. Erre használható egy a fenti célok közül egyszerre a szerver sql_mode sql_mode függvényében:

    1. Alapértelmezett A "karakter" karakterlánc literálok egymásba ágyazására használható "
    2. ANSI_QUOTES módban a " karakter használható azonosítók megadására, ANSI_QUOTES

    A következő lekérdezés az SQL módtól függően eltérő eredményeket (vagy hibákat) produkál:

    SELECT "oszlop" FROM táblázatból WHERE foo = "bar"

    ANSI_QUOTES letiltva

    A lekérdezés kiválasztja a string literal "oszlopot", ahol a foo egyenlő a "bar" karakterlánccal

    ANSI_QUOTES engedélyezve

    A lekérdezés azt az oszlopot választja ki, ahol a foo egyenlő oszloppal

    Mikor kell használni

    • Azt javaslom, hogy kerülje a "" használatát, hogy a kódja ne függjön az SQL-módoktól
    • Mindig tüntesse fel az azonosítókat, mivel ez bevált gyakorlat (elég néhány kérdés, szóval beszélje meg ezt)

    Egyértelmű különbség van a " " és a " " használata között .

    Ha mindenben " " szerepel, nincs "átalakítás vagy fordítás". Úgy van kinyomtatva, ahogy van.

    A " " esetén bármit is vesz körül, a rendszer "lefordítja vagy átalakítja" az értékére.

    Fordításon/konvertáláson a következőket értem: bármi, ami az egyetlen idézőjelben van, nem lesz "lefordítva" az értékükre. Elfogadjuk őket, mivel az idézőjelben szerepelnek. Példa: a=23 , akkor az echo "$a" $a-t generál szabványos kimeneten. Míg az echo "$a" 23-at produkál normál kimeneten.

    Alapvetően tehát mélyen ástam magam a MySQL-ben és a PHP-ben... különösen azokban a biztonsági intézkedésekben, amelyeket meg kell tennem az adatbázis- és űrlapbevitelek kezelésekor. Eddig a következőket találtam erősen ajánlottnak:

    1. Elkészített nyilatkozatok
    2. A _real_escape_string() használata
    3. NEM használ varázsidézeteket, mert összezavarja az adatbázisokat, és olyan dolgokat ad meg, mint például: „Nem nevezted el...”.

    Minden nagyon jó és követem. Azonban azon tűnődtem, hogy az olyan karaktereket, mint a dollárjel [$], a százalékjel [%] és esetleg mások, ki kell-e hagyni. A lekérdezés nem értelmezheti a dollárjelet PHP változóként? Mi a helyzet a LIKE szintaxissal, amelyről hallottam, hogy % karaktert vagy akár helyettesítő karaktert használ? Az elkészített kimutatásoknak technikailag gondoskodniuk kell erről az egészről, de én csak a biztonság kedvéért akartam lenni, és megbizonyosodni arról, hogy minden megfelelően elmenekül. Abban az esetben, ha elfelejtem használni az előkészített nyilatkozatokat, vagy egyszerűen figyelmen kívül hagyom őket, abban reménykedtem, hogy ez a második védelmi vonal megmondja, hogy megszabadulhatok szédülésemtől.

    Jelenleg a következőket használom a menekülésre:

    Escape függvény($connection, $data)( $new_data = trim($data); $new_data = i_real_escape_string($connection, $new_data); $new_data = addcslashes($new_data, "%_$"); $new_data = htmlspecialchars ($új_adatok, ENT_NOQUOTES); $új_adatok visszaadása; )

    Tehát helyes? Valami szörnyen rosszul csinálok? Vegye figyelembe, hogy az adatbázis adatainak visszaküldésekor el kell távolítanom a fordított perjelet a $,% és a _ karakterek előtt.

    Valami szörnyen rosszul csinálok?

    Először is a kutatásodról.

    Elkészített nyilatkozatok - az egyetlen csodálatos dolgot találtál.

    A mysqli_real_escape_string használata közben (feltételezve, hogy előkészített utasításokat használ) haszontalan és káros(olyan eredmény létrehozása, amelyet magad is megjegyeztél: "Azt nevezted meg, hogy nem...").

    A Magic Quotes pedig már régen kikerült a nyelvből – így nem igazán ér semmit.

    Így még az eredeti feltételezések nagy része is egyértelműen hibás.

    Most a kérdésedre.

    A lekérdezés nem értelmezheti a dollárjelet PHP változóként?

    Mi a helyzet a LIKE szintaxissal, amelyről hallottam, hogy % karaktert vagy akár helyettesítő karaktert használ?

    Igen, jól hallottad. A LIKE operátor pontos célja a mintakeresés végrehajtása. A karakterek LIKE-ban való letiltásának a legcsekélyebb értelme sem lenne.

    Minden alkalommal, amikor a LIKE operátort használja, el kell döntenie, hogy melyik karaktert használja és melyiket tiltja le. Egyszeri megoldást nem használhat. Arról nem is beszélve, hogy az összes többi mysql interakcióban a % jelnek nincs különösebb jelentése.

    Az elkészített kimutatásoknak technikailag gondoskodniuk kell erről

    Az elkészített állításoknak semmi közük a $ vagy % jelekhez. Az elkészített utasítások az SQL injekcióhoz kapcsolódnak, de egyetlen karakter sem válthatja ki (nevezhetnénk az "injekciót" megfelelően használt LIKE operátornak, ugye?).

    Végül a legszörnyűbb részhez.

    Abban az esetben, ha elfelejti használni az előkészített utasításokat, vagy egyszerűen elhanyagolja végrehajtásukat,

    semmi sem ment meg.

    És a legkevesebb segítséget az általad tervezett funkció jelentené.

    Összesít.

    1. Szabaduljon meg ettől a funkciótól.
    2. Használat helyőrzők * hogy minden egyes változót reprezentáljon a lekérdezésben.
    3. Escape % és _ karaktereket csak akkor írjon be, ha a LIKE operátor használja, és nem akarja értelmezni őket.
    4. Használja a htmlspecialchars()-t a kimenethez, ne a mysql bemenetet.

    * Olvassa el az elkészített nyilatkozatokat, ha nem ismeri ezt a kifejezést.

    Nem kell megszöknie a dollárjel elől. A MySQL nem kezeli kifejezetten ezt a karaktert, és a PHP csak forráskódban ismeri fel, karakterláncértékekben nem (hacsak nem eval egy karakterláncon, de az egy másik férgek).

    Csak akkor kell kihagynia a % és a _ karaktereket, ha LIKE argumentumként a felhasználói bevitelt használta, és nem akarta, hogy a felhasználó helyettesítő karaktereket tudjon használni. Ez akkor fordulhat elő, ha egy keresési űrlapot dolgoz fel. Adatbázisban való tároláskor nem kell használnia.

    Adatbázis elérésekor nincs szükség a htmlspecialchars használatára. Ezt csak akkor szabad használni, ha adatokat jelenít meg a felhasználó számára egy HTML-oldalon, hogy megakadályozza az XSS-injektálást.

    Attól függően, hogy milyen adatokat és mire használják fel.

    Ha úgy találja, hogy a PHP alapértelmezett kész utasításai túl nagyok és bonyolultak, azt javaslom, hogy vessen egy pillantást a githubon elérhető osztályokra, hogy képet kapjon az egyszerűsített lekérdezésekről.

    Példa lekérdezések beszúrására ezzel az osztállyal

    $data = Array ("login" => "admin", "active" => true, "firstName" => "John", "lastName" => "Doe", "password" => $db->func( "SHA1(?)",Array("titkos jelszó+só")), // jelszó = SHA1("titkos jelszó+só") "createdAt" => $db->now(), // createAt = MOST() " expires" => $db->now("+1Y") // expires = MOST() + intervallum 1 év // Támogatott intervallumok [s]másodperc, [m]perc, [h]óra, [d]nap, [Hónap év); $id = $db->insert("felhasználók", $adat); if ($id) echo "felhasználó jött létre. Id=" . $id; else echo "insert failed:" . $db->getLastError();


    Kezdésnek egy kicsit arról, hogy egyáltalán miért van szükség ezekre a perjelekre.
    Ha bármilyen adatot behelyettesítünk a lekérdezésben, akkor ahhoz, hogy ezeket az adatokat meg tudjuk különböztetni az SQL parancsoktól, idézni kell.
    Például ha írsz
    SELECT * FROM táblázat WHERE név = Számla
    akkor az adatbázis úgy dönt, hogy Bill egy másik mező neve, nem találja meg, és hibát ad ki. Ezért a behelyettesített adatot (jelen esetben a Bill nevet) idézőjelbe kell tenni - ekkor az alap karakterláncnak tekinti, aminek az értékét a névmezőhöz kell rendelni:
    SELECT * FROM táblázat WHERE név = "Számla"
    Magában az adatban azonban idézőjelek is találhatók. Például,
    SELECT * FROM táblázat WHERE név = "D"Artagnan"
    Itt az adatbázis úgy dönt, hogy "D" az adat, az Artagnan pedig egy parancs, amelyet nem ismer, és szintén hibát fog kiütni. Ezért minden adatot nyomon kell követni, hogy elmagyarázzuk az adatbázisnak, hogy a bennük található idézetek (és néhány más speciális karakter) az adatokra vonatkoznak.
    Ennek eredményeként a megfelelő kérést kapjuk, amely nem okoz hibákat:
    SELECT * FROM táblázat WHERE név = "D\"Artagnan"

    Így azt találtuk, hogy amikor karakterlánc-adatokat helyettesítünk egy lekérdezésben, két szabályt kell követni:
    - minden beszúrt karakterlánc adatot idézőjelek közé kell tenni (egyes vagy dupla, de kényelmesebb és gyakoribb az egyszeres idézőjel).
    - a speciális karaktereket perjelekkel kell megszökni.

    Külön meg kell jegyezni: a hozzáadott perjelek NEM kerülnek be az adatbázisba. Csak a kérésben van rájuk szükség. Az alaphoz ütve a perjeleket el kell dobni. Ennek megfelelően gyakori hiba a perjelek használata az adatok adatbázisból való lekérésekor.

    A fentiek mindegyike a karakterlánc típusú adatokra és dátumokra vonatkozik. A számok beszúrhatók vágás nélkül, vagy idézőjelek közé helyezhetők. Ha így tesz, akkor SZÜKSÉGSZERŰEN! erővel öntse az adatokat a kívánt típusba, mielőtt beszúrná a lekérdezésbe, például:
    $id = intval($id );
    Az egyszerűség (és a megbízhatóság) érdekében azonban a számokkal ugyanúgy dolgozhatunk, mint a karakterláncokkal (mivel a mysql továbbra is a kívánt típusra konvertálja őket). Ennek megfelelően nyomon követjük és idézzük a kérelemben szereplő adatokat.

    Van még egy szabály - nem kötelező, de be kell tartani a hibák elkerülése érdekében:
    A mező- és táblaneveket hátsó idézőjelek közé kell tenni - "`" (az ezzel a karakterrel rendelkező billentyű a szabványos billentyűzeten az "1" billentyűtől balra található) Végül is a mezőnév megegyezhet a mysql kulcsszavakkal, de ha használj egy hátsó idézetet, a MySQL megérti, hogy minden helyes:
    SELECT * FROM `table` WHERE `date` = "2006-04-04"
    Ezeket az idézeteket meg kell különböztetni, és nem szabad összetéveszteni egymással. Azt sem szabad elfelejteni, hogy a hátsó idézőjeleket nem kerülik el perjelek.

    Tehát megtanultuk, hogyan kell helyesen behelyettesíteni az adatokat a kérésbe.
    DE! A dinamikus lekérdezés nem korlátozódik az adatok helyettesítésére. A lekérdezésben gyakran SQL parancsokat és mezőneveket kell helyettesítenünk. És itt már át is megyünk a biztonság témájára:

    Az SQL Injection egyfajta hackertámadás, amikor a szkriptnek továbbított adatokat úgy módosítják, hogy az ebben a szkriptben generált lekérdezés valami egészen mást kezd végrehajtani, mint amire szánták.
    Az ilyen támadások elleni védekezés szabályai két pontra oszthatók:
    1. Adatokkal való munka.
    2. Lekérdezésvezérlőkkel való munka.

    Az első pontot fentebb részletesen tárgyaltuk. Azt lehet mondani, hogy ez valójában nem védekezés. Az adatok lekérdezéshez való hozzáadására vonatkozó szabályok betartását mindenekelőtt az SQL SYNTAX követelményei határozzák meg. Mellékhatásként pedig van védelmünk a hackelés ellen is.

    A második pont sokkal nehezebb, mivel nincs egyetlen univerzális szabály, mint az adatokra – a visszafelé mutató idézet semmiképpen sem védi meg a mezőnevet a hacker általi módosítástól. Nem idézhet táblanevet, SQL utasításokat, LIMIT parancsbeállításokat és egyéb utasításokat.
    Ezért a fő szabály a vezérlőelemek kérésben való helyettesítésekor a következő:
    Ha dinamikusan szeretne SQL utasításokat vagy mezők, adatbázisok, táblák neveit behelyettesíteni a lekérdezésbe, semmi esetre se illessze be közvetlenül a lekérdezésbe.
    Az ilyen kiegészítések minden beállítását ELŐRE kell írni a szkriptben, és a felhasználó által megadott adatok alapján kell kiválasztani.
    Például, ha egy mezőnevet utasítással kell átadnia a rendelésnek, akkor semmi esetre se helyettesítse közvetlenül. Előbb meg kell nézni. Például hozzon létre egy érvényes értékek tömbjét, és csak akkor helyettesítse be a kérést, ha az átadott paraméter jelen van ebben a tömbben:
    $orders =array("név" , "ár" , "mennyiség" );
    $kulcs = array_search($_GET [ "rendezés" ], $rendek ));
    $orderby = $rendelések [ $kulcs ];
    $query = "SELECT * FROM `table` ORDER BY$orderby" ;

    A korábban leírt opciók tömbjében keresünk egy, a felhasználó által beírt szót, és ha megtaláljuk, kiválasztjuk a tömb megfelelő elemét. Ha nem található egyezés, a tömb első eleme kerül kiválasztásra.
    Így a kérést nem azzal helyettesítjük, amit a felhasználó beírt, hanem azzal, amit a szkriptünkben írtunk.
    Minden más esetben ugyanezt kell tenni.
    Például, ha a WHERE záradék dinamikusan jön létre:
    if (!empty($_GET [ "ár" ])) $where .= "price="" .mysql_real_escape_string ($_GET [ "ár" ]).""" ;
    $query = "SELECT * FROM `table` WHERE $hol" ;

    Nehezen tudom elképzelni azt az esetet, amikor a tábla nevét dinamikusan be lehet illeszteni a lekérdezésbe, de ha ez megtörténik, akkor a nevet is csak a szkriptben korábban megírt halmazból kell beilleszteni.
    A LIMIT utasítás paramétereit aritmetikai műveletek vagy az intval() függvény segítségével egész típusra kell kényszeríteni.
    Nem szabad azt gondolnia, hogy az itt felsorolt ​​példák kimerítik a dinamikus lekérdezés összes lehetőségét. Csak meg kell értened az elvet, és minden ilyen esetben alkalmazni kell.

    Ha hibát észlel, jelöljön ki egy szövegrészt, és nyomja meg a Ctrl + Enter billentyűket
    OSSZA MEG: