9.15. Session, beléptető rendszer, felhasználó kezelés

Default book

A session magyarul munkamenet. Arra szolgál, hogy a szerveren biztonságosan lehessen a böngésző és a webalkalmazás kapcsolatának állapotát írják le. Ez azt jelenti, hogy egy webalkalmazással végzett műveleteket az alkalmazás lementi a szerveren és a következő oldallekérésekor a korábban lementett adatokat visszatölti a következő oldal hívásakor. Ezt a fajta kapcsolatot állapottartó kapcsolatnak hívjuk.

Eredetileg a cookie-k voltak hivatva ezt a feladatot ellátni, de azokat a böngészőben tároljuk, ami a biztonságot nem szolgálja, továbbá a cookie mérete legfeljebb 4 kbyte lehet.

Jellemzői

  • A szerveren lementett adatok biztonságban vannak, hiszen a böngésző nem éri el azokat közvetlenül, csak a webalkalmazás kódján keresztül ellenőrzött körülmények között

  • A szerveren tárolt adatok mérete (szinte) korlátlan, ugyanakkor minél nagyobb a munkamenettel tárolt adatmennyiség, annál lassabb lesz a következő oldal letöltés ideje, hiszen az adatokat a szerver oldalon be kell tölteni.

  • A munkamenetek "lejárnak", azaz ha a böngésző nem folytatja a munkát a webalkalmazással, akkor a szerveren előre beállított idő múlva érvénytelen lesz a munkamenet és az elmentett adatok elérhetetlenné válnak.

  • A böngésző oldalon csak a session azonosítóját tárolja a webalkalmazás, amely egy véletlenszerűen generált karatersorozat, ilyen módon nem kitalálható.

  • Ha a session lejárt hiába van meg a böngészőben a session azonosító, a session a továbbiakban már nem elérhető.

Milyen adatokat tároljunk?

Tipikusan olyan adatokat érdemes tárolni, amelyek a felhasználó webalkalmazással végzett tevékenységét rögzítik.

  • Ilyen például bejelentkezés után az aktuális felhasználó neve, és a bejelentkezett állapot maga. Amikor kijelentkezik, akkor ezt az állapotot töröljük vagy hamisra állítjuk.
  • Például egy webáruház esetén a kosár tartalma.
  • Egy több oldalas űrlap kitöltése során az addig kitöltött adatok.
  • Egy több oldalas listán azt, hogy éppen melyik oldalt töltöttük le.

Nem szokás olyan adatokat sessionben tárolni, amelyek a szerver oldalon egy adatbázisból kinyerhetők

Működése

  • Amikor a böngésző először hívja meg egy webalkalmazás valamelyik oldalát, akkor a szerver oldalon az alkalmazás ellenőrzi, hogy létezik-e a böngészőhöz tartozó session. Ha nincsen, akkor létrehoz egyet, aminek véletlenszerű nevet ad, például. 5463721fga45ba4.

  • Az alkalmazás lefutása során, de bármilyen egyéb kimenet létrehozása előtt elküld egy session cookie-t a böngészőnek, a fenti név felhasználásával, amit az letárol: sess_5463721fga45ba4. ez a cookie semmi mást nem tartalmaz, mint ezt az azonosítót, tovább azt, hogy a cookie mikor jár le. Minden egyes oldallekéréskor a cookie lejárati ideje meghosszabbodik

  • A szerver oldalon az alkalmazás kódjának lefutása közben létrejönnek a megfelelő adatok, amelyeket a kódnak be kell tenni a $_SESSION tömb megfelelő elemébe. Például: $_SESSION["logged_in"] = True;

  • Többféle adatot, akár egy Objektum pillanatnyi állapotát is le lehet menteni a $_SESSION tömbbe.

  • Amikor az oldal lefut, a szerver az adatokat serializálja, azaz olyan karaktersorozattá alakítja, amely megadott rendben tárolja string formájában az adatokat. A letárolt adatok az alábbiak: Az eltárolt változó neve, típusa, értéke. Ha a változó egy tömb, akkor a tömb elemeinek száma is. Majd a serializált adatokat a PHP motor a beállításaiban megadott könyvtárba menti egy fájlba, amelynek a neve: sess_5463721fga45ba4.  Ez a könyvtár és persze a tartalma nem elérhető az internet felől, csak a PHP motor éri el.

  • A következő oldalletöltésnél a böngésző elküldi a szervernek a session cookie-t, ha az még nem járt le. A PHP megkeresi a szerveren a session cookie tartalma alapján a session fájlt és betölti a memóriába a $_SESSION tömbbe. Az alkalmazás tudja használni a session adatokat, módosíthatja azokat, majd az oldal lefutásával már az új adatokat menti le a szerveren.

Néhány tudnivaló

  • Ha a session cookie a böngészőben lejárt, akkor a böngésző nem küldi el a szervernek, tehát a session nem érhető el.

  • Ha a PHP-ban beállított idő eltelik, akkor a session már nem érhető el még akkor sem, ha esetleg a böngészőben a session cookie tartalmát, lejárati idejét módosítják. A session lejártát úgy állapítja meg a szerver, hogy a session fájl utolsó módosítását nézi meg. Ha azóta eltelt egy bizonyos idő, akkor a sesson érvénytelen lesz.

  • A session cookie lejárati ideje alapértelmezésben 1440 másodperc, amely 24 perc.Ha eddig nem kéri le újból a böngésző az adatokat, akkor a session lejár.

  • Még sessionben sem szabad tárolni jelszót elkódolatlanul! Csak a belépett állapotot szokás tárolni.

  • Alapesetben a session fájlokat a fájlrendszerben tárolja a szerver, de a webalkalmazások létrehozhatnak saját session tárolási rendszert, amely például adatbázisban tárolja a sessionöket. Ehhez csak néhány függvényt kell megalkotni és megadni a PHP-nak, hogy ez az új tárolási mód.

  • A lejárt sessionök fájjljai ott hevernek a szerveren és foglalják a helyet. Éppen ezért a PHP általában minden ezredik hívás után (véletlenszerűen) lefuttat egy szemétszedő algoritmust, amely letörli a szerverről a lejárt sessionok már nem használható fájljait.

Néhány fogalom

Serializálás: Az a művelet, amikor egy változó (tömb) adataiból olyan string jön létre, amelyben letároljuk a tömbelemek neveit, típusait és értékeit. A serializált adatok az unserializálás során visszakapják eredeti állapotukat. A sessionokön kívül is lehet használni ezt az eljárást.

Unserializálás: Visszaállítja a serializált adatokat eredeti állapotukba:

serialize( tetszőleges adat) : string - Ez a függvény a megadott, tetszőleges típusú adatokból serializált stringet hoz létre. Erőforrás típust nem lehet serializálni!

unserialize( serializált adatstring) : változó - Az eredeti adatszerkezetet kapjuk vissza. Ha a string nem olyan szerkezetű, amelyet serializálás során hoztak létre, akkor a visszatérési érték False.

Ha egy objektumot serializálunk, akkor a visszállítás előtt be kell tölteni az objektumnak megfelelő osztály kódját, mert csak akkor ismeri fel a PHP, hogy milyen szerkezetet tároltunk le.

A sessionök automatikusan serializálják az adatokat tárolás előtt és visszaalakítják azokat a következő oldalon a betöltés után.

Sessionökkel végezhető feladatok

session_start() - az oldalon elindítja a session kezelését. A PHP kód vagy a HTML kód bármiféle adatküldése előtt kell ennek az utasításnak lefutnia, mert a szerver oldalról a sesson azonosítót a válasz fejlécében küldi ki (header). Ha a böngésző küldött session cookie-t a PHP-nak, akkor azt a session-t fogja használni, ha ilyen nevű érvényes session létezik a szerveren. Ha nincsen megadott nevű érvényes session vagy már lejárt, akkor új session-t fog létrehozni.

session_write_close() - Ha már az oldalon nincsen szükségünk a session további kezelésére, akkor ez a függvény lezárja a session-t az oldalon. Letárolja az adatokat a session fájlba.

session_destroy() - megszünteti (érvényteleníti) az aktuálisan megnyitott sessiont. Utána már ez a session nem használható a következő oldalon sem.

session_id(): string - visszadja az aktuálisan betöltött session nevét. Csak akkor szokás használni, ha javascript / JAVA /  HTML / segítségével többféle technológiát használunk a webalkalmazáskor. Ezzel lehet például a JAVA kóddal tudatni, hogy éppen mi a session kódja. Használni érdemes akkor is, ha a böngészőben letiltottak mindenféle cookie-t.

Egy beléptető rendszer

Az alábbi minta a tanításom során alkalmazott egyszerű beléptető rendszer. Két fájlból áll:

login.php - ez lépteti be a felhasználót. sikeres belépés után átirányítja a tényleges oldalra

alkalmazas.php - Ez az igazi webalkalmazás...

A felhasználói neveket és a hozzájuk tartozó jelszavakat nyíltan tárolom (ami nem szép dolog), de ez csak egy példa. A login.php tartalmaz egy login függvényt, amely a felhasználó nevét és jelszavát ellenőrzi. Ha az adatokat például egy mysql adatbázisban tároljuk, akkor csak ezt a függvényt kell átírni.

login.php

<?php
// beléptető függvény
function login($n,$p) {
    $tu = array("Pista", "Geza", "Feri", "xxy");
    $tp = array("12345","54321","asdfghjk","xxy");
    $i= 0;
    $db = count( $tu );
    while( $i<$db && $n != $tu[$i] && $p != $tp[$i]){
        $i++;
    }
    Return ($i< $db);
}

session_start();
if(isset($_GET['out'])) session_destroy();

if(isset($_SESSION["belepve"]) && $_SESSION["belepve"]){
   header("location: alkalmazas.php");
   die();
}

if( ( isset($_POST["nev"] ) && isset( $_POST["pwd"] ) ) ) {
    $nev = $_POST["nev"];
    $pwd = $_POST["pwd"];
    $ok  = login($nev,$pwd);
    if($ok){
       $_SESSION["belepve"] = true;
       session_write_close();
       header("location: login.php");
       die();
    }
    $msg = " Próbálkozz mégegyszer, mert hibás a név vagy a jelszó";
}else{
    $nev = "";
    $msg = "Kérem a nevet és a jelszót";
}
?>
<html>
<head></head>
<body>
    <?php print($msg); ?>
    <br>
    <form method="POST">
    <INPUT TYPE="text" NAME="nev" VALUE="<?php print($nev); ?>"><br>
    <INPUT TYPE="password" NAME="pwd"><br>
    <INPUT TYPE="submit"><br>
    </form>
</body>
</html>

alkalmazas.php

<?php
session_start();
if(!(isset($_SESSION["belepve"]) && $_SESSION["belepve"]) ){
    header("location: login.php");
    die();
}
?>
<html>
<head>
</head>
<body>
<?php
print " Happy Sunshine, azt csinálunk, amit akarunk!!!!<br/>";
print "<a href='login.php?out=1' target='_self'>Kilépés</a>";
?>
</body>
</html>

A fenti alkalmazásban nagyon egyszerűen lehet létrehozni a kiléptetés funkciót is, de ez már a tanulók dolga...

Itt lehet megnézni a sessionok kezelésének összes lehetőségét: https://www.php.net/manual/en/book.session.php

Beléptetés két faktoros azonosítással vagy Captcha használatával

A két faktoros azonosítás azt jelenti, hogy a felhasználói név és jelszón kívül egy további adatot is meg kell adnunk a webalkalmazásnak. Ezt a további adatot az alkalmazás véletlenszerűen generálja és küldi el a belépő felhasználónak, akinek az elküldött adatot is be kell vinnie a beléptető űrlapon.

A további adatot más felületre, más eszközre küldi a webalkalmazás. Ilyen lehetőség a mobiltelefonra küldött SMS vagy egy megadott email címre küldött email. Természetesen a szoftver előállításához szükség van egyéb infrastruktúrára is, mint például SMS küldési vagy email küldési lehetőségre is. Különösen az SMS-ek küldése pénzbe kerülhet a szolgáltatónak.

Mi az ilyen beléptetés elméleti alapja?

Először is a felhasználó regisztrációja során létre kell hozni kötelezően a telefonszámot vagy az email címet is a felhasználó adatainak rögzítésekor. Ez az adat egyébként az "elfelejtett jelszó" esetén is jól jön.

A belépéskor a felhasználó elküldi a felhasználói nevet és jelszót, amelyet a szerver oldal leellenőriz hasonlóképpen, mint fent láttuk. Ekkor létrejön a felhasználó azonosítói session, de az állapota még nem belépve, hanem belépésre várva. Pl: $_SESSION['logging'] = 'wait'

Ekkor véletlenszerűen generál az alkalmazás mondjuk egy 6 jegyű számot ( 1 millió lehetőség), amelyet a sessionbe is lement, mondjuk $_SESSION['twofactor'] = mt_rand(100000, 999999);

Ezt a kódot kiküldi emailben vagy SMS-ben a felhasználónak. Erre van néhány ingyenes lehetőség. Ilyen például a https://www.textlocal.in/ oldal. A használata a PHP mail függvényének vagy a curl librarynak a használatát igényli. Regisztrálni kell az SMS küldő platformon felhasználóként, majd a megfelelő, itt nem részletezett kódot használva kell küldeni SMS-t a telefonra.

Az oldal meghívja saját magát a korábban beírt usernév, jelszóval, amit már az űrlapon nem módosítható formában jelenít meg viszont beírhatóvá teszi a two factor kódot.

Leellenőrzi a usernév, jelszó, two factor kódot egyszerre és ennek alapján állítja be a $_SESSION['logging'] = 'logging' állapotot.

További megfontolások:

  • Az első belépési űrlap kitöltése során még nem kell megjeleníteni a two factor lehetőség bevitelét.

  • A session kezelés biztonságosabb á tétele érdekében használjuk az itt található beállításokat: https://www.php.net/manual/en/session.security.ini.php

  • Fontos: A sessionoknak legyen lejárati idejük rövid. Ha a böngészőből kilép, akkor járjon le a session. A sessionok beállításait a ini_set('paraméter', érték); utasítással tudjuk beállítani.

A hozzá szükséges kódot nem fogom tárgyalni, mert ez túllép a jegyzet keretein.