PHP session destroy böngésző bezárásakor

 ( Proci85 | 2019. május 30., csütörtök - 0:15 )

Sziasztok

Mi a legjobb módja egy weboldalból történő user kiléptetésnek, ha szabályos kilépés nélkül csak bezárja a böngészőt?

A net teli van ezzel a kérdéssel és mind arra hivatkozik, amit én is tapasztalok: a szerver oldali php beállítás (session.cookie_lifetime=0) hatástalan.
A megoldások egyik fele elmegy abba az irányba, hogy x percnyi inaktivitás után törölje a sessiont.
A másik irány ajax, javascripttel sűrű keepalive üzenekkel próbálkozik kliens-szerver között.

Az, hogy x percnyi inaktivitás után kiléptesse megoldva. Ez kellően magas, pl. 15 perc, hogy ne zavarja a munkamenetet
Bezárt böngésző esetén viszont nem várhatunk ennyit, kb azonnal ki kell léptetni.

Mi a szakmailag elfogadott, kulturált megoldás?

update jún.4:
Köszönöm az eddigi válaszokat, az ajaxos keepalive megoldást megvizsgáljuk.
Egy olyan irány jutott még eszembe, hogy htaccess+htpasswd, de sql-ből kiszolgálva. Olyat még nem láttam, hogy egy htaccess logint megjegyezzen és beléptessen a böngésző. Böngésző bezárás->nyitás után feldobja az ablakot.
Az így belépett usert php-ból le lehet kérdezni, tehát elvileg csak kicsit kell átírni a login modult és utána ugyanaz minden. (Nem vagok fejlesztő csak jött hozzám ez a probléma, hogy próbáljak megoldást találni rá. Főleg annak fényében, hogy a legelején azt sem tudtuk, hogy hol bukik el a dolog. Most már tudjuk: böngésző túl kényelmes feature)
Láttok ebben valami szakmai ellenérvet?

Hozzászólás megjelenítési lehetőségek

A választott hozzászólás megjelenítési mód a „Beállítás” gombbal rögzíthető.

Session cookie, lejárat nélkül. (Itt nem PHP sessionre kell gondolni hanem HTTP terminológia.) https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies "The cookie created above is a session cookie: it is deleted when the client shuts down, because it didn't specify an Expires or Max-Age directive. However, web browsers may use session restoring, which makes most session cookies permanent, as if the browser was never closed." Mondjuk ez az utóbbi mondat érdekes... És persze ez kliens oldal. Szerver oldalon csak a keepalive marad, mert mi van, ha a kliens lefagy vagy elmegy a net, nem tud szólni.

"A másik irány ajax, javascripttel sűrű keepalive üzenekkel próbálkozik kliens-szerver között."

A Liferay is valahogy így csinálja, ha jókat találtam meg, akkor itt:

https://github.com/liferay/liferay-portal/blob/master/modules/apps/frontend-js/frontend-js-aui-web/src/main/resources/META-INF/resources/liferay/session.js
https://github.com/liferay/liferay-portal/blob/master/portal-web/docroot/html/portal/extend_session.jsp

Kicsire vették (/lehet venni) a session timeout-ot szerver oldalon, és ajax-al behívogatnak, ami miatt újra indul szerver oldalon a timeout számolása. (ha be van az auto extend kapcsolva, ha jól emlékszem.)

> Kicsire vették (/lehet venni) a session timeout-ot szerver oldalon, és ajax-al behívogatnak, ami miatt újra indul szerver oldalon a timeout számolása.

Nekem ez tűnik a legjobb megoldásnak!
PHP-ban ezek a beállítási opciók lehetnek érdekesek:
session.gc_probability "1" PHP_INI_ALL
session.gc_divisor "100" PHP_INI_ALL
session.gc_maxlifetime "1440" PHP_INI_ALL

Meg van azzal tekerve, h a szerveren nem minden kéréskor történik meg a lejárt session fájlok törlése, csak akkor ha elindul a törlési mechanizmus is. Én most nem értem, h csak kéréskor indul/vagy épp nem indul ez el - aktuális beállítástól függően, vagy cronból is lefut időnként? És mi történik akkor, ha van egy az idő szerint lejárt session fájl ami még nem törlődött (a fenti beállítások miatt) és beesik egy kérés ami rá vonatkozik - ez esetben úgy fog viselkedni a program mintha ott sem lenne a fájl? Mert ha úgy viselkedik, akkor a törlés tulképp csak egy másodlagos dolog, pusztán arra van h ne halmozódjon fel a rengeteg fájl, de a program lefutását a lejárt session fájlok megléte nem befolyásolja, mert arra csak kizárólag (gondolom) a fájl atime ideje van kihatással. Ezt nem ártana tisztázni! Szóval elképzelhető, h a topiknyitó által tapasztalt session fájl nem törlődések nem azt jelentik feltétlenül, h az adott session még él.

"nem azt jelentik feltétlenül, h az adott session még él."

Sajnos de. Egy loginnal ellátott felületen belül vagyok, böngésző bezárása->megnyitása után is. A sessiont tartja. Ezt csak akkor, amikor a böngészőben be van kapcsolva, hogy "előző munkamenet folytatása".
Teszteltem egy sima drupallal is (nem hup) és az sem léptet ki. Tehát a jelenség nagyon is valós, a net tele van ezzel a problémával (drupal fóruma is). Tehát amióta ilyen kényelmesek lettek a böngészők, igény volna a kivédésre, de mindenféle workaround van csak.

Kicsit elbeszélünk egymás mellett.
De a lényeg, h olyan jellegű megoldás amit szeretnél valószínűleg nem létezik. Szerintem két perces szerveroldali session lifetime + az oldalon lefuttó js kód ami 20 másodpercenként egy háttérben történő kéréssel megújítja szerveroldali idő számolását bőven az elfogadható határon belül van az adott problémára vonatkozóan. Ennek eredménye képen a böngésző bezárását követő két percen túl elvileg nem lehet visszaszerezni a sessiont.

"+ az oldalon lefuttó js kód ami 20 másodpercenként egy háttérben történő kéréssel megújítja szerveroldali idő számolását"

Igen, valami ilyesmi irányba megyünk el szerintem. Köszönöm az ötleteket.

Ha túl nagyra veszed a szerver oldali timeoutot, akkor kb. fölösleges a kliens oldalról pingelni, legalábbis sűrűn, elég akár 10 percenként is.

Ha túl kicsire a szerver oldali timeoutot, akkor meg sokat fognak szidni, amikor pl. 20 másodperces timeout esetén 21 másodpercre elmegy a net vagy elalszik a gép vagy csak háttérbe kerül az oldal és a böngésző energiamegtakarításból ritkábban futtatja az oldal kódját.

Valahol közép esetben meg ugyanott vagy, ahol indultál: ha egy szarul konfigurált böngészőt bezárnak, és megint megnyitnak, akkor megmarad a session.

"elég akár 10 percenként is."

Nem lehet, ha bezárom, pár másodperc eltelik, megnyitom, ki kell vágnia. Ezért ha ezt választják, akkor 2-3 másodpercenként kell egy keepalive a klienstől a szerver felé.

"amikor pl. 20 másodperces timeout esetén 21 másodpercre elmegy a net vagy elalszik a gép vagy csak háttérbe kerül az oldal és a böngésző energiamegtakarításból ritkábban futtatja az oldal kódját."

Az nem hiszem, hogy baj. Ha akadozik a net, az alkalmazott technológia korláton kívül van. Az elalvó gépre tök jogos, hogy kilépteti, mivel otthagyta a gépét. A felvetés egyébként tovább gondolandó. Nincs standby beállítva, otthagyja a gépét és nem lép ki, de nem csinál semmit az oldalon. Akkor is kiléptesse-e? Fel sem merem tenni a megrendelőnek ezt a kérdést :)
Erre lehet jó a topikban említett esemény vezérelt session megújítás. Minden leütést, kattintást js-ből érzékel, ha jól értetem és szintén megújítja a session time-ot.

A háttérbe tett oldal viszont egy megvizsálandó kérdés. Szerintem a js akkor is lefut. Gondolok a Roundcube webmailre, ami a háttérben is nézi a leveleimet.

Lehet hogy valamit félreértek, de ha a szerver oldalon végetért a session, mert szerver oldali timeout volt, azaz timout időn belül nem érkezett újabb request, akkor kliens oldalon hiába tart valami session id-t a böngésző, mert az már lejárt szerver oldalon. De PHP-val nem tudom, hogy mik a lehetőségek, hogyan állíthatod be a szerver oldali timeout-ot.

Esetleg még a login oldal indíthat azzal, hogy törli a cookiet.

2 dolog van:
- szerver oldali timeout, ami viszonylagas magas kell legyen, mivel tartalmat töltenek fel, cikket írnak. Legyen mondjuk 15 és 40 perc között. Egyelőre nem meghatározott. De lehet 1 perc is, az is túl nagy már mert:
- van egy olyan igény, hogy ha bezárom a böngészőt, akkor ne tudjak login nélkül visszalépni. Ez egy jogos igény, és ezt nem olyan könnyű teljesíteni mióta a böngészők elmentenek valamit. Timeouton belül röhögve folytatják a sessiont.

Az utóbbira van konkrét php ini beállítás, de mióta a böngészők ezt a kényelmi szolgáltatást nyújtják, teljesen hasztalan, semmit sem ér.

