ugrás a tartalomhoz

Sessionmentes weboldalak

janoszen · Nov. 1. (K), 01.45
Sessionmentes weboldalak

Az elmúlt hetekben érdekes koncepcióval játszottam. Mi lenne, ha nem lenne munkamenetünk, vagy ismertebb nevén sessionünk? Lehetne-e modern weboldalt készíteni? Működnének-e az elvárt funkciók? Mennyire lenne nehéz fejleszteni?

Miért?

Ezen a ponton joggal gondolkozol el, hogy vajon elgurult-e a gyógyszerem, hogy egy ilyen alapvető technológiát ki akarok dobni? De nézzük, hogy mi is az a session.

A weboldalak a HTTP alapjain nyugszanak. Egy kérés, egy válasz. Ha egy erőforrást el akarunk érni, intézünk egy kérést a szerverhez, amire válaszként megkapunk egy HTML dokumentumot. Vagy egy képet. Vagy egy videót.

A probléma ott van, hogy a szerver nem tudja ezeket a lekérdezéseket egymáshoz kapcsolni. Nem tudja azt, hogy aki az előző lekérdezésben a helyes jelszót küldte, az ugyanaz az ember, aki most a szupertitkos fájlokhoz hozzá szeretne férni.

Na ezt a problémát oldja meg a session. Az első válasszal küldünk a böngészőnek egy sütit, benne egy azonosítóval, amit az innentől minden újabb kéréssel visszaküld. Szerveroldalon ehhez az azonosítóhoz rendeljük azokat az adatokat, amik ahhoz a sessionhöz, ahhoz a munkamenethez tartoznak.

Ez elméletben szép és jó, azonban egy igen csúnya probléma van vele. A programozó.

Az olyan környezetek, mint a PHP ugyanis nemcsak automatizálják a folyamatot, de transzparensen lemezre is szerializálják az azonosítóhoz rendelt adatokat, ami igen kényelmes gyorstárazási lehetőséget kínál, amely ráadásul egy-egy felhasználóra egyedi. Vagyis bejelentkezéskor szépen betöltjük az egész user objektumot, majd eltároljuk a sessionben. És ha már ott tartunk, az összes megrendelését is. És a session fájl csak nő, és nő, és nő.

Amellett, hogy rengeteg helyet foglal a diszken, komoly logikai problémákat is okozhat a sessionök ilyen jellegű használata. Hiszen mi történik, ha a felhasználó egy másik eszközről is bejelentkezik, teszem azt a telefonjáról, és onnan módosítja az adatait?

Mindjárt nem lesznek aktuálisak a sessionben gyorstárazott adatok, és mindenféle érdekes problémák lépnek fel, amiket ráadásul nehéz lenyomozni.

Vagy mondok kacifántosabbat. Mi történik akkor, ha egy felhasználó párhuzamosan két lekérdezést indít?

Amint látható, mindkét folyamat betölti a session adatokat, majd mindkettő elkezd dolgozni a saját feladatán. A feldolgozás végeztével mindkettő visszaírja a sessiont a fájlba vagy adatbázisba. Vegyük észre azonban, hogy a második lekérdezés felülírja az első által végzett módosításokat. Például a PHP alapértelmezett munkamenet-kezelője ezt elkerülendő zárolja az adatokat, és egyszerre csak egy folyamatnak biztosít hozzáférést a sessionhöz, ami nem skálázódik túl jól. Egy elosztott rendszeren, ahol a zárolás nem jöhet szóba, az egy az egyben kiolvasott és viszaírt adattömeg folyamatos ütközésekhez fog vezetni.

A sessionökkel önmagában nincs baj. A probléma akkor keletkezik, amikor elkezdjük használni a legtöbb webes környezet által hozzájuk felkínált amorf adattároló zsákot. Vagyis például PHP-ban a $SESSION-t. Nézzük tehát az alternatívákat.

Bejelentkezés

Hogyan valósítanánk meg a felhasználói bejelentkezést sessionök nélkül?

A válaszhoz ihletet merítünk az OAuth protokollból. Amikor a felhasználó bejelentkezik felhasználónévvel és jelszóval, kiadunk egy egyedi azonosítót. Egy tokent. Munkamenet-azonosító helyett ezt tároljuk el a sütiben.

Amikor a felhasználó egy olyan oldalra téved, ahol a felhasználói adataira van szükség, a süti kiolvasásra kerül, és a token alapján betöltjük a felhasználó adatait az adatbázisból.

Vagyis minden lekérdezésre kénytelenek vagyunk az auth tokent ellenőrizni. Elsőre azt sejtenénk, hogy ez nagyon nem hatékony, de ha jobban belegondolunk, a sessionöket ugyanúgy be kellett tölteni. Annyi a különbség, hogy most nem egy hatalmas amorf adathalmazt próbálunk kiszedni az adatbázisból, hanem egy nagyonis konkrét céllal nyúlunk hozzá. Az eredmény az, hogy ehhez a célhoz tudunk megfelelő adatbázist választani és optimalizálni.

Sőt mi több, mégegy nagyon fontos lehetőség nyílik meg előttünk. Mivel az auth tokeneket a felhasználóhoz kötötten tároljuk, lehetőségünk nyílik a felhasználó aktív tokenjeit kilistázni, hasonlóan mint ahogy a Facebook is csinálja.

Űrlapok kezelése

A sessionök másik gyakori felhasználása a különböző űrlapokba írt értékek megőrzése, például többoldalas űrlapok esetén.

Természetesen erre is van megoldás, hiszen a sessionök helyett minden további nélkül tárolhatjuk sütikben is a felhasználótól kapott adatokat. Gondoljunk bele, semmi olyan nincs benne, amit a felhasználó ne tudna! A böngésző által rendelkezésünkre bocsájtott 4 kB erre bőségesen elegendő. Ha ennél több adatot kell megadni egy űrlapban, akkor egyébként is javasolt egyfajta autosave funkció implementálása.

Állapot megőrzése

Sokan a munkameneteket arra is használják, hogy megőrizzenek bizonyos állapotot. Például azt, hogy melyik lépésnél tartott a felhasználó a regisztrációs folyamatban. Ezt a technikát személy szerint kerülendőnek tartom, hiszen a felhasználó egy vissza gomb megnyomásával semmissé teheti a jól kigondolt állapoti logikánkat.

Helyette azt javaslom, hogy minden lépés rendelkezzen önálló címmel, és egyedileg ellenőrizze, hogy aktuális-e még a kitöltése. Ha nem, automatikusan ugorjon a következőre. Ez megkerüli a session problémáját és a felhasználói élményt is javítja, mert működni fog a vissza gomb.

Ellenérvek

Noha a fenti elképzelést a gyakorlatban is teszteltem, és meglepően jól működik, vannak ellenérvek. A legnagyobb talán az, hogy ezt a fajta működést egyetlen általam ismert űrlapkezelő programkönyvtár sem támogatja. Azaz szinte nulláról kell lefejleszteni mindent, vagy meglehetősen sokat kell módosítani a meglevő szoftvereken.

Ezen felül érdemes figyelemmel kísérni a sütiket tartalmazó fejléc méretét is. Ha sok űrlapunk van, könnyen túlnőheti a webszerveren beállított maximális méretet, ami fura hibákat eredményezhet.

Jelen állapotában ezt a technikát nem tudom javasolni általános felhasználásra. Olyan esetekben mint az enyém, ahol egy egyedi szoftverplatformon kell dolgozni, és esélytelen a külső könyvtárak használata, viszont érdemes megfontolni az alkalmazását.

Összegzés

Ha jobban belegondolunk, ez a megoldás is egyfajta session, amit részben a felhasználói adatok közé, részben pedig a kliensoldalra helyezünk. Csak éppen szépen, strukturáltan tároljuk az adatokat, a jellegüknek megfelelő helyen, nem egyetlen amorf zsákban, amibe az égegyadta világon mindent bele lehet tenni. Ugyanezt az elvet kellene követni a többi adattervezési feladatnál is. Ezzel elérjük azt, hogy az esetleges hibák sokkal lokalizáltabbak, könyebben felderíthetőek, és a teljesítményen is javíthatunk.

 
janoszen arcképe
janoszen
Pásztor János a fejlesztés és az üzemeltetés témakörével is foglalkozik, igyekszik az egyikben szerzett tapasztalatokat a másikba is átültetni. A Weblaboron kívül Facebookon ,Twitteren, a Refaktor Magazinon és a Refactor Zone-on publikál.
1

+1

szabo.b.gabor · Nov. 1. (K), 09.12
hiánypótló cikk (: abszolút egyetértek. tényleg csak annyi fontos, hogy ki csinálja amit éppen csinál, amire egy token bőven elég.

én mondjuk cookie-ban nem tárolnék form adatokat, sőt leginkább semmit sem, lévén mindig utaznak mindenhova, meg a csrf-re figyelni miatta. ez a token is menjen egy speckó headerben, aztán viszonlátásra. ok, kényelmi szempontból maradhat egy másolat cookieban is, de ne a cookie-ból olvassuk ki szerver oldalon.

adattárolásra meg ott van a javascript, localstorage, meg biztos van más is..
2

Ez így van

janoszen · Nov. 1. (K), 09.34
Ha belegondolsz, a sütikben levő adat pont annyira megbízhatatlan, mint az űrlapból jövő. Vagyis szerver oldalon pont ugyanúgy kell kezelni a kettőt. Az előnye az, hogy szerver oldalról írható-olvasható, nem kell hozzá JS.

CSRF ellen meg szépen lehet védekezni egy httpOnly CSRF token sütivel.
3

Süti

Poetro · Nov. 1. (K), 10.45
Szerintem a süti is teljesen felesleges. Sokkal hatékonyabb lehet a tokent sessionStorage-ban tárolni, és csak a kéréseknek elküldeni, amelyeknek szüksége van erre. A sütik túl nagyok, és túl sok kérés megkapja őket (minden kérés az adott szerveren, ami beleesik a süti hatókörébe).
4

Akár

janoszen · Nov. 1. (K), 11.04
A süti hatókörét azért lehet korlátozni ha optimalizálni akarsz. Azon a setupon ahol ezt a technikát használon, az összed static asset külön aldomainen van.

Persze ha a backendet csak API-ként használod, akár a sessionStorage is jó lehet.
5

Ahol pedig én használok SSO-t

Poetro · Nov. 1. (K), 11.16
Ahol pedig én használok SSO-t (ahogy mindenhol az utóbbi 3 évben), az mind SPA volt, és mindenhol a backend csak API-ként volt használva. Az, hogy a token hogyan került a szerver oldalra, teljesen változó volt. Volt hogy sessionStorage, volt ahol süti, és volt ahol szerver oldali session volt (és egyik sem PHP).
6

Nekem hiányérzetem van, nem

inf3rno · Nov. 1. (K), 18.43
Nekem hiányérzetem van, nem igazán lett kifejtve, hogy mi az a token ebben a kontextusban. Illetve az sem lett kifejtve, hogy abból adódnak a konkurrenciával kapcsolatos gondok, hogy a kliens állapotát a szerveren próbáljuk kezelni.
7

Nehéz

janoszen · Nov. 1. (K), 19.03
Azért, mert baromi nehéz általánosan leírni a problémákat. A session egy hatalmas zsák és bármilyen verselyhelyzet adatvesztéshez vezethet, függetlenül attól, hog a kliens állapotát próbálod tárolni, "csak" cacheled-e az adatokat, vagy egyéb feladatokra használod.

A cikk mondanivalója inkább az, hogy a session feladatköreit szét kéne szabdalni, apróbb, kezelhetőbb részekre vágni, és ha lehet, a versenyhelyzetektől mentesíteni. (A lockolás az én szememben nem játszik, mert egy bizonyos méret fölött lehetetlen.)
8

Hát ezzel egyet tudok érteni.

inf3rno · Nov. 1. (K), 19.35
Hát ezzel egyet tudok érteni. Ha valaki úgy is dönt, hogy kell neki a hagyományos session, akkor is érdemes minimumra redukálni a tartalmát, és a kevésbé életbevágó dolgokat, mondjuk az űrlapok tartalmát inkább kliens oldalon tárolni. Bizonyos esetekben ha állapotmentes kommunikáció kell, akkor meg szerver oldali session helyett lehet tokenezni.
9

Ha kliens oldalon tarolod az

csongor@halmai.hu · Nov. 23. (Sze), 07.14
Ha kliens oldalon tarolod az adatokat, akkor is lehet problema. Ha pl. telefonnal a kezemben hasznalom az asztali gepet, akkor a ket eszkoz lokalisan tarol valami kulonbozot, aminek elobb-utobb a szerverre kell kerulnie, es akkor utkozni fognak.
10

Ütközés?

Poetro · Nov. 23. (Sze), 09.38
Miért lenne ütközés? Kettő munkameneted van, amiben két különböző dolgot csinálsz. Ha például egy bevásárlókosárról van szó, akkor lehet, hogy két kosarad van.
11

State

janoszen · Nov. 23. (Sze), 11.57
Igen, ha allapotod van, akkor ez problema. A cel az, hogy ne legyen allapot, es a session elso szamu kisertes valamilyen allapot letrehozasara.

A cel az, hogy ne legyen ilyen jellegu allapotod, hanem pl. a kosar tartalmat ne a sessionben, hanem a DB-ben tarold, userhez kotve. Igy mindket keszuleken ugyanazt latod.
12

Tehát - ha jól értem - adott

visuall · Dec. 10. (Szo), 16.35
Tehát - ha jól értem - adott egy (backend -> )tokenkiadó szerver + a kiszolgáló. Tegyük fel, hogy szeretnék egy ilyet írni. Alapvetően milyen technológiák állnak rendelkezésre a webes interfész kiszolgálásához?
Beépíthetjük közvetlenül a PHP-ba a token kiadását, de annak lefolyása a többi folyamattól független lesz - speciális esetben kell a lockolás, ami nem megfelelő. Van a node.js, amellyel egy socketen keresztül beszélgethetünk.
Mi más van még?
(ui.: hogy vélekednek ma már a CGI-alapú futtatásról?)
13

Nem

janoszen · Dec. 11. (V), 11.02
Ennek nem feltetlenul kell kulon szerveren lennie, lehet az alkalmazasodon belul is. A lenyeg egy logikai kulonbseg a sessionben valo tarolashoz kepest. Ajanlom figyelmedbe az Entity-Boundary-Interactor tervezesi mintat, azzal igen konnyen megvalosithato egy ilyen struktura.
14

Ránéztem a cikkedre

visuall · Dec. 12. (H), 21.18
Ránéztem a cikkedre (https://www.refaktor.hu/tiszta-kod-8-resz-egy-tiszta-kod-blog-kezdetei/), és el kell mondanom, hogy profi munka lett!
Hasonló következtetésekre jutottam, mikor a saját OO-alapú blogomat terveztem, de ez sokkal összeszedettebbé rakta eme gondolataimat. A TDD-alapú fejlesztést figyelgettem, de nem nagyon fogott meg. Pedig egy nagyon hasznos dolog: kiszűri a következtethetetlen részeket.
Na, meg is jött a hangulatom egy saját oldal elkészítéséhez! Ezer köszönet! :)
15

BDD-t nézegessed, szerintem

inf3rno · Dec. 13. (K), 12.10
BDD-t nézegessed, szerintem az sokkal emberközelibb, ha jól csinálják, mint a TDD, bár kevésbé alapos.
17

vitatkoznék :)

