Session ID védelem PHP-ben. A munkamenetek használatának buktatói PHP-ben Érték vagy tömb átadása PHP munkamenet segítségével

Üdvözlet kedves közösség.

Először is szeretnék köszönetet mondani egy nagyon hasznos forrásért. Nem egyszer sok érdekes ötletet és gyakorlati tanácsot találtam itt.

Ennek a cikknek az a célja, hogy rávilágítson a munkamenetek PHP-ben való használatának buktatóira. Természetesen van PHP dokumentáció és rengeteg példa, és ez a cikk nem egy teljes útmutató. Úgy tervezték, hogy feltárja a munkamenetekkel végzett munka néhány árnyalatát, és megvédje a fejlesztőket a felesleges időpazarlástól.

A munkamenetek használatának leggyakoribb példája természetesen a felhasználói jogosultság. Kezdjük a legalapvetőbb megvalósítással, hogy az új feladatok felmerülésekor fokozatosan fejleszthessük.

(Tér- és időtakarékosság érdekében a példáinkat csak magukra a munkamenet-függvényekre korlátozzuk, ahelyett, hogy itt egy teljes értékű tesztalkalmazást építenénk, gyönyörű osztályhierarchiával, átfogó hibakezeléssel és egyéb jó dolgokkal).

A startSession() függvény ( // Ha a munkamenet már elindult, állítsa le a végrehajtást, és adja vissza a TRUE értéket // (a php.ini beállításfájlban a session.auto_start paramétert le kell tiltani - az alapértelmezett érték) if (session_id()) visszatér true; else return session_start(); // Megjegyzés: Az 5.3.0-s verzió előtt a session_start() függvény TRUE értéket adott vissza, még akkor is, ha hiba történt. // Ha 5.3.0-nál korábbi verziót használ, végezzen további ellenőrzést for session_id() // a session_start() ) függvény meghívása után a deleteSession() ( if (session_id()) ( // Ha van aktív munkamenet, törölje a session cookie-kat, setcookie(session_name(), session_id(), time() )-60*60*24); // és semmisítse meg a session_unset( ); session_destroy(); ) )

Megjegyzés: Feltételezzük, hogy az olvasó alapvető ismeretekkel rendelkezik a PHP munkamenetekről, ezért itt nem térünk ki a session_start() és session_destroy() függvények működési elvére. A bejelentkezési űrlap elrendezésének és a felhasználói hitelesítésnek a feladatai nem kapcsolódnak a cikk témájához, ezért ezeket is mellőzzük. Hadd emlékeztesselek arra, hogy a felhasználó azonosításához minden további kérésben a sikeres bejelentkezés pillanatában el kell tárolnunk a felhasználói azonosítót egy munkamenet változóban (például userid néven), amely minden további kérésben elérhető lesz az ülés élete. Szükséges továbbá a startSession() függvényünk eredményének feldolgozását megvalósítani. Ha a függvény FALSE-t ad vissza, jelenítse meg a bejelentkezési űrlapot a böngészőben. Ha a függvény TRUE-t adott vissza, és létezik a jogosult felhasználó azonosítóját (esetünkben - userid) tartalmazó munkamenet-változó - jelenítse meg a jogosult felhasználó oldalát (a hibakezelésről bővebben a 2013-06-án kelt kiegészítésben olvashat). 07 a munkamenet változóiról szóló részben).

Eddig minden világos. A kérdések akkor kezdődnek, amikor be kell vezetnie a felhasználói inaktivitás vezérlését (munkamenet időtúllépés), lehetővé kell tennie több felhasználó egyidejű munkáját egy böngészőben, és meg kell védenie a munkameneteket az illetéktelen használattól. Erről az alábbiakban lesz szó.

Felhasználói inaktivitás szabályozása beépített PHP-eszközökkel Az első kérdés, amely gyakran felmerül a különböző konzolok fejlesztői körében a felhasználók számára, a munkamenet automatikus leállítása a felhasználó inaktivitása esetén. Semmi sem egyszerűbb, mint ezt a PHP beépített képességeivel megtenni. (Ez a lehetőség nem különösebben megbízható vagy rugalmas, de a teljesség kedvéért megfontoljuk).