; Lifetime in seconds of cookie or, if 0, until browser is restarted.
; http://php.net/session.cookie-lifetime
session.cookie_lifetime = 0

"de mióta a böngészők ezt a kényelmi szolgáltatást nyújtják, teljesen hasztalan, semmit sem ér."

A böngésző hiába próbál bármit is megtartani a session-ből, hiába örzi meg a session id-t, ha az a session szerver oldalon el van dobva.

A szerver oldali sessiont (aminek rövid timeoutja lehet) pedig életben tudod tartani ajax requestekkel,ahogy pl a Liferay is a fenti példában.

De a meglévő session kezelést is kiegészítheted saját cookie-val, ami alapján eldöntheted szerver oldalon, hogy egy valid munkamenethez érkezett request, vagy valaki újra nyitotta a böngészőt.

> ha bezárom a böngészőt, akkor ne tudjak login nélkül visszalépni

- És ha csak a tabot zárod be, nem a böngészőt?
- Vagy ha két tab van, de csak egyet zársz be?

Vagy mondok jobbat, mobilon:
- Ha tabot váltasz? (általában csak egy tabot lát a user)
- Ha home gombbal eltüntetem a böngészőt, de valójában nem zárja be a user?

> de ha a szerver oldalon végetért a session

Ez a "végetérés" h történik pontosan? Mi a döntő: session fájl megléte vagy az utsó hozzáférési idő?

Sajnos a PHP-t nem ismerem, ezt írtam is. Java alatt pl. be van állítva egy timeout (szerver oldal), ha az lejár, mert nem volt request, akkor törlődnek a szerver oldali sessionből az adatok+lefut egy listener ha csináltál. Csak feltételezem, hogy ennek/hasonlónak kell történnie mindenhol.

Mi az igazi probléma? Vagyis milyen gondot okoz, ha a serveren a session túléli a klienst (és valamilyen inactivity timeout után zárodik le)?

Biztonsági kockázat és az oldal biztonsági besorolása nem engedi meg.

Esetleg nézz rá az "onunload" JavaScript eseményre: https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onunload

Ezzel küldhetsz egy "mondjátok meg a komisszárnak Szemipalatyinszkban, hogy törölje a sessionömet..." jellegű üzenetet, amikor a böngésző kinyírja az ablakot.

"beforeunload" is létezik, nekem ezt sikerült használnom hasonlóra, de nem tud 100% megbízhatósággal működni. Arra jó, hogy többnyire időben ki tudjuk dobálni a page-hez tartozó adatokat. Egyébként ki kell várni az inaktivitás timeout-ot.

Ez ugye nem session-höz tartozik, hanem egy folyamatában megjelenített oldalhoz, amihez szerveroldali app megvalósítás esetén tartozik egy szerver oldali objektum.

Ha bezárja a böngészőt elveszlik a session, legalábbis nálam újból be kell lépnie.
Az user osztályba pedig csak annyi van, hogy megnézi van-e user session és ha nincs akkor a loginscreen-re viszi.

pch
--
SB-soft online ügyviteli rendszer
--

Konkrétan a session fájl sem törlődik a szerveren a session tmp dirben. Újranyitás után vígan használja.

A következők lehetnek: 1. maradt még böngészőablak nyitva, tehát seseion-cookie nem törlödött. 2. A session-cookie nem session-cookie volt. 3. A session-cookie tényleg session-cookie volt, de a böngésző segítő szándékkal meghosszabbította az élettartamát.

És a session ID cookie-ban van? Ha igen, akkor olyanra kell beállítani a cookie-t, ami törlődik, ha kilépsz. Vagy nem adsz meg lejáratot a cookie-ban, vagy üres string-et adsz meg, nem tudom melyik.

Szerk. 1: De a böngészőben nézd meg, hogy milyen jött létre, és ne legyen benne expires
Szerk. 2: Chrome-ban megnéztem egyet, ezt kell hogy kiírja:

Lejár
Amikor a böngészési programfolyamat véget ér

Még egy megjegyzés: Nem tudom a PHP hogy intézi, de ettől még megmarad a szerver oldalon a session, a szerver oldalon beállított timeout-ig.

Most teszteltük. Ha firefoxban be van kapcsolva, hogy "előző munkamenet folytatása", akkor él a probléma.
Bezárom a tabot, majd bezárom a böngészőt. Megnyitom a böngészőt, megnyitom az url-t és ott van a korábban elmentett session tartalma.
Ez csak akkor működik, ha ez a funkció be van kapcsolva. Úgy néz ki, hogy a látogatott, de bezárt lapokat is elmenti bezáráskor. Ez ellen pedig szerver oldalon muszáj védekezni.

.

Ha ennyire para, akkor nyiss js-ből websocketet a szerver felé. Amikor megszakad a kapcsolat a szerver és kliens között, akkor ott lefuthat egy destroy eljárás a session-on.

nemjo. ket tabon van nyitva a site, miutan kiolvasta az user az egyiket, bezarja. es folytatja a masik tab olvasasaval, 2 perc mulva lepne tovabb de mar logoutolt a site.

--
A vegtelen ciklus is vegeter egyszer, csak kelloen eros hardver kell hozza!

A szerver oldalon eldöntöd, hogy az adott sessionhoz hány nyitott aktív tab van (2 socket egy session). Amíg van aktív tab, addig nem destroy.

Aztán ha egy pillanatra kihagy pl. a wifi, akkor lesz nagy öröm... Persze ha nem létező problémát akarunk megoldani erőből, árral szemben, akkor vannak ilyen járulékos károk :).

de ez most miért nem létező probléma?
Vegyünk pl. egy netcafét preparált böngészőkkel!

Incognito. De vegyünk egy netcafét preparált keyloggerrel akkor már.

Szerintem ez egy valós probléma. Elképzelhető olyan szituáció amikor ezzel vissza lehet élni. Sajnálatosan csak elég gány megoldások merülnek fel bennem a dolog ellen.

Netkávézókhoz minden böngésző támogat valami privacy.sanitize.sanitizeOnShutdown-szerűséget (ez ugye FX, de IE/Edge-re és Chrome-ra is van hasonló)

BlackY
--
"en is amikor bejovok dolgozni, nem egy pc-t [..] kapcsolok be, hanem a mainframe-et..." (sj)

A probléma szerintem meg van oldva, úgy hívják, hogy session cookie. Pont arra lett kitalálva, hogy ha bezárod a böngészőt, akkor eldobódik, és szerver oldalon timeout után ki lehet dobni. Kliens oldalon meg lehet spékelni egy timeout időzítő kijelzéssel. Ha ezek után valaki olyan böngészőt használ, ami a session cookie-t nem dobja el, az magára vessen. Ez nem egy szerver oldali probléma.

Erre tökéletes megoldás úgysem lesz. Bármit találsz ki, egy leleményes user (akit zavarnak a hülye korlátozások) vagy egy gonosz user (aki direkt vissza akar élni a szuperbiztos rendszerrel) vagy egy béna user (aki pl. be van lépve a böngészőben és unlock nélkül elhagyja a telefonját/laptopját) könnyedén meg tudja kerülni. Vagy ha túl jól sikerül, akkor a jóindulatú ártatlan userekkel is ki fogsz szúrni. Ebből csak tákolás meg széllel szemben hugyozás lesz.

Ez egy olyan helyzet, amikor el kell magyarázni az ügyfélnek, hogy szép gondolat volt, de sajnos a világ másfele megy, értelmetlen evvel túl sokat görcsölni, ettől hasznosabb dolgokkal is lehetne foglalkozni.

+1
Ez történik, amikor laikusok fújják a passzátszelet... Ennek a programozós megoldása egy piros felirat a képernyő tetején: "A [kijelentjezés] gomb nemhasználata biztonsági gondokhoz vezethet (éppúgy mint pl. a lezáratlanul magára hagyott készülék). Ezekért a gondokért önt fogják hibáztatni."

Elég ritkán látni ilyet :-)

Minden, adott session sütivel érkező kérés a szerveren növelje meg a session lejáratát 1-2-5-valamennyi perccel, ami mindenképp legyen nagyobb, mint az oldalon kattintás nélkül átlagosan eltelt idő.
Kitöltős formok/adatbevitel esetén ezt tessék megspékelni némi OnChange() eseményre aggatott lejáratnöveléssel.

Az lehet még megoldás, ha nem csak a session id-t követed, hanem minden page-nek generálsz egy azonosítót (ez amúgy is tipikus ilyen rendszereknék), és nem session-ben követed a bejelentkezési állapotot, hanem a page-hez kötve. Lényegében egy saját session implementációt csinálsz, aminke a tokenje JS-ben utazik a szerver és a kliens között.

Ebből az is következik persze, hogy nem lehet új lapot nyitni, és ott továbbra is bejelentkezve maradni, hanem minden lapnyitásba be kell jelentkezni. Vagy esetleg külön kezelni azt, hogy az oldalon lévő linkekben van egy egyszer használatos kód - amit klikkre generálsz, és annak segítségével hozzákötöd az eredeti session-höz az új lapnyitást.

Jó bonyolult, kiváló házi feladat annak, aki szopatni akarja magát :-)

JWT erre van, igaz SPA-khoz, amik nem töltik újra az oldalt. Eleve sessionstorageba kell menteni a tokent, amit szerintem töröl a böngésző, de ha azt sem törli, akkor is könnyebb a server oldalon a tokent invalidnak venni.