Pepita · Dec. 18. (V), 16.44
TDD is simán ember közeli, ha valóban jól csinálod.
Van egy terved (mondom van, nem fejben, hanem le írva :) ), ez alapján írsz egy első tesztet, ami a legelső valamit fogja vizsgálni.
Futtatod.
Hoppá, el szállt, nincs is olyan class. :-D
Hát létre hozod a class valamit.
Megint futtatod.
Hoppá, nincs az a metódus. :)
Csinálsz neki.
...
A mellett, hogy tök mókás, egyrészt duplán figyelsz a kódod minőségére, másrészt a későbbiekben ha változtatni kell, meg véd egy csomó bug lehetőségtől.
18

Szerintem nem jött át. A

inf3rno · Dec. 18. (V), 23.48
Szerintem nem jött át. A TDD-t csak programozó érti, a BDD-t meg laikus is. Nagyjából ennyi a különbség. Ezek után nem hinném, hogy a TDD ember közeli lesz valaha is, más absztrakciós szinten van...
19

jogos

Pepita · Dec. 18. (V), 23.51
Én értettem félre.
16

Ha

janoszen · Dec. 14. (Sze), 13.52
Ha motivaltalak uj dolgok tanulasara, akkor elertem a celomat. :)
20

Bár koránt sem értek annyira

Oregon · Dec. 31. (Szo), 17.18
Bár koránt sem értek annyira ehhez, mint te janaszen, de nálam régóta ez a megoldás a session-ben:
user_id;
hash('sha512', $data);
// $data = 3-4 adat a kliens gépéről + só, mint pl.: ip, böngésző neve, OS, etc...
// session lopás miatt raktam ezt bele


Ezenkívül minden db-ből érkezik, így az alap problémát kiváltó okok nem merülnek fel nálam.
21

Session ID

janoszen · Jan. 1. (V), 11.12
Remelem nem a session ID-t generalod igy.
22

dehogy!!!! Vagy ez vicc volt?

Oregon · Jan. 1. (V), 17.19
dehogy!!!! Vagy ez vicc volt?

Ez két változó a session-ben.
23

De miert is?

janoszen · Jan. 2. (H), 12.49
De akkor miert is csinalsz ilyet? Azert, hogy azonositsd hogy ugyanarrol a bongeszorol jon-e? Az IP ugye valtozhat, kulons keppen mobil keszulekeknel amik wifirol mobil halozatra ugranak es vissza. A bongeszo user agent stringje szinten valtozhat ha upgradel. A Chrome pl. silent upgradekkel rendelkezik, eleg idegesito ha emiatt kiloggolodik az ember.

Es mindez hogyan kapcsolodik ahhoz a problemahoz hogy a session-oknek igen komoly problemaja a lockolas szuksegessege?
24

Úgy értem a probléma abból

Oregon · Jan. 2. (H), 13.09
Úgy értem a probléma abból van, hogy változtatható adatokat raksz a session-be. Rosszul értelmeztem?

A második megoldást céges inetrneten logó privát rendszerhez használom és elfogadható az esetleges killoggolás.
25

Nem

janoszen · Jan. 2. (H), 15.36
A problema ket reszbol all:

1. ha ket lekerdezes jon parhuzamosan, lockolas nelkul elveszhetnek a valtozasok, mert a masodik lekerdezes mentese felulirja az elsot.

2. a session nagyon kinalja magat allapot bevezetesehez. Hogy csak egy trivialis peldat mondjak, sokan az arukosarat a sessionbe rakjak, pedig semmi keresnivaloja nincs ott.
26

1. Épp ezért tartom

Oregon · Jan. 2. (H), 18.21
1. Épp ezért tartom minimálisan a sessions-t.
2. Ettől én is kivagyok. Az általam fejlesztett webes alkalmazások akár egy számlázó is, folytatható egy másik gépen ugyanonnan ahol abbahagyta a folyamatot felhasználó.
27

Ilyet ne

lolka_bolka · Jan. 5. (Cs), 15.23
Vagyis bejelentkezéskor szépen betöltjük az egész user objektumot, majd eltároljuk a sessionben. És ha már ott tartunk, az összes megrendelését is.

Ilyet nem csinálunk. Volt erről egy izgalmas thread a stackoverflow-n.

A felhasználó azonosítóját tároljuk el max, és ha kell, akkor példányosítjuk a Usert.
28

Mi akalyoz meg benne?

janoszen · Jan. 17. (K), 14.47
De mi akadalyoz meg benne? Sok fejleszto a legkisebb ellenallas iranyaba megy, es a Session nagyon kis ellenallast nyujt az ellen hogy abban minden szemetet eltaroljunk.