A startSession() függvény ( // Felhasználó inaktivitási időtúllépése (másodpercben) $sessionLifetime = 300; if (session_id()) true; // A cookie élettartamának beállítása ini_set("session.cookie_lifetime", $sessionLifetime); // Ha a felhasználó inaktivitási időtúllépés be van állítva, állítsa be a munkamenet élettartamát a kiszolgálón // Megjegyzés: Éles kiszolgáló esetén ajánlatos ezeket a paramétereket előre beállítani a php.ini fájlban if ($sessionLifetime) ini_set("session.gc_maxlifetime", $sessionLifetime) ; if (session_start( )) ( setcookie(munkamenet_neve(), session_id(), time()+$sessionLifetime); return true; ) else return false; )

Néhány pontosítás. Mint ismeretes, a PHP a böngésző által a kérés fejlécében elküldött cookie-név alapján határozza meg, hogy melyik munkamenetet kell elindítani. A böngésző viszont megkapja ezt a sütit a szervertől, ahová a session_start() függvény elhelyezi. Ha a böngésző sütije lejárt, azt nem küldi el a kérésben, ami azt jelenti, hogy a PHP nem tudja meghatározni, hogy melyik munkamenetet indítsa el, és ezt új munkamenet létrehozásaként kezeli. A PHP beállítási paramétere session.gc_maxlifetime, amely egyenlő a felhasználói inaktivitási időtúllépésünkkel, beállítja a PHP munkamenet élettartamát, és a szerver vezérli. A munkamenet élettartamának szabályozása a következőképpen működik (itt egy példát tekintünk a munkamenetek ideiglenes fájlokban való tárolására, mint a PHP leggyakoribb és alapértelmezett opciójára).

Új munkamenet létrehozásakor egy sess_ nevű fájl jön létre abban a könyvtárban, amely a session.save_path PHP beállítási paraméterében a munkamenetek tárolására van beállítva, ahol a munkamenet azonosítója. Ezután minden kérésben, egy már létező munkamenet indításakor a PHP frissíti a fájl módosítási idejét. Így minden további kérésben a PHP az aktuális időpont és a munkamenetfájl utolsó módosításának időpontja közötti különbség alapján meg tudja határozni, hogy a munkamenet aktív-e, vagy az élettartama már lejárt. (A régi munkamenet-fájlok törlésének mechanizmusát részletesebben a következő részben tárgyaljuk.)

Megjegyzés: Itt meg kell jegyezni, hogy a session.gc_maxlifetime paraméter egy szerveren belüli összes munkamenetre vonatkozik (pontosabban egy fő PHP folyamaton belül). A gyakorlatban ez azt jelenti, hogy ha több oldal fut a szerveren, és mindegyiknek megvan a saját felhasználói inaktivitási időtúllépése, akkor ennek a paraméternek az egyik oldalon történő beállítása más oldalakra vonatkozó beállításához vezet. Ugyanez vonatkozik a megosztott tárhelyre is. A helyzet elkerülése érdekében külön munkamenet-könyvtárakat használnak ugyanazon a kiszolgálón belüli minden egyes helyhez. A sessions könyvtár elérési útja a php.ini beállításfájlban található session.save_path paraméterrel vagy az ini_set() függvény meghívásával történik. Ezt követően az egyes webhelyek munkamenetei külön könyvtárakba kerülnek, és az egyik oldalon beállított session.gc_maxlifetime paraméter csak a munkamenetére lesz érvényes. Ezt az esetet nem fogjuk részletesen megvizsgálni, különösen azért, mert van egy rugalmasabb lehetőségünk a felhasználói inaktivitás figyelésére.

A felhasználói inaktivitás szabályozása munkamenet-változók segítségével Úgy tűnik, hogy az előző opció minden egyszerűsége ellenére (csak néhány további kódsor) mindent megad, amire szükségünk van. De mi van akkor, ha nem minden kérés tekinthető felhasználói tevékenység eredményének? Például egy oldalnak van egy időzítője, amely időnként AJAX kérést küld a kiszolgálótól érkező frissítések fogadására. Egy ilyen kérés nem tekinthető felhasználói tevékenységnek, ami azt jelenti, hogy a munkamenet élettartamának automatikus meghosszabbítása ebben az esetben nem helyes. De tudjuk, hogy a PHP minden alkalommal automatikusan frissíti a session_start() függvény meghívásakor a session fájl módosítási idejét, ami azt jelenti, hogy minden kérés a munkamenet élettartamának meghosszabbodásához vezet, és a felhasználói inaktivitási időtúllépés soha nem következik be. Ezenkívül az előző szakasz utolsó megjegyzése a session.gc_maxlifetime paraméter bonyolultságáról túlságosan zavarónak és egyesek számára nehezen megvalósíthatónak tűnhet.

A probléma megoldása érdekében felhagyunk a beépített PHP-mechanizmusokkal, és számos új munkamenet-változót vezetünk be, amelyek segítségével magunk szabályozhatjuk a felhasználói inaktivitás idejét.

Függvény startSession($isUserActivity=true) ($sessionLifetime = 300; if (session_id()) true értéket ad vissza; // A cookie élettartamának beállítása a böngésző bezárása előtt (a szerver oldalon mindent szabályozunk) ini_set("session. cookie_lifetime", 0) ; if (! session_start()) visszatér false; $t = time(); if ($sessionLifetime) ( // Ha a felhasználói inaktivitási időtúllépés be van állítva, // ellenőrizze az utolsó felhasználói tevékenység óta eltelt időt // (utolsó kérés időpontja, amikor a lastactivity munkamenet változó frissítve lett) if (isset($_SESSION["lastactivity"]) && $t-$_SESSION["lastactivity"] >= $sessionLifetime) ( // Ha az idő eltelt azóta a felhasználó utolsó tevékenysége, // nagyobb, mint az inaktivitási időtúllépés, ami azt jelenti, hogy a munkamenet lejárt, és meg kell szakítania a munkamenetet deleteSession(); return false; ) else ( // Ha az időtúllépés még nem következett be, // és ha a kérés felhasználói tevékenység eredményeként érkezett, // frissítse a lastactivity változót az aktuális egyszer értékével, // ezáltal meghosszabbítja a munkamenet időtartamát egy újabb sessionLifetime másodperccel if ($isUserActivity) $_SESSION["lastactivity"] = $t; ) ) true return; )

Foglaljuk össze. Minden kérésnél ellenőrizzük, hogy az utolsó felhasználói tevékenység óta az aktuális pillanatig elérte-e az időtúllépést, és ha elérte, megsemmisítjük a munkamenetet és megszakítjuk a funkció végrehajtását, visszaküldve FALSE-t. Ha nem érte el az időtúllépés, és a $isUserActivity paraméter TRUE értékű átadásra kerül a függvénynek, frissítjük a felhasználó utolsó tevékenységének időpontját. Csak annyit kell tennünk, hogy a hívó szkriptben meghatározzuk, hogy a kérés felhasználói tevékenység eredménye-e, és ha nem, hívjuk meg a startSession függvényt a $isUserActivity paraméter FALSE értékével.

Kiegészítés 2013-06-07 A sessionStart() függvény eredményének feldolgozása

A megjegyzések rámutattak arra, hogy a FALSE visszaküldése nem ad teljes megértést a hiba okáról, és ez teljesen korrekt. Részletes hibakezelést itt nem publikáltam (a cikk terjedelme már elég nagy), mivel ez nem kapcsolódik közvetlenül a cikk témájához. De figyelembe véve a megjegyzéseket, pontosítok.

Amint látható, a sessionStart függvény két esetben adhat vissza FALSE-t. Vagy a munkamenet nem indítható el néhány belső szerverhiba miatt (például a php.ini helytelen szekcióbeállításai), vagy a munkamenet élettartama lejárt. Az első esetben át kell irányítanunk a felhasználót egy olyan oldalra, amelyen hibaüzenet jelenik meg, amely jelzi, hogy problémák vannak a szerveren, és egy űrlapot kell küldeni a támogatáshoz. A második esetben át kell vinnünk a felhasználót a bejelentkezési űrlapra, és meg kell jelenítenünk benne egy megfelelő üzenetet arról, hogy a munkamenet lejárt. Ehhez hibakódokat kell beírnunk, és a FALSE helyett a megfelelő kódot kell visszaadnunk, és a hívási metódusban ellenőrizni kell, és ennek megfelelően kell eljárni.

Ha a felhasználó inaktivitási időtúllépése lejárt, akkor is megsemmisül az első alkalommal, amikor a kiszolgálón egy munkamenet még mindig létezik. És ez attól függetlenül megtörténik, hogy milyen munkamenet-élettartam van beállítva a globális PHP beállításokban.

Megjegyzés: Mi történik, ha a böngészőt bezárják, és a munkamenetnév-cookie automatikusan megsemmisül? A böngésző következő megnyitásakor a szerverhez intézett kérés nem fogja tartalmazni a session cookie-t, és a szerver nem tudja megnyitni a munkamenetet és ellenőrizni a felhasználó inaktivitási időtúllépését. Számunkra ez egy új munkamenet létrehozásának felel meg, és semmilyen módon nem befolyásolja a funkcionalitást vagy a biztonságot. Felmerül azonban egy jogos kérdés – ki fogja akkor megsemmisíteni a régi munkamenetet, ha eddig az időkorlát lejárta után semmisítettük meg? Vagy most örökre a sessions könyvtárban fog lógni? A PHP régi szekcióinak megtisztításához létezik egy szemétgyűjtés nevű mechanizmus. A kiszolgálóhoz intézett következő kérés időpontjában fut, és a munkamenetfájlok utolsó módosítási dátuma alapján törli az összes régi munkamenetet. De a szemétgyűjtési mechanizmus nem indul el minden, a szerverhez intézett kéréssel. Az indítás gyakoriságát (vagy inkább valószínűségét) a session.gc_probability és a session.gc_divisor két beállítási paraméter határozza meg. Az első paraméter másodikkal való elosztásának eredménye a szemétgyűjtő mechanizmus elindításának valószínűsége. Így ahhoz, hogy a munkamenet-törlési mechanizmus a szerverhez intézett minden egyes kéréssel elinduljon, ezeket a paramétereket egyenlő értékekre kell beállítani, például „1”. Ez a megközelítés tiszta munkamenet-könyvtárat garantál, de nyilvánvalóan túl drága a szerver számára. Ezért éles rendszereken a session.gc_divisor alapértelmezett értéke 1000, ami azt jelenti, hogy a szemétgyűjtő mechanizmus 1/1000 valószínűséggel fog futni. Ha ezekkel a beállításokkal kísérletezik a php.ini fájlban, észreveheti, hogy a fent leírt esetben, amikor a böngésző bezárja és törli az összes cookie-ját, egy ideig még maradnak régi munkamenetek a sessions könyvtárban. De ettől nem kell aggódnia, mert... mint már említettük, ez semmilyen módon nem befolyásolja a mechanizmusunk biztonságát.

Frissítés 2013-06-07-től A szkriptek lefagyásának megakadályozása a munkamenet-fájlok zárolása miatt

A hozzászólások felvetették, hogy az egyidejűleg futó szkriptek lefagynak a munkamenetfájl blokkolása miatt (a legszembetűnőbb lehetőség a long poll).

Először is megjegyzem, hogy ez a probléma nem közvetlenül a szerver terhelésétől vagy a felhasználók számától függ. Természetesen minél több a kérés, annál lassabban futnak le a szkriptek. De ez közvetett függőség. A probléma csak egy munkameneten belül jelentkezik, amikor a szerver több kérést is kap egy felhasználó nevében (például az egyik hosszú lekérdezés, a többi normál kérés). Minden kérés ugyanahhoz a munkamenet-fájlhoz próbál hozzáférni, és ha az előző kérés nem oldotta fel a fájl zárolását, akkor a következő lefagy és vár.

A munkamenetfájlok zárolásának minimálisra csökkentése érdekében erősen ajánlott a munkamenet lezárása a session_write_close() függvény azonnali meghívásával, miután a munkamenet-változókkal végzett műveletek befejeződtek. A gyakorlatban ez azt jelenti, hogy nem szabad mindent munkamenet-változókban tárolni, és a szkript végrehajtása során hozzáférni hozzájuk. És ha néhány munkaadatot munkamenetváltozókban kell tárolnia, akkor azonnal olvassa el őket a munkamenet indulásakor, mentse el őket helyi változókba későbbi használatra, és zárja be a munkamenetet (ez azt jelenti, hogy a session_write_close függvénnyel zárja be a munkamenetet, és ne semmisítse meg a session_destroy használatával ).

Példánkban ez azt jelenti, hogy egy munkamenet megnyitása, élettartamának és jogosult felhasználó meglétének ellenőrzése után azonnal be kell olvasnunk és el kell mentenünk az alkalmazás által igényelt összes további munkamenet-változót (ha van ilyen), majd a munkamenetet be kell zárnunk a session_write_close(), és folytassa a szkript végrehajtását, legyen az egy hosszú lekérdezés vagy egy szokásos kérés.

A munkamenetek védelme a jogosulatlan használattól Képzeljünk el egy helyzetet. Egyik felhasználója kap egy trójai programot, amely kirabolja a böngésző cookie-jait (amelyekben a munkamenetünket tároljuk), és elküldi a megadott e-mail címre. A támadó megszerzi a cookie-t, és arra használja fel, hogy meghamisítson egy kérést a jogosult felhasználónk nevében. A szerver sikeresen elfogadja és feldolgozza ezt a kérést, mintha egy jogosult felhasználótól származna. Ha az IP-cím további ellenőrzését nem hajtják végre, egy ilyen támadás a felhasználó fiókjának sikeres feltöréséhez vezet, az ebből eredő összes következménnyel együtt.

Miért volt ez lehetséges? Nyilvánvalóan azért, mert a név és a munkamenet azonosító mindig ugyanaz a munkamenet teljes élettartama alatt, és ha megkapja ezeket az adatokat, akkor könnyen küldhet kéréseket egy másik felhasználó nevében (természetesen ennek a munkamenetnek az élettartamán belül). Lehet, hogy nem ez a legelterjedtebb támadás, de elméletileg eléggé kivitelezhetőnek tűnik, főleg, ha figyelembe vesszük, hogy egy ilyen trójainak még adminisztrátori jogokra sincs szüksége ahhoz, hogy kirabolja a felhasználó böngésző cookie-jait.

Hogyan védekezhet az ilyen jellegű támadások ellen? Ismét nyilvánvalóan a munkamenet-azonosító élettartamának korlátozásával és az azonosító ugyanazon munkameneten belüli időszakos megváltoztatásával. A munkamenet nevét úgy is megváltoztathatjuk, hogy a régit teljesen töröljük, és új munkamenetet hozunk létre, ebbe átmásoljuk a régi munkamenet összes változóját. Ez azonban nem befolyásolja a megközelítés lényegét, ezért az egyszerűség kedvéért csak a munkamenet-azonosítóra szorítkozunk.

Nyilvánvaló, hogy minél rövidebb a munkamenet-azonosító élettartama, annál kevesebb időre van szüksége a támadónak ahhoz, hogy cookie-kat szerezzen be és használjon felhasználói kérés hamisításához. Ideális esetben minden kéréshez új azonosítót kell használni, ami minimálisra csökkenti annak lehetőségét, hogy valaki más munkamenetét használja. De figyelembe vesszük azt az általános esetet, amikor a munkamenet-azonosító regenerálási ideje tetszőlegesen van beállítva.

(A kód már tárgyalt részét kihagyjuk).

Függvény startSession($isUserActivity=true) (// Munkamenet azonosító élettartama $idLifetime = 60; ... if ($idLifetime) ( // Ha a munkamenet azonosító élettartama be van állítva, // ellenőrizze a munkamenet kezdete óta eltelt időt létrehozott vagy az utolsó újragenerálás // (az utolsó kérés időpontja, amikor a munkamenet változó kezdő időpontja frissítve volt) if (isset($_SESSION["starttime"])) (if ($t-$_SESSION["starttime"] >= $ idLifetime) ( // A munkamenet azonosítójának lejártának ideje // Új azonosító generálása session_regenerate_id(true); $_SESSION["starttime"] = $t; ) ) else ( // Ide kerülünk, ha a munkamenet éppen létrehozva // Állítsa be a munkamenet azonosító generálásának idejét a jelenlegi időpontra $_SESSION["starttime"] = $t; ) ) return true; )

Tehát egy új munkamenet létrehozásakor (amikor a felhasználó sikeresen bejelentkezik) a munkamenet azonosítójának utolsó generációjának idejét tároló session starttime változót az aktuális szerveridővel megegyező értékre állítjuk. Ezután minden kérésnél ellenőrizzük, hogy elég idő (idLifetime) telt-e el az azonosító utolsó generációja óta, és ha igen, akkor újat generálunk. Így ha az azonosító beállított élettartama alatt annak a támadónak, aki megkapta a jogosult felhasználó cookie-ját, nincs ideje használni azt, akkor a hamis kérést a szerver jogosulatlannak tekinti, és a támadó a bejelentkezési oldalra kerül. .

Megjegyzés: Az új session ID a session_regenerate_id() függvény meghívásakor kerül be a böngésző cookie-jába, amely a session_start() függvényhez hasonlóan elküldi az új cookie-t, így nem kell magunknak frissítenünk a cookie-t.

Ha a lehető legbiztonságosabbá akarjuk tenni a munkameneteinket, elég az azonosító élettartamát egyre állítani, vagy akár eltávolítani a session_regenerate_id() függvényt a zárójelekből, és eltávolítani az összes ellenőrzést, ami az azonosító újragenerálásához vezet minden esetben. kérés. (Nem teszteltem ennek a megközelítésnek a teljesítményre gyakorolt ​​hatását, és csak azt tudom mondani, hogy a session_regenerate_id(true) függvény lényegében csak 4 műveletet hajt végre: új azonosító generálása, fejléc létrehozása a session cookie-val, a régi törlése és létrehozása. egy új munkamenet fájl).

Lírai kitérő: Ha a trójai olyan okosnak bizonyul, hogy nem küld cookie-kat a támadónak, hanem azonnal megszervezi egy előre elkészített hamis kérés elküldését a cookie beérkezése után, akkor a fent leírt módszer nagy valószínűséggel nem lesz képes védeni kell egy ilyen támadás ellen, mert a süti fogadása és a hamis kérés elküldése között gyakorlatilag nem lesz különbség, és nagy a valószínűsége annak, hogy ebben a pillanatban a munkamenet azonosító nem generálódik újra.

Egyidejű munkavégzés lehetősége egy böngészőben több felhasználó nevében Az utolsó feladat, amit szeretnék figyelembe venni, az egy böngészőben több felhasználó egyidejű munkavégzése. Ez a funkció különösen a tesztelési szakaszban hasznos, amikor a felhasználók egyidejű munkáját kell emulálni, és ezt célszerű kedvenc böngészőjében megtenni, ahelyett, hogy a teljes elérhető arzenált használná, vagy inkognitó módban nyitná meg a böngésző több példányát. .

Korábbi példáinkban nem adtunk meg kifejezetten munkamenetnevet, ezért az alapértelmezett PHP nevet (PHPSESSID) használtuk. Ez azt jelenti, hogy az általunk eddig létrehozott összes munkamenet sütiket küldött a böngészőnek PHPSESSID néven. Nyilvánvaló, hogy ha a cookie neve mindig ugyanaz, akkor nincs lehetőség két azonos nevű munkamenet megszervezésére ugyanazon a böngészőn belül. De ha minden felhasználóhoz saját munkamenetnevet használnánk, a probléma megoldódna. Tegyük úgy.

A startSession($isUserActivity=true, $prefix=null) függvény (... if (session_id()) true értékkel tér vissza; // Ha a felhasználói előtag átadásra kerül a paraméterekben, // állítson be egyedi munkamenetnevet, amely tartalmazza ezt előtag, // egyébként az összes felhasználó közös neve beállítása (például MYPROJECT) session_name("MYPROJECT".($prefix ? "_".$prefix: "")); ini_set("session.cookie_lifetime", 0); if (! session_start()) hamis értéket ad vissza; ... )

Most már csak meg kell győződni arról, hogy a hívó szkript minden felhasználó számára egyedi előtagot ad át a startSession() függvénynek. Ez megtehető például egy előtag átadásával az egyes kérések GET/POST paraméterei között, vagy egy további cookie-n keresztül.

Összegzés Befejezésül megadom a PHP szekciókkal való munkavégzéshez szükséges függvényeink teljes végleges kódját, beleértve a fent tárgyalt összes feladatot.

Függvény startSession($isUserActivity=true, $prefix=null) ( $sessionLifetime = 300; $idLifetime = 60; if (session_id()) true; session_name("MYPROJECT".($prefix ? "_".$prefix): "")); ini_set("session.cookie_lifetime", 0); if (! session_start()) return false; $t = time(); if ($sessionLifetime) ( if (isset($_SESSION["lastactivity"] ) && $t-$_SESSION["lastactivity"] >= $sessionLifetime) ( deleteSession(); return false; ) else ( if ($isUserActivity) $_SESSION["lastactivity"] = $t; ) ) if ($idLifetime ) ( if (isset($_SESSION["kezdési időpont"])) (if ($t-$_SESSION["kezdési időpont"] >= $idLifetime) ( session_regenerate_id(true); $_SESSION["kezdési időpont"] = $t; ) ) else ( $_SESSION["kezdési időpont"] = $t; ) ) return true; ) function deleteSession() ( if (session_id()) ( session_unset(); setcookie(session_name(), session_id(), time() -60*60*24); session_destroy(); ) )

Remélem, ez a cikk időt takarít meg azoknak, akik még soha nem ástak bele mélyen a munkamenet-mechanizmusba, és kellő betekintést nyújt ebbe a mechanizmusba azok számára, akik most kezdik ismerkedni a PHP-vel.

Felhasználónévre és jelszóra van szüksége?

A cikkek online beküldéséhez és a beküldött cikkek állapotának ellenőrzéséhez regisztrálnia kell, és be kell jelentkeznie fiókjába.

Ellenőrző lista a cikk benyújtására való előkészítéséhez

A cikkbeküldési folyamat részeként a szerzőknek ellenőrizniük kell, hogy cikkük megfelel-e az alábbi pontoknak; a cikkeket visszaküldhetjük a szerzőknek, ha nem felelnek meg ezeknek a követelményeknek.

A cikk a követelményeknek megfelelően készült

A szerzői jog átruházásának feltételei

A szerzők fenntartják a mű szerzői jogait, és a munkával együtt megadják a folyóirat első megjelenési jogát, miközben a Creative Commons Attribution License feltételei szerint licencet adnak, amely lehetővé teszi mások számára, hogy ezt a művet a mű szerzőjének kötelező feltüntetésével és egy linkkel terjeszthessék. a folyóirat eredeti publikációjához.

Adatvédelmi nyilatkozat

A magazin weboldalán megadott neveket és e-mail címeket kizárólag a jelen folyóirat által meghatározott célokra használjuk fel, és nem használjuk fel semmilyen más célra, illetve nem adjuk át más személynek vagy szervezetnek.

A rendszerbe történő regisztráció előtt a felhasználó elfogadja a személyes adatok kezelésére és tárolására vonatkozó szabályzatot.

Szerző fizetések

1500 karakter szóközökkel: 300,00 (RUB)

1 oldal kézirat kiadása (1500 karakter) - 300 rubel. A grafikai anyagokat / táblázatokat külön kell fizetni - 50 rubel / 1 darab. A szerző másolatát, beleértve az Oroszországon belüli szállítást is, a szerző kérésére fizetik - 400 rubelt. Szállítás külföldre - 800 rubel. Az anyag közzétételre történő elfogadásáról szóló igazolás küldésének költsége 150 rubel.

A kísérő információk (a szerzők teljes neve, munkahelye; cím; absztrakt; kulcsszavak) fordítása angolra 0,5 rubel karakterenként, szóközökkel együtt.

Figyelem! Azok a szerzők (a tudomány jelöltjei és doktorai), akik az elibrary.ru szerint legalább 300 hivatkozással rendelkeznek (az önhivatkozások aránya nem haladhatja meg a 30%-ot), ingyenesen közzéteszik. Ha jogosult az ingyenes publikálásra, az anyag beküldésekor a megjegyzés rovatban tüntesse fel a könyvtári profiljára mutató hivatkozást az idézetek számával. Az átvétel szállítási költsége külön fizetendő.

A webhely biztonsága a munkamenet-kezelésen alapul. Amikor a felhasználó biztonságos webhelyhez csatlakozik, hitelesítő adatokat ad meg, jellemzően felhasználónév és jelszó formájában. A webszervernek fogalma sincs, melyik felhasználó van már bejelentkezve, vagy hogyan navigál oldalról oldalra. A munkamenet-mechanizmus megakadályozza, hogy a felhasználóknak minden alkalommal jelszót kelljen megadniuk, amikor új műveletet szeretnének végrehajtani vagy új oldalra akarnak lépni.

Lényegében a munkamenet-kezelés biztosítja, hogy az éppen csatlakoztatott felhasználó legyen az, akit hitelesítettek. Sajnos azonban a munkamenetek a hackerek nyilvánvaló célpontjává váltak, mivel hitelesítés nélkül is hozzáférést tudnak biztosítani egy webszerverhez.

A felhasználó hitelesítése után a webszerver munkamenet-azonosítóval látja el. Ezt az azonosítót a böngésző tárolja, és minden alkalommal helyettesíti, amikor hitelesítésre van szükség. Ez lehetővé teszi az ismételt bejelentkezési/jelszóbeviteli folyamatok elkerülését. Mindez a háttérben történik, és nem okoz kényelmetlenséget a felhasználónak. Képzelje el, ha minden alkalommal megadná felhasználónevét és jelszavát, amikor új oldalt nézett meg!

Ebben a cikkben megpróbálom felvázolni az általam ismert összes módot a munkamenet-azonosító védelmére a PHP-ben.

Cookie-k használata Alapértelmezés szerint minden munkamenet-információ, beleértve az azonosítót is, egy cookie-ba kerül. De ez nem mindig történik meg. Egyes felhasználók letiltják a cookie-kat a böngészőjükben. Ebben az esetben a böngésző átadja a munkamenet-azonosítót az URL-ben.

Itt az azonosító egyértelmű szövegben kerül továbbításra, ellentétben a cookie-n keresztüli munkamenettel, amikor az információ el van rejtve a HTTP fejlécben. Ez ellen a legegyszerűbb védekezési mód az lenne, ha letiltjuk a munkamenet-azonosítónak a címsoron keresztüli továbbítását. Ezt úgy teheti meg, hogy beírja a következőket az Apache szerver .htaccess konfigurációs fájljába:

Php_flag session.use_only_cookies bekapcsolva

Titkosítás használata Ha webhelyének érzékeny információkat, például hitelkártyaszámokat kell feldolgoznia (üdvözöljük a Sonytól), SSL3.0 vagy TSL1.0 titkosítást kell használnia. Ehhez a cookie beállításakor meg kell adni a true paramétert a biztonságos paraméternél.

Ha a munkamenet jelszavát a $_SESSION változóban tárolja (még mindig jobb az sql-t használni), akkor nem szabad tiszta szövegben tárolnia.

If ($_SESSION["jelszó"] == $felhasználói jelszó) ( // kód )

A fenti kód nem biztonságos, mert a jelszó egyszerű szövegként van tárolva egy munkamenet-változóban. Ehelyett használjon md5 titkosítást, valami ilyesmit:

If ($_SESSION["md5password"] == md5($userpass)) ( // kód )

Böngésző ellenőrzése Annak elkerülése érdekében, hogy egy munkamenetet más böngészőből (számítógépről) használjon, be kell jelölnie a user-agent HTTP fejléc mezőjét:

Session_start(); if (isset($_SESSION["HTTP_USER_AGENT"])) (if ($_SESSION["HTTP_USER_AGENT"] != md5($_SERVER["HTTP_USER_AGENT"])) ( // kód ) ) else ( $_SESSION["HTTP_USER_AGENT" ] = md5($_SZERVER["HTTP_USER_AGENT"]); )

Munkamenet lejárata Korlátozza a munkamenet élettartamát, valamint a cookie-k lejárati idejét. Alapértelmezés szerint a munkamenet időtartama 1440 másodperc. Ezt az értéket a php.ini és a .htaccess fájlokkal módosíthatja. Példa a .htaccess fájlra:

# A munkamenet élettartama másodpercben
php_value session.gc_maxlifetime 3600
# A süti élettartama másodpercben
php_value session.cookie_lifetime 3600

Kötés IP-cím alapján Bizonyos helyzetekben (nem mindig) IP-cím alapján kell kötni. Főleg, ha a felhasználók száma korlátozott és statikus IP-vel rendelkeznek. Az ellenőrzés történhet az engedélyezett IP-címek listája alapján,

Include("ip_list.php"); //$ip_white_list = tömb ("admin1" => "111.222.333.444", "admin2" => "555.666.777.888"); if(!empty(array_search($_SERVER["TÁVOLI_CÍM"],$ip_white_list))) ( header("Hely: admin.php"); ) else ( echo "A CESSESS DENY!"; )

Vagy IP-cím alapján minden kérésnél (csak statikus IP esetén):

If(isset($_SESSION["ip"]) és $_SESSION["ip"] == $_SERVER["REMOTE_ADDR"]) ( header("Hely: admin.php"); ) else ( session_unset(); $ _SESSION["ip"] = $_SZERVER["REMOTE_ADDR"]; )

Tudnia kell, hogy a hackelést nem lehet teljesen elkerülni. Ezt a feltörést csak bármilyen ismert eszközzel lehet a lehető legnehezebbé tenni. Nem szabad azonban megfeledkezni a legális felhasználóiról sem, hogy ne bonyolítsák az életüket egy ilyen védelemmel.

Ez a cikk 2009-ben íródott, és továbbra is az egyik legnépszerűbb bejegyzésünk. Ha szeretne többet megtudni a PHP-ről és a MySQL-ről, ez nagy érdeklődésre tarthat számot.

MEGJEGYZÉS: Ezt a cikket frissen frissítettük, hogy a PHP 4.2-es vagy újabb verzióján működjön!

Nemrég volt alkalmam egy kisebb projekten dolgozni egy csoport emberrel. Már korán eldöntöttük, hogy az e-mail önmagában nem lesz elég ahhoz, hogy mindenkit a pályán tartsunk, ezért megbíztak, hogy készítsek egy kis webhelyet a projekthez. Tartalmazna egy egyszerű üzenőfalat, egy helyet, ahová dokumentumokat és egyéb fájlokat tölthetnénk fel a csapat többi tagja számára, valamint a különböző csapattagok elérhetőségeit.

Ahhoz, hogy sok ilyen funkció működjön, tudtam, hogy a felhasználóknak be kell jelentkezniük, mielőtt hozzáférnének a webhely megfelelő részeihez. Olyan rendszerre volt szükségem, amely lehetővé teszi a felhasználók számára, hogy regisztráljanak egy felhasználói azonosítót, hogy hozzáférhessenek az oldalhoz, majd azonnal használhassák az azonosítót az én beavatkozásom nélkül.

Ebben a cikkben áttekintést adok az általam kifejlesztett rendszerről, az első felében a felhasználói regisztrációs folyamattól kezdve. A második felében magára az oldalra fogok összpontosítani, arra, hogy miként követeli meg a felhasználóktól a bejelentkezést, és hogyan tartja fenn ezt a bejelentkezett állapotot a látogatásuk során. Különös figyelmet fogok fordítani a PHP munkamenet-kezelési funkcióinak használatára. A végére rendelkeznie kell minden olyan információval, amelyre szüksége van egy hasonló rendszer megvalósításához.

Ebben a cikkben azt feltételezem, hogy alapvető ismeretekkel rendelkezik a PHP nyelvben, az űrlapok használatában a PHP-szkriptbe való információküldéshez, és arról, hogy a PHP hogyan használható a MySQL adatbázissal való interakcióra. Ha ezek közül bármelyik idegen számodra, kezdd azzal, hogy elolvasod előző cikkem, .

Első rész: A regisztrációs folyamat A regisztrációs űrlap

A regisztrációs folyamat természetes helye egy olyan webhely létrehozásának, amelyhez a felhasználóknak regisztrálniuk kell. Ahogy az várható volt, egy egyszerű webalapú űrlap megteszi a trükköt. Így fog kinézni:

És itt van az űrlap kódja:




Új felhasználói regisztráció



Új felhasználó regisztrációs űrlapja

* mezőt kötelező kitölteni


Miután a cél már világos, végigvezetem az accesscontrol.php kódon. Kezdje a két praktikus belefoglaló fájl hozzáadásával: