Sesionet
E meta kryesore e protokolit HTTP është pamundësia për ta ruajtur gjendjen, gjegjësisht për t’i ruajtur vlerat e variablave gjatë kalimit nga një skriptë në tjetrën. Kjo mangësi deri diku kompensohet si vijon:
- duke ia bashkangjitur vlerat e dëshiruara URL-së që thirret (GET),
- duke i dërguar vlerat me anë të një formulari (POST),
- duke i ruajtur vlerat në një fajll lokal (COOKIE) për t’i bartur pastaj në server
Në të tri rastet flitet për bartje të vlerave, e jo për ruajtjen e tyre. Gjatë bartjes së atyre vlerave, është i mundur edhe ndryshimi i tyre, me apo pa qëllim.
Për aplikacione më komplekse, ku duhet të ruhet gjendja, gjegjësisht zgjedhjet që i ka bërë një vizitor (si në rastin e një e-commerce aplikacioni), asnjëra prej metodave të cekura nuk ofrojnë fleksibilitet të mjaftueshëm.
Metoda GET bie poshtë sepse do të duhej që në çdo URL të shtohet query string me vlerat e variablave, diç që në një moment mund të jetë i pamenaxhueshëm nga ana e skriptës për shkak të kompleksitetit. Veç kësaj, vlerat në URL janë të manipulueshme, gjë që do ta cenonte integritetin e aplikacionit. Imagjinoni nëse në URL vendoset çmimi dhe vizitori e ndryshon atë.
Metoda POST është jopraktike për shkak se në çdo faqe do të duhej të futeshin formularë, të cilat fillimisht i lexojnë vlerat e dëshiruara, për t’ia bartur pastaj skriptës së thirrur.
COOKIE poashtu i ka mangësitë e veta që e bëjnë të papërshtatshëm për përdorim në të gjitha aspektet e një aplikacioni kompleks. Ato mund të jenë të manipulueshme sepse të dhënat ruhen në një fajll lokal, ku sulmuesi mund t’i ndryshojë të dhënat sipas nevojës, për t’iu prezantuar Web serverit si ndonjë vizitor tjetër. Cookiet, nëse nuk janë ndërmarrë masat e duhura, janë të lexueshme nga JavaScript, duke e bërë kështu aplikacionin të ekspozueshëm ndaj XSS.
Zgjidhja më e mirë ofrohet me SESSION, ku mekanizmi për bartjen dhe ruajtjen e vlerave është diç më kompleks, por më i kompletuar dhe më i sigurtë.
Sesioni startohet me funksionin session_start(). Me këtë i udhëzohet serverit që ta krijojë një sesion të ri, apo ta vazhdojë sesionin aktual.
Me krijim të sesionit të ri nënkuptohet krijimi i një fajlli në server, brenda të cilit do të ruhen të gjitha të dhënat e nevojshme. Ai fajll do të largohet automatikisht kur mbaron sesioni.
Pra, pas session_start() krijohet një fajll që i korrespondon atij sesioni. Emërtimi i fajllit është një hash unik, dhe kjo bëhet me qëllim që të parandalohet përdorimi i fajllit të njëjtë për dy sesione. Ai hash paraqet ID-në e sesionit, session_id().
Meqenëse HTTP, gjatë kalimit prej një faqeje në tjetrën nuk e ruan gjendjen, si do të dijë serveri se cili sesion cilit vizitor i përket?
Të dhënat që Web serveri i merr prej browserit janë të pamjaftueshme për ta identifikuar vizitorin në mënyrë unike. Të dhënat “identifikuese” janë:
- IP adresa
- Browseri
- Versioni i browserit
- Sistemi operativ
Këto të dhëna i dërgohen serveri gjatë çdo HTTP request, psh. kur kërkohet hapja e një faqeje dhe duken kështu:
Mozilla/5.0 (Windows NT 6.3; WOW64; rv:37.0) Gecko/20100101 Firefox/37.0
Këto të dhëna janë të pamjaftueshme për ta identifikuar vizitorin, sepse Web serveri e “sheh” vetëm IP adresën publike, ndërkohë që janë me miliona kompjuterë prapa NAT (Network Address Translation), gjegjësisht prapa routerëve, me IP adresa private. As të dhënat mbi sistemin operativ dhe browserin nuk mund të formojë një identifikator unik sepse shumë përdorues mund ta kenë të njëjtin sistem operativ dhe të njëjtin version të browserit.
Në pamundësi të identifikimit të vizitorit nga të dhënat e dërguara me HTTP, Web serveri shërbehet me një cookie që do t’ia dërgojë browserit, nëse ai cookie tashmë nuk ekziston në atë browser. Cookie do të përmbajë vlerën (hash-in) e session ID. Ky cookie, prej momentit të krijimit e deri në fund të sesionit, do t’i bashkangjitet çdo HTTP requesti duke ia bartur Web serverit ID-në e sesionit, e në bazë të kësaj - Web serveri do të dijë se në cilin fajll t’i regjistrojë vlerat e sesionit.
Pra, për ndërtimin e “urës” ndërmjet browserit dhe Web serverit, na ndihmon prezenca e një cookie që e përmban ID-në e sesionit.
Skenari:
- Browseri i dërgon Web serverit kërkesë për hapjen e faqes
- Serveri verifikon HTTP requestin e pranuar dhe kërkon prezencën e cookie me ID-në e sesionit
- Nëse cookie nuk ekziston, krijohet një sesion i ri (duke krijuar fajll të ri) dhe ID-ja e atij sesioni regjistrohet në një cookie që i dërgohet browserit në çdo HTTP response
- Nëse cookie ekziston në HTTP request, lexohet vlera e ID-së së sesionit, dhe kërkohet fajlli me atë ID (hash). Nëse fajlli ekziston, procesi vazhdon normalisht. Nëse nuk ekziston, kjo do të thotë se cookie përmban informatë jovalide, kështu që hapet një sesion i ri duke krijuar një fajll të ri në server dhe duke dërguar një cookie të ri në browser.
- Prej momentit që Web serveri ia dërgon browserit cookien me session ID, browseri do ta kthejë atë cookie në Web server në çdo HTTP request, ndërsa Web serveri do ta kthejë prapa në browser në çdo HTTP response. Me këtë “ping-pong” të cookie ndërmjet browserit dhe serverit ruhet kontinuiteti i “identitetit” të vizitorit përgjatë një sesioni.
Përmbajtja e cookie të sesionit:
PHPSESSID=pd6fqjdm7rc8d7ho5claukmv66
PHPSESSID është emri i cookie, ndërsa pd6fqjdm7rc8d7ho5claukmv66 është ID-ja e sesionit. Në Web server ekziston fajlli me emërtimin sess_pd6fqjdm7rc8d7ho5claukmv66 ku ruhen vlerat e variablave të përdorura gjatë këtij sesioni.
Me echo session_save_path(); mund të verifikojmë se në cilin direktorium ruhen fajllat e sesionit. Në rastin e WAMP, ky lokacion do të jetë c:/wamp/tmp:
- sess_6nhs0c9j9u7qp3dcrtnh00mm96
- sess_f5cnai4mdvqkem7v286dr9ar66
- sess_g76a18t8p7opc328qpj6grd7m23gg10l
- sess_jkn3s6ac38f029ah9jip2t5v93 …
Nëse e hapim ndonjërin prej fajllave, aty do të gjejmë të dhëna të serializuara të sesionit:
1 shporta|a:2:{i:0;a:3:{s:2:"id";i:1;s:5:"price";d:650.14999999999998;s:3:"qty";d:\
2 1;}i:1;a:3:{s:2:"id";i:2;s:5:"price";d:999.95000000000005;s:3:"qty";d:4;}}crsf_t\
3 oken|s:32:"ecdb364e8740ce40879410a7071725e4";
Këto të dhëna janë të ruajtura në plain text dhe mund të dekodohen lehtë si array:
1 array (size=2)
2 'shporta' =>
3 array (size=2)
4 0 =>
5 array (size=3)
6 'id' => int 1
7 'price' => float 650.15
8 'qty' => float 1
9 1 =>
10 array (size=3)
11 'id' => int 2
12 'price' => float 999.95
13 'qty' => float 4
14 'crsf_token' => string 'ecdb364e8740ce40879410a7071725e4' (length=32)
Prandaj, është me rëndësi që askush nga jashtë të mos ketë qasje në këto fajlla.
Jetëgjatësia e sesionit
Sa do të jetojë ky cookie, gjegjësisht sa do të jetë jetëgjatësia e një sesioni? Varet si është konfiguruar PHP serveri. Vlera standarde është 1440 sekonda, gjegjësisht 24 minuta.
php.ini
session.gc_maxlifetime = 1140
Nëse brenda 24 minutave nuk ka aktivitet nga ana e vizitorit, fajlli i sesionit fshihet dhe në mungesë të tij, sesioni do të skadojë.
Natyrisht, ka metoda për tejkalimin e këtij “kufizimi”, me përdorimin e një cookie tjetër që e përmban ID-në e anëtarit (jo të sesionit) dhe që ka jetë më të gjatë (psh 30 ditë). Aplikacioni mund të programohet asisoj që së pari e verifikon ekzistencën e këtij cookie të dytë dhe nëse ekziston, e lexon ID-në e anëtarit nga aty dhe fillon një sesion të ri, duke e deklaruar anëtarin të autentikuar. Në këtë parim funksionon opsioni “Remember me”, që e hasim nëpër Web site të ndryshme.
Fillimi i një sesioni
session_start();
Përfundimi i sesionit
Sesioni mbaron në tri mënyra:
- Kur vizitori e mbyll browserin
- Kur vizitori është inaktiv brenda një periudhe kohore
- Kur vizitori e klikon butonin përkatës për çlajmërim
- Kur fshihet session cookie nga browseri
Mbyllja e një sesioni:
1 $_SESSION = array();
2 session_destroy();
3 setcookie('PHPSESSID', ", time()-3600,'/', ", 0, 0);
Session hijacking
//
Menaxhimi i sesioneve nga databaza
Sesionet mund të menaxhohen edhe nga databaza.