Mbrojtja e ID-së së sesionit në PHP. Grackat e përdorimit të sesioneve në PHP Kalimi i një vlere ose grupi duke përdorur një sesion PHP

Përshëndetje, komunitet i dashur.

Para së gjithash, dua t'ju falënderoj për një burim shumë të dobishëm. Më shumë se një herë kam gjetur shumë ide interesante dhe këshilla praktike këtu.

Qëllimi i këtij artikulli është të nxjerrë në pah kurthet e përdorimit të seancave në PHP. Sigurisht, ka dokumentacion PHP dhe shumë shembuj, dhe ky artikull nuk synon të jetë një udhëzues i plotë. Është krijuar për të zbuluar disa nga nuancat e punës me sesione dhe për të mbrojtur zhvilluesit nga humbja e panevojshme e kohës.

Shembulli më i zakonshëm i përdorimit të sesioneve është, natyrisht, autorizimi i përdoruesit. Le të fillojmë me zbatimin më themelor, në mënyrë që ta zhvillojmë gradualisht ndërsa lindin detyra të reja.

(Për të kursyer hapësirë ​​dhe kohë, ne do t'i kufizojmë shembujt tanë vetëm në vetë funksionet e sesionit, në vend që të ndërtojmë këtu një aplikacion testimi të plotë me një hierarki të bukur të klasës, trajtim gjithëpërfshirës të gabimeve dhe gjëra të tjera të mira).

Funksioni startSession() ( // Nëse sesioni ka filluar tashmë, ndaloni ekzekutimin dhe kthejeni TRUE // (parametri session.auto_start në skedarin e cilësimeve php.ini duhet të çaktivizohet - vlera e paracaktuar) nëse (session_id()) kthehet e vërtetë; përndryshe ktheje session_start(); // Shënim: Përpara versionit 5.3.0, funksioni session_start() u kthye TRUE edhe nëse ndodhi një gabim. // Nëse jeni duke përdorur një version para 5.3.0, kryeni një kontroll shtesë për session_id() // pas thirrjes sesion_start() ) funksion shkatërronSession() ( if (session_id()) ( // Nëse ka një seancë aktive, fshini kukit e sesionit, setcookie(sesion_name(), session_id(), time( )-60*60*24); // dhe shkatërro seancën session_unset(); session_destroy();) )

Shënim: Supozohet se lexuesi ka njohuri bazë për sesionet PHP, kështu që ne nuk do të mbulojmë këtu parimin e funksionimit të funksioneve session_start() dhe session_destroy(). Detyrat e paraqitjes së formularit të hyrjes dhe vërtetimi i përdoruesit nuk lidhen me temën e artikullit, kështu që ne gjithashtu do t'i heqim ato. Më lejoni t'ju kujtoj se për të identifikuar përdoruesin në çdo kërkesë pasuese, në momentin e hyrjes me sukses, duhet të ruajmë identifikuesin e përdoruesit në një variabël sesioni (për shembull, me emrin userid), i cili do të jetë i disponueshëm në të gjitha kërkesat pasuese brenda jeta e seancës. Është gjithashtu e nevojshme të zbatohet përpunimi i rezultatit të funksionit tonë startSession(). Nëse funksioni kthehet FALSE, shfaqni formularin e hyrjes në shfletues. Nëse funksioni u kthye TRUE, dhe një variabël sesioni që përmban identifikuesin e përdoruesit të autorizuar (në rastin tonë - userid), ekziston - shfaqni faqen e përdoruesit të autorizuar (për më shumë informacion rreth trajtimit të gabimeve, shihni shtimin e datës 2013-06- 07 në seksionin mbi variablat e sesionit).

Deri këtu gjithçka është e qartë. Pyetjet fillojnë kur ju duhet të zbatoni kontrollin e pasivitetit të përdoruesit (përfundimi i sesionit), të mundësoni përdorues të shumtë të punojnë njëkohësisht në një shfletues dhe gjithashtu të mbroni seancat nga përdorimi i paautorizuar. Kjo do të diskutohet më poshtë.

Kontrolli i pasivitetit të përdoruesit duke përdorur mjete të integruara PHP Pyetja e parë që shpesh lind midis zhvilluesve të konzollave të ndryshme për përdoruesit është përfundimi automatik i sesionit në rast të pasivitetit nga ana e përdoruesit. Nuk ka asgjë më të lehtë sesa ta bëni këtë duke përdorur aftësitë e integruara të PHP. (Ky opsion nuk është veçanërisht i besueshëm ose fleksibël, por ne do ta konsiderojmë atë për plotësinë).

Funksioni startSession() ( // Koha e paaktivitetit të përdoruesit (në sekonda) $sessionLifetime = 300; nëse (session_id()) kthehet e vërtetë; // Cakto jetëgjatësinë e kukive ini_set("session.cookie_lifetime", $sessionLifetime); // Nëse përdoruesi caktohet afati i pasivitetit, caktoni jetëgjatësinë e sesionit në server // Shënim: Për një server prodhimi, rekomandohet të paracaktoni këto parametra në skedarin php.ini nëse ($sessionLifetime) ini_set("session.gc_maxlifetime", $sessionLifetime) ; nëse (session_start( )) (setcookie(sesion_name(), session_id(), time()+$sessionLifetime); kthe e vërtetë; ) tjetër kthe false; )

Disa sqarime. Siç e dini, PHP përcakton se cili sesion duhet të nisë nga emri i cookie-t të dërguar nga shfletuesi në kokën e kërkesës. Shfletuesi, nga ana tjetër, e merr këtë cookie nga serveri, ku funksioni session_start() e vendos atë. Nëse cookie-i i shfletuesit ka skaduar, ai nuk do të dërgohet në kërkesë, që do të thotë se PHP nuk do të jetë në gjendje të përcaktojë se cilin sesion të fillojë dhe do ta trajtojë këtë si krijimi i një sesioni të ri. Parametri i cilësimeve të PHP-së session.gc_maxlifetime, i cili është vendosur i barabartë me kohën tonë të mosaktivitetit të përdoruesit, cakton jetëgjatësinë e një sesioni PHP dhe kontrollohet nga serveri. Kontrolli i jetëgjatësisë së sesionit funksionon si më poshtë (këtu konsiderojmë një shembull të ruajtjes së sesioneve në skedarë të përkohshëm si opsioni më i zakonshëm dhe i paracaktuar në PHP).

Kur krijohet një sesion i ri, një skedar me emrin sess_ krijohet në drejtorinë e vendosur si direktori për ruajtjen e sesioneve në parametrin e cilësimeve PHP session.save_path, ku është identifikuesi i sesionit. Më pas, në çdo kërkesë, në momentin e nisjes së një sesioni tashmë ekzistues, PHP përditëson kohën e modifikimit të këtij skedari. Kështu, në çdo kërkesë pasuese, PHP, nga diferenca midis kohës aktuale dhe kohës së modifikimit të fundit të skedarit të sesionit, mund të përcaktojë nëse sesioni është aktiv ose kohëzgjatja e tij tashmë ka skaduar. (Mekanizmi për fshirjen e skedarëve të vjetër të sesionit diskutohet më në detaje në seksionin vijues.)

Shënim: Duhet të theksohet këtu se parametri session.gc_maxlifetime zbatohet për të gjitha sesionet brenda një serveri (më saktë, brenda një procesi kryesor PHP). Në praktikë, kjo do të thotë që nëse disa sajte po funksionojnë në server dhe secila prej tyre ka afatin e vet të mosaktivitetit të përdoruesit, atëherë vendosja e këtij parametri në një nga faqet do të çojë në vendosjen e tij për faqet e tjera. E njëjta gjë vlen edhe për pritjen e përbashkët. Për të shmangur këtë situatë, drejtoritë e veçanta të sesioneve përdoren për çdo sajt brenda të njëjtit server. Vendosja e shtegut për në direktorinë e sesioneve bëhet duke përdorur parametrin session.save_path në skedarin e cilësimeve php.ini, ose duke thirrur funksionin ini_set(). Pas kësaj, sesionet e çdo sajti do të ruhen në drejtori të veçanta dhe parametri session.gc_maxlifetime i vendosur në një nga sajtet do të jetë i vlefshëm vetëm për sesionin e tij. Ne nuk do ta shqyrtojmë këtë rast në detaje, veçanërisht pasi kemi një opsion më fleksibël për monitorimin e pasivitetit të përdoruesit.

Kontrolli i pasivitetit të përdoruesit duke përdorur variablat e sesionit Duket se opsioni i mëparshëm, me gjithë thjeshtësinë e tij (vetëm disa rreshta shtesë kodi), jep gjithçka që na nevojitet. Por, çka nëse jo çdo kërkesë mund të konsiderohet si rezultat i aktivitetit të përdoruesit? Për shembull, një faqe ka një kohëmatës që bën periodikisht një kërkesë AJAX për të marrë përditësime nga serveri. Një kërkesë e tillë nuk mund të konsiderohet si aktivitet i përdoruesit, që do të thotë se zgjatja automatike e jetëgjatësisë së sesionit nuk është e saktë në këtë rast. Por ne e dimë se PHP përditëson automatikisht kohën e modifikimit të skedarit të sesionit sa herë që thirret funksioni session_start(), që do të thotë se çdo kërkesë do të çojë në një zgjatje të jetëgjatësisë së sesionit dhe koha e mosaktivitetit të përdoruesit nuk do të ndodhë kurrë. Për më tepër, shënimi i fundit nga seksioni i mëparshëm në lidhje me ndërlikimet e parametrit sesion.gc_maxlifetime mund të duket shumë konfuz dhe i vështirë për t'u zbatuar për disa.

Për të zgjidhur këtë problem, ne do të braktisim përdorimin e mekanizmave të integruar PHP dhe do të prezantojmë disa variabla të reja të sesionit që do të na lejojnë të kontrollojmë vetë kohën e pasivitetit të përdoruesit.

Funksioni startSession($isUserActivity=true) ($sessionLifetime = 300; nëse (session_id()) kthehet true; // Cakto jetëgjatësinë e cookie-t përpara mbylljes së shfletuesit (ne do të kontrollojmë gjithçka në anën e serverit) ini_set("sesion. cookie_lifetime", 0) ; nëse (! session_start()) kthen false; $t = time(); nëse ($sessionLifetime) ( // Nëse afati i mosaktivitetit të përdoruesit është caktuar, // kontrolloni kohën e kaluar që nga aktiviteti i fundit i përdoruesit // (koha e kërkesës së fundit kur u përditësua ndryshorja e sesionit të aktivitetit të fundit) nëse (isset($_SESSION["lastactivity"]) && $t-$_SESSION["lastactivity"] >= $sessionLifetime) ( // Nëse koha ka kaluar që nga ajo kohë aktiviteti i fundit i përdoruesit, / / ​​është më i madh se koha e paaktivitetit, që do të thotë se sesioni ka skaduar dhe ju duhet të përfundoni seancën shkatërroniSession(); ktheni false; ) tjetër ( // Nëse afati nuk ka ndodhur ende, // dhe nëse kërkesa erdhi si rezultat i aktivitetit të përdoruesit, // përditësoni variablin e fundit të aktivitetit me vlerën e një kohe aktuale, // duke zgjatur kështu kohën e seancës me një seancë tjetër Lifetime sekonda nëse ($isUserActivity) $_SESSION["lastactivity"] = $t; ) ) kthimi i vërtetë; )

Le të përmbledhim. Në çdo kërkesë kontrollojmë nëse është arritur afati që nga aktiviteti i fundit i përdoruesit deri në momentin aktual dhe nëse është arritur, shkatërrojmë seancën dhe ndërpresim ekzekutimin e funksionit, duke e kthyer FALSE. Nëse koha nuk është arritur dhe parametri $isUserActivity me vlerën TRUE i kalohet funksionit, ne përditësojmë kohën e aktivitetit të fundit të përdoruesit. Gjithçka që duhet të bëjmë është të përcaktojmë në skriptin e thirrjes nëse kërkesa është rezultat i aktivitetit të përdoruesit dhe nëse jo, thirrni funksionin startSession me parametrin $isUserActivity të vendosur në FALSE.

Shtim nga 07-06-2013 Përpunimi i rezultatit të funksionit sesionStart()

Komentet theksuan se kthimi FALSE nuk ofron një kuptim të plotë të shkakut të gabimit, dhe kjo është absolutisht e drejtë. Unë nuk publikova trajtimin e detajuar të gabimeve këtu (gjatësia e artikullit tashmë është mjaft e madhe), pasi kjo nuk lidhet drejtpërdrejt me temën e artikullit. Por duke pasur parasysh komentet, unë do të sqaroj.

Siç mund ta shihni, funksioni sesionStart mund të kthejë FALSE në dy raste. Ose sesioni nuk mund të fillonte për shkak të disa gabimeve të brendshme të serverit (për shembull, cilësimet e gabuara të sesionit në php.ini), ose kohëzgjatja e sesionit ka skaduar. Në rastin e parë, duhet ta ridrejtojmë përdoruesin në një faqe me një gabim që thotë se ka probleme në server dhe një formular për të kontaktuar mbështetjen. Në rastin e dytë, ne duhet ta transferojmë përdoruesin në formularin e hyrjes dhe të shfaqim një mesazh përkatës në të që thotë se sesioni ka skaduar. Për ta bërë këtë, ne duhet të fusim kodet e gabimit dhe të kthejmë kodin përkatës në vend të FALSE, dhe në metodën e thirrjes, ta kontrollojmë dhe të veprojmë në përputhje me rrethanat.

Tani, edhe nëse një sesion në server ekziston ende, ai do të shkatërrohet herën e parë kur aksesohet nëse afati i pasivitetit të përdoruesit ka skaduar. Dhe kjo do të ndodhë pavarësisht nga jeta e sesionit të caktuar në cilësimet globale të PHP.

Shënim: Çfarë ndodh nëse shfletuesi mbyllet dhe cookie-ja e emrit të sesionit shkatërrohet automatikisht? Kërkesa për serverin herën tjetër që të hapet shfletuesi nuk do të përmbajë skedarin e sesionit dhe serveri nuk do të jetë në gjendje të hapë sesionin dhe të kontrollojë kohën e paaktivitetit të përdoruesit. Për ne, kjo është e barabartë me krijimin e një sesioni të ri dhe nuk ndikon në asnjë mënyrë funksionalitetin ose sigurinë. Por lind një pyetje e drejtë - kush do ta shkatërrojë më pas seancën e vjetër, nëse deri më tani e kemi shkatërruar pas skadimit të afatit? Apo do të mbetet përgjithmonë në drejtorinë e sesioneve? Për të pastruar seancat e vjetra në PHP, ekziston një mekanizëm i quajtur mbledhja e mbeturinave. Ai funksionon në momentin e kërkesës së radhës në server dhe pastron të gjitha seancat e vjetra bazuar në datën e fundit të modifikimit të skedarëve të sesionit. Por mekanizmi i mbledhjes së mbeturinave nuk fillon me çdo kërkesë drejtuar serverit. Frekuenca (ose më mirë, probabiliteti) i nisjes përcaktohet nga dy parametrat e cilësimeve session.gc_probability dhe session.gc_divisor. Rezultati i ndarjes së parametrit të parë me të dytin është probabiliteti i nisjes së mekanizmit të grumbullimit të plehrave. Kështu, në mënyrë që mekanizmi i pastrimit të sesionit të hapet me çdo kërkesë në server, këto parametra duhet të vendosen në vlera të barabarta, për shembull "1". Kjo qasje garanton një drejtori të pastër të sesioneve, por është padyshim shumë e shtrenjtë për serverin. Prandaj, në sistemet e prodhimit, vlera e paracaktuar e session.gc_divisor është vendosur në 1000, që do të thotë se mekanizmi i grumbullimit të mbeturinave do të funksionojë me një probabilitet prej 1/1000. Nëse eksperimentoni me këto cilësime në skedarin tuaj php.ini, mund të vini re se në rastin e përshkruar më sipër, kur shfletuesi mbyllet dhe pastron të gjitha kukit e tij, ka ende seanca të vjetra të mbetura në drejtorinë e sesioneve për pak kohë. Por kjo nuk duhet t'ju shqetësojë, sepse... siç u tha tashmë, kjo nuk ndikon në asnjë mënyrë në sigurinë e mekanizmit tonë.

Përditësim nga 07-06-2013 Parandalimi i ngrirjes së skripteve për shkak të kyçjes së skedarit të sesionit

Komentet ngritën çështjen e ngrirjes së ekzekutimit të njëkohshëm të skripteve për shkak të bllokimit të skedarit të sesionit (opsioni më i mrekullueshëm është sondazhi i gjatë).

Për të filluar, vërej se ky problem nuk varet drejtpërdrejt nga ngarkesa e serverit ose numri i përdoruesve. Sigurisht, sa më shumë kërkesa, aq më ngadalë ekzekutohen skriptet. Por kjo është një varësi indirekte. Problemi shfaqet vetëm brenda një sesioni, kur serveri merr disa kërkesa në emër të një përdoruesi (për shembull, njëra prej tyre është sondazh i gjatë, dhe pjesa tjetër janë kërkesa të rregullta). Çdo kërkesë përpiqet të hyjë në të njëjtin skedar sesioni, dhe nëse kërkesa e mëparshme nuk e zhbllokoi skedarin, atëherë kërkesa e mëpasshme do të mbetet në pritje.

Për të mbajtur në minimum bllokimin e skedarit të sesionit, rekomandohet fuqimisht mbyllja e seancës duke thirrur funksionin session_write_close() menjëherë pasi të kenë përfunduar të gjitha veprimet me variablat e sesionit. Në praktikë, kjo do të thotë që nuk duhet të ruani gjithçka në variablat e sesionit dhe t'i aksesoni ato gjatë gjithë ekzekutimit të skriptit. Dhe nëse keni nevojë të ruani disa të dhëna pune në variablat e sesionit, atëherë lexoni ato menjëherë kur të fillojë sesioni, ruajini ato në variabla lokale për përdorim të mëvonshëm dhe mbyllni seancën (që do të thotë mbyllja e seancës duke përdorur funksionin session_write_close dhe jo shkatërrimi duke përdorur session_destroy ).

Në shembullin tonë, kjo do të thotë që menjëherë pas hapjes së një sesioni, kontrollimit të jetëgjatësisë së tij dhe ekzistencës së një përdoruesi të autorizuar, ne duhet të lexojmë dhe ruajmë të gjitha variablat shtesë të sesionit të kërkuara nga aplikacioni (nëse ekzistojnë), më pas të mbyllim seancën duke përdorur një telefonatë. për të session_write_close() dhe për të vazhduar ekzekutimin e një skripti, qoftë një sondazh i gjatë apo një kërkesë e rregullt.

Mbrojtja e seancave nga përdorimi i paautorizuar Le të imagjinojmë një situatë. Një nga përdoruesit tuaj merr një trojan që grabit cookie-t e shfletuesit (në të cilat ruhet sesioni ynë) dhe e dërgon atë në emailin e specifikuar. Sulmuesi merr cookie-n dhe e përdor atë për të mashtruar një kërkesë në emër të përdoruesit tonë të autorizuar. Serveri e pranon me sukses dhe e përpunon këtë kërkesë sikur të ishte nga një përdorues i autorizuar. Nëse verifikimi shtesë i adresës IP nuk zbatohet, një sulm i tillë do të çojë në një hakim të suksesshëm të llogarisë së përdoruesit me të gjitha pasojat që pasojnë.

Pse ishte e mundur kjo? Natyrisht, sepse emri dhe identifikuesi i sesionit janë gjithmonë të njëjtë për të gjithë jetëgjatësinë e sesionit, dhe nëse i merrni këto të dhëna, mund të dërgoni lehtësisht kërkesa në emër të një përdoruesi tjetër (natyrisht, brenda jetëgjatësisë së këtij sesioni). Ky mund të mos jetë lloji më i zakonshëm i sulmit, por teorikisht duket mjaft i realizueshëm, veçanërisht duke marrë parasysh që një trojan i tillë nuk ka nevojë as për të drejtat e administratorit për të grabitur cookie-t e shfletuesit të përdoruesit.

Si mund të mbroheni nga sulmet e këtij lloji? Përsëri, padyshim, duke kufizuar jetëgjatësinë e identifikuesit të sesionit dhe duke ndryshuar periodikisht identifikuesin brenda të njëjtit sesion. Ne gjithashtu mund të ndryshojmë emrin e sesionit duke fshirë plotësisht të vjetrën dhe duke krijuar një sesion të ri, duke kopjuar të gjitha variablat e sesionit nga ai i vjetër në të. Por kjo nuk ndikon në thelbin e qasjes, kështu që për thjeshtësi do të kufizohemi vetëm në identifikuesin e sesionit.

Është e qartë se sa më e shkurtër jetëgjatësia e ID-së së sesionit, aq më pak kohë do të ketë një sulmues për të marrë dhe përdorur cookie për të falsifikuar një kërkesë përdoruesi. Idealisht, një identifikues i ri duhet të përdoret për çdo kërkesë, i cili do të minimizojë mundësinë e përdorimit të seancës së dikujt tjetër. Por ne do të shqyrtojmë rastin e përgjithshëm kur koha e rigjenerimit të identifikuesit të sesionit caktohet në mënyrë arbitrare.

(Ne do të heqim pjesën e kodit që tashmë është diskutuar).

Funksioni startSession($isUserActivity=true) (// Jetëgjatësia e identifikuesit të sesionit $idLifetime = 60; ... nëse ($idLifetime) ( // Nëse jetëgjatësia e identifikuesit të sesionit është caktuar, // kontrolloni kohën e kaluar që kur seanca ishte krijuar ose rigjenerimi i fundit // (koha e kërkesës së fundit kur u përditësua variabli i sesionit koha e fillimit) if (isset($_SESSION["starttime"])) ( if ($t-$_SESSION["starttime"] >= $ idLifetime) ( // Koha që jeta e identifikuesit të sesionit ka skaduar // Gjeneroni një identifikues të ri session_regenerate_id(true); $_SESSION["starttime"] = $t;) ) other ( // Arrijmë këtu nëse seanca sapo ka është krijuar // Cakto kohën për gjenerimin e identifikuesit të sesionit në kohën aktuale $_SESSION["starttime"] = $t; ) ) return true; )

Pra, kur krijojmë një sesion të ri (që ndodh kur përdoruesi regjistrohet me sukses), vendosim variablin e seancës starttime, e cila ruan për ne kohën e gjeneratës së fundit të identifikuesit të sesionit, në një vlerë të barabartë me kohën aktuale të serverit. Më pas, në çdo kërkesë, ne kontrollojmë nëse ka kaluar mjaft kohë (idLifetime) nga gjenerimi i fundit i identifikuesit dhe nëse po, ne gjenerojmë një të ri. Kështu, nëse gjatë jetës së caktuar të identifikuesit sulmuesi që ka marrë cookie-n e përdoruesit të autorizuar nuk ka kohë për ta përdorur atë, kërkesa e rreme do të konsiderohet nga serveri si e paautorizuar dhe sulmuesi do të dërgohet në faqen e hyrjes. .

Shënim: ID-ja e re e sesionit futet në cookie-n e shfletuesit kur thirret funksioni session_regenerate_id(), i cili dërgon skedarin e ri, ngjashëm me funksionin session_start(), kështu që nuk kemi nevojë ta përditësojmë vetë cookie-n.

Nëse duam t'i bëjmë seancat tona sa më të sigurta, mjafton të vendosim jetëgjatësinë e identifikuesit në një ose madje të heqim funksionin session_regenerate_id() nga kllapat dhe të heqim të gjitha kontrollet, të cilat do të çojnë në rigjenerimin e identifikuesit në secilën prej tyre. kërkesë. (Unë nuk e kam testuar ndikimin e kësaj qasjeje në performancën dhe mund të them vetëm se funksioni session_regenerate_id(true) në thelb kryen vetëm 4 veprime: gjenerimi i një identifikuesi të ri, krijimi i një titulli me skedarin e sesionit, fshirja e të vjetrit dhe krijimi një skedar të ri sesioni).

Digresioni lirik: Nëse trojani rezulton të jetë aq i zgjuar sa nuk dërgon skedarë skedarësh te sulmuesi, por organizon dërgimin e një kërkese të rreme të parapërgatitur menjëherë pas marrjes së cookie-t, metoda e përshkruar më sipër ka shumë të ngjarë të mos jetë në gjendje të mbrojeni kundër një sulmi të tillë, sepse midis kohës kur Trojani merr cookie-n dhe dërgimit të një kërkese të rreme, praktikisht nuk do të ketë asnjë ndryshim dhe ka një probabilitet të lartë që në këtë moment identifikuesi i sesionit të mos rigjenerohet.

Mundësia e punës së njëkohshme në një shfletues në emër të disa përdoruesve Detyra e fundit që do të doja të konsideroja është mundësia e punës së njëkohshme në një shfletues nga disa përdorues. Kjo veçori është veçanërisht e dobishme në fazën e testimit, kur duhet të imitoni punën e njëkohshme të përdoruesve, dhe këshillohet ta bëni këtë në shfletuesin tuaj të preferuar, në vend që të përdorni të gjithë arsenalin e disponueshëm ose të hapni disa raste të shfletuesit në modalitetin e fshehtë. .

Në shembujt tanë të mëparshëm, ne nuk specifikuam në mënyrë eksplicite një emër sesioni, kështu që u përdor emri i paracaktuar PHP (PHPSESSID). Kjo do të thotë që të gjitha seancat që kemi krijuar deri tani kanë dërguar një cookie në shfletuesin me emrin PHPSESSID. Natyrisht, nëse emri i cookie-t është gjithmonë i njëjtë, atëherë nuk ka asnjë mënyrë për të organizuar dy sesione me të njëjtin emër brenda të njëjtit shfletues. Por nëse do të përdornim emrin tonë të sesionit për secilin përdorues, problemi do të zgjidhej. Le të bëjmë kështu.

Funksioni startSession($isUserActivity=true, $prefix=null) ( ... nëse (session_id()) kthehet true; // Nëse prefiksi i përdoruesit kalohet në parametrat, // vendosni një emër unik të sesionit që përfshin këtë prefiks, // përndryshe vendosni një emër të përbashkët për të gjithë përdoruesit (për shembull, MYPROJECT) emri i sesionit ("MYPROJECT".($prefiks ? "_".$prefiks: "")); ini_set("session.cookie_lifetime", 0); nëse (! session_start()) kthen false; ...)

Tani gjithçka që mbetet është të sigurohemi që skripti thirrës të kalojë një prefiks unik për secilin përdorues në funksionin startSession(). Kjo mund të bëhet, për shembull, duke kaluar një prefiks në parametrat GET/POST të çdo kërkese ose përmes një cookie shtesë.

Përfundim Si përfundim, unë do të jap kodin përfundimtar të plotë të funksioneve tona për të punuar me sesionet PHP, duke përfshirë të gjitha detyrat e diskutuara më sipër.

Funksioni startSession($isUserActivity=true, $prefiks=null) ( $sessionLifetime = 300; $idLifetime = 60; nëse (session_id()) kthehet i vërtetë; emri i sesionit ("MYPROJECT".($prefiksi ? "_".$prefiksi: "")); ini_set ("session.cookie_lifetime", 0); nëse (! session_start()) kthen false; $t = time(); if ($sessionLifetime) ( if (isset($_SESSION["lastactivity"] ) && $t-$_SESSION["lastactivity"] >= $sessionLifetime) (structSession(); kthe false; ) tjetër (nëse ($isUserActivity) $_SESSION["lastactivity"] = $t; ) ) nëse ($idLifetime ) ( if (isset($_SESSION["starttime"])) ( if ($t-$_SESSION["starttime"] >= $idLifetime) ( session_regenerate_id(true); $_SESSION["starttime"] = $t; ) ) else ( $_SESSION["starttime"] = $t; ) ) kthen true; ) funksioni deathSession() ( if (session_id()) ( session_unset(); setcookie(sesion_name(), session_id(), time() -60*60*24); session_destroy(); ) )

Shpresoj se ky artikull do të kursejë pak kohë për ata që nuk kanë hyrë kurrë shumë thellë në mekanizmin e sesionit dhe do të japë njohuri të mjaftueshme për këtë mekanizëm për ata që sapo kanë filluar të njihen me PHP.

Keni nevojë për një emër përdoruesi dhe fjalëkalim?

Për të dërguar artikuj në internet dhe për të kontrolluar statusin e artikujve të dorëzuar, duhet të regjistroheni dhe të identifikoheni në llogarinë tuaj.

Lista kontrolluese për përgatitjen e një artikulli për paraqitje

Si pjesë e procesit të paraqitjes së artikujve, autorët duhet të kontrollojnë që artikulli i tyre plotëson të gjitha pikat e mëposhtme; artikujt mund t'u kthehen autorëve nëse nuk i plotësojnë këto kërkesa.

Artikulli është përgatitur në përputhje me kërkesat

Kushtet e transferimit të së drejtës së autorit

Autorët ruajnë të drejtën e autorit të veprës dhe i japin revistës të drejtat e botimit të parë së bashku me veprën, ndërkohë që e licencojnë atë sipas kushteve të Creative Commons Attribution License, e cila u lejon të tjerëve ta shpërndajnë këtë vepër me atribuim të detyrueshëm tek autori i veprës dhe një lidhje tek botimi origjinal në këtë revistë.

Deklarata e Privatësisë

Emrat dhe adresat e postës elektronike të futura në faqen e internetit të kësaj reviste do të përdoren vetëm për qëllimet e përcaktuara nga kjo revistë dhe nuk do të përdoren për ndonjë qëllim tjetër ose nuk do t'i jepen asnjë personi ose subjekti tjetër.

Përpara regjistrimit në sistem, përdoruesi pajtohet me politikën për përpunimin dhe ruajtjen e të dhënave personale.

Pagesat e autorit

1500 karaktere me hapësira: 300.00 (RUB)

Botimi i 1 faqe dorëshkrimi (1500 karaktere) - 300 rubla. Materialet / tabelat grafike paguhen veçmas - 50 rubla / 1 copë. Kopja e autorit, përfshirë transportin brenda Rusisë, paguhet me kërkesë të autorit - 400 rubla. Transporti jashtë vendit - 800 rubla. Kostoja e dërgimit të një certifikate të pranimit të materialit për botim është 150 rubla.

Përkthimi i informacionit shoqërues (emri i plotë, vendi i punës së autorëve; titulli; abstrakt; fjalë kyçe) në anglisht 0,5 rubla për çdo personazh, duke përfshirë hapësirat.

Kujdes! Autorët (kandidatët dhe doktorët e shkencave) të cilët, sipas elibrary.ru, kanë 300 ose më shumë citate (pjesa e vetë-citimeve nuk duhet të jetë më shumë se 30%) publikohen pa pagesë. Nëse keni të drejtë për publikim falas, kur dërgoni materialin, në fushën e komenteve, tregoni një lidhje me profilin tuaj të bibliotekës me numrin e citimeve. Kostot e transportit për grumbullimin paguhen veçmas.

Siguria e faqes në internet bazohet në menaxhimin e sesioneve. Kur një përdorues lidhet me një sajt të sigurt, ata japin kredencialet, zakonisht në formën e një emri përdoruesi dhe fjalëkalimi. Serveri i uebit nuk e ka idenë se cili përdorues është identifikuar tashmë ose si lundrojnë nga faqja në faqe. Mekanizmi i sesionit i pengon përdoruesit që të vendosin një fjalëkalim sa herë që duan të kryejnë një veprim të ri ose të shkojnë në një faqe të re.

Në thelb, menaxhimi i sesionit siguron që përdoruesi i lidhur aktualisht është ai që është vërtetuar. Por për fat të keq, seancat janë bërë një objektiv i dukshëm për hakerat, sepse ato mund të lejojnë akses në një server në internet pa pasur nevojë për vërtetim.

Pasi përdoruesi është vërtetuar, serveri i uebit i siguron atij një ID të sesionit. Ky ID ruhet në shfletues dhe zëvendësohet sa herë që nevojitet vërtetimi. Kjo ju lejon të shmangni proceset e përsëritura të hyrjes/hyrjes së fjalëkalimit. E gjithë kjo ndodh në sfond dhe nuk shkakton shqetësim tek përdoruesi. Imagjinoni sikur të keni futur emrin e përdoruesit dhe fjalëkalimin sa herë që shikoni një faqe të re!

Në këtë artikull do të përpiqem të përshkruaj të gjitha mënyrat që di për të mbrojtur ID-në e sesionit në PHP.

Përdorimi i cookie-ve Si parazgjedhje, të gjitha informacionet e sesionit, duke përfshirë ID-në, dërgohen te një cookie. Por kjo nuk ndodh gjithmonë. Disa përdorues çaktivizojnë cookies në shfletuesit e tyre. Në këtë rast, shfletuesi do të kalojë ID-në e sesionit në URL.

Këtu ID-ja transmetohet në tekst të qartë, në krahasim me një sesion nëpërmjet një cookie, kur informacioni është i fshehur në kokën HTTP. Mënyra më e thjeshtë për t'u mbrojtur nga kjo do të ishte ndalimi i transmetimit të identifikuesit të sesionit përmes shiritit të adresave. Kjo mund të bëhet duke shkruar sa vijon në skedarin e konfigurimit të serverit Apache .htaccess:

Php_flag session.use_only_cookies aktiv

Përdorimi i enkriptimit Nëse faqja juaj duhet të përpunojë informacione të ndjeshme, të tilla si numrat e kartave të kreditit (përshëndetje nga Sony), duhet të përdorni enkriptimin SSL3.0 ose TSL1.0. Për ta bërë këtë, kur vendosni një cookie, duhet të specifikoni true për parametrin e sigurt.

Nëse e ruani fjalëkalimin e sesionit në variablin $_SESSION (është akoma më mirë të përdorni sql), atëherë nuk duhet ta ruani atë në tekst të qartë.

Nëse ($_SESSION["fjalëkalimi"] == $userpass) ( // kodi )

Kodi i mësipërm nuk është i sigurt sepse fjalëkalimi ruhet si tekst i thjeshtë në një variabël sesioni. Në vend të kësaj, përdorni enkriptimin md5, diçka si kjo:

Nëse ($_SESSION["md5password"] == md5($userpass)) ( // kodi )

Kontrolli i shfletuesit Për të parandaluar mundësinë e përdorimit të një sesioni nga një shfletues tjetër (kompjuter), duhet të vendosni një kontroll të fushës së titullit HTTP të agjentit të përdoruesit:

Fillimi_sesionit(); if (isset($_SESSION["HTTP_USER_AGENT"])) (nëse ($_SESSION["HTTP_USER_AGENT"] != md5($_SERVER["HTTP_USER_AGENT"])) ( // kodi ) ) tjetër ($_SESSION["HTTP_USER_USER_USER" ] = md5 ($_SERVER["HTTP_USER_AGENT"]);

Skadimi i sesionit Kufizoni jetëgjatësinë e sesionit, si dhe kohën e skadimit të cookies. Si parazgjedhje, kohëzgjatja e seancës është 1440 sekonda. Ju mund ta ndryshoni këtë vlerë përmes php.ini dhe .htaccess. Shembull për .htaccess:

# Jetëgjatësia e seancës në sekonda
sesioni php_value.gc_maxlifetime 3600
# Jetëgjatësia e biskotave në sekonda
php_value sesion.cookie_lifetime 3600

Lidhja sipas adresës IP Në situata të caktuara (jo gjithmonë), duhet të lidhni me adresën IP. Kryesisht kur numri i përdoruesve është i kufizuar dhe ka IP statike. Kontrolli mund të bazohet ose në listën e adresave IP të lejuara,

Include ("ip_list.php"); //$ip_white_list = grup ("admin1" => "111.222.333.444", "admin2" => "555.666.777.888"); if(!empty(array_search($_SERVER["REMOTE_ADDR"],$ip_white_list))) (header("Vendndodhja: admin.php"); ) else (jehonë "MODUHIM AKSES!"; )

Ose me adresë IP për secilën kërkesë (vetëm për IP statike):

If(isset($_SESSION["ip"]) dhe $_SESSION["ip"] == $_SERVER["REMOTE_ADDR"]) ( header ("Vendndodhja: admin.php"); ) other ( session_unset (); $ _SESSION["ip"] = $_SERVER["REMOTE_ADDR"];)

Duhet të jeni të vetëdijshëm se hakerimi nuk mund të shmanget plotësisht. Ju mund ta bëni këtë hak sa më të vështirë të jetë e mundur vetëm me çdo mjet të njohur. Sidoqoftë, gjithashtu nuk duhet të harroni për përdoruesit tuaj të ligjshëm, në mënyrë që të mos ndërlikoni jetën e tyre me një mbrojtje të tillë.

Ky artikull është shkruar në vitin 2009 dhe mbetet një nga postimet tona më të njohura. Nëse dëshironi të mësoni më shumë rreth PHP dhe MySQL, mund ta gjeni këtë me interes të madh.

SHËNIM: Ky artikull është përditësuar rishtazi për të punuar në PHP 4.2 ose më vonë!

Kohët e fundit pata rastin të punoj në një projekt të vogël me një grup njerëzish. Ne kishim vendosur që herët se vetëm ai email nuk do të ishte i mjaftueshëm për t'i mbajtur të gjithë të informuar, kështu që unë u ngarkova të ndërtoja një uebfaqe të vogël për projektin. Ai do të përmbajë një tabelë të thjeshtë mesazhesh, një vend ku mund të ngarkojmë dokumente dhe skedarë të tjerë për t'i përdorur nga pjesa tjetër e ekipit dhe informacione kontakti për anëtarët e ndryshëm të ekipit.

Që shumë prej këtyre veçorive të funksiononin, e dija se do të më duhej që përdoruesit të identifikoheshin përpara se të hyja në pjesët përkatëse të faqes. Ajo që më duhej ishte një sistem që do t'i lejonte përdoruesit të regjistroheshin për një ID përdoruesi për të hyrë në faqe, pastaj ta përdornin menjëherë atë ID pa asnjë ndërhyrje nga ana ime.

Në këtë artikull, unë do të jap një pasqyrë të sistemit që kam zhvilluar, duke filluar në gjysmën e parë me procesin e regjistrimit të përdoruesit. Në gjysmën e dytë, do të përqendrohem në vetë sajtin, se si kërkon që përdoruesit të identifikohen dhe më pas të ruajnë statusin e hyrjes gjatë gjithë vizitës së tyre. Unë do t'i kushtoj vëmendje të veçantë përdorimit të veçorive të menaxhimit të sesioneve në PHP. Në fund, duhet të keni të gjithë informacionin që ju nevojitet për të zbatuar një sistem të ngjashëm tuajin.

Gjatë gjithë këtij artikulli, unë do të supozoj se ju keni një njohje bazë me gjuhën PHP, përdorimin e formularëve për të paraqitur informacion në një skript PHP dhe se si PHP mund të përdoret për të bashkëvepruar me një bazë të dhënash MySQL. Nëse ndonjë nga këto është koncepte të huaja për ju, duhet të filloni duke lexuar artikullin tim të mëparshëm, .

Pjesa e Parë: Procesi i Regjistrimit Formulari i Regjistrimit

Një vend i natyrshëm për të filluar ndërtimin e një faqeje që do t'u kërkojë përdoruesve të regjistrohen për akses është vetë procesi i regjistrimit. Siç mund të pritej, një formë e thjeshtë e bazuar në ueb do ta bëjë këtë. Ja si do të duket:

Dhe këtu është kodi për këtë formë:




Regjistrimi i ri i përdoruesit



Formulari i regjistrimit të përdoruesit të ri

* tregon një fushë të kërkuar


Me objektivin tani të qartë, unë do t'ju përshkruaj kodin për accesscontrol.php. Filloni duke përfshirë dy skedarët tuaj të dobishëm të përfshirë: