Login rendszer felépítése
Sziasztok!
Régóta próbálkozok egy login rendszer létrehozásával. Olvastam sokat a biztonságról, elméletben ezen részek meg is vannak. A bajom a belépett felhasználó azonosításával, a session/cookie-val van. Sok cikket elolvastam(itt a weblaboron is) azzal kapcsolatban is, de vannak homályok. Reménykedek, hogy itt tudtok segíteni. (Mgj.: Nem vagyok profi, csak hobbi szinten programozgatok).
Én úgy gondoltam, hogy belép a felhasználó, elmentek egy SESSION[] változóban egy adatsort(session_id, ip, user_agent, hoszt...) Majd ezt ellenőrzöm(adatbázis alapján), hogy létezik-e és megfelelő-e az adatsor. Ez ugye akkor szűnik meg, ha kilép a felhasználó, vagy bezárja a böngészőt. Ehhez az kell, hogy minden oldal elején kell indítanom egy session_start()-ot. Ha eddig nagyjából jól gondolkodtam, akkor nem értem minek a cookie? Azt mire használja minden oldal?
■ Régóta próbálkozok egy login rendszer létrehozásával. Olvastam sokat a biztonságról, elméletben ezen részek meg is vannak. A bajom a belépett felhasználó azonosításával, a session/cookie-val van. Sok cikket elolvastam(itt a weblaboron is) azzal kapcsolatban is, de vannak homályok. Reménykedek, hogy itt tudtok segíteni. (Mgj.: Nem vagyok profi, csak hobbi szinten programozgatok).
Én úgy gondoltam, hogy belép a felhasználó, elmentek egy SESSION[] változóban egy adatsort(session_id, ip, user_agent, hoszt...) Majd ezt ellenőrzöm(adatbázis alapján), hogy létezik-e és megfelelő-e az adatsor. Ez ugye akkor szűnik meg, ha kilép a felhasználó, vagy bezárja a böngészőt. Ehhez az kell, hogy minden oldal elején kell indítanom egy session_start()-ot. Ha eddig nagyjából jól gondolkodtam, akkor nem értem minek a cookie? Azt mire használja minden oldal?
Login
1. Felhasználó azonosítása
Az első kérdés amit el kell dönteni az, hogy mi alapján azonosítjuk a felhasználót. Régebbi rendszerek jellemzően numerikus ID-kat (számokat) használnak erre. Ezzel azonban vigyázni kell, mert a számok növekedése árulkodhat arról, hogy milyen ütemben növekszik a felhasználók száma. Ehelyett újabb / nagyobb rendszerek UUID-ket használnak.
Ehhez az azonosítóhoz kötjük a felhasználó metaadatait, pl. usernév, e-mail cím, név, stb. Jellemzően újabb rendszerek többnyire e-mail címhez kötik bejelentkezést, mivel a felhasználónevek elég könnyen tudnak ütközni. Arra érdemes figyelni, hogy az e-mail cím ne "leakeljen", ne lehessen a felhasználó nyilvánosan hozzáférhető adataiból kikövetkeztetni az e-mail címet. Ilyen például a Gravatar használata, ahol az MD5 hash alapján hozzá lehet kötni a felhasználói accounthoz az e-mail címet.
2. Jelszavak
Ahhoz, hogy valaki bejelentkezzen, értelemszerűen szökség van jelszavakra. Itt részletesen leírtam, hogy miért rossz ötlet saját jelszó titkosítást implementálni. Vagyis akármit csinálsz, a jelszavak titkosítása vagy bcrypt, vagy PBKDF-2 legyen. PHP-ban erre vannak a jelszó függvények.
3. Bejelentkezés
Bejelentkezéskor a felhasználó megadja valamilyen egyedi azonosítóját (usernév vagy e-mail cím) és a jelszavát. Ilyenkor a rendszer a beütött jelszót azonos módon titkosítja, és összehasonlítja az eltárolt titkosított jelszóval. Ha azonos, akkor elhisszük a usernek, hogy az akinek mondja magát.
Na most, itt jön az ugró pont. Ha sessionöket használsz, a bejelentkezés hatására generálsz egy új session ID-t (ez fontos), eltárolhatod a user ID-ját sessionben, és ezt felhasználva a további lekérdezéseknél ez alapján azonosítód.
Ezzel azonban több probléma is van, többek között nem tudod a usernek megmondani, hány helyről van bejelentkezve, vagy kiütni a user többi sessionjét. (Mint ahogy a Facebook is csinálja.) Éppen ezért nagyobb projekteknél azt javaslom, hogy user azonosításra teljesen mellőzd a sessionöket. Helyette bejelentkezéskor generálsz egy tokent amit eltárolsz az adatbázisban, és ezt a felhasználónak sütiben adod oda. A további lekérdezéseknél ez alapján nézed meg, hogy milyen felhasználónévhez tartozik a token.
4. Kijelentkezés
Ha sessionöket használsz, nagyon egyszerűen elpusztítod a sessiont és új session ID-t adsz a usernek. Ha tokent használod, törlöd a tokent.
Login Teszt
El is készítettem egy nagyon alap login tesztet, ami nagyjából bemutatja, hogy hogyan működhetne ez a login rendszer: Ez így jónak tűnik? Min kellene javítani? (Mgj.: Ez csak logika)
Hianyzik
Persze
Nem
Ehelyett probalj meg rendes random generatort hasznalni, pl.
mt_rand
vagyopenssl_random_pseudo_bytes
.Ezen felul a tokent nem 60 masodpercre allitanam, mert az eleg gyorsan automatikusan kilepteti a usert.
Valami ilyesmi:
Rendben
Ez lenne az a bizonyos kódolás?
igen
setcookie
Akar...
Nem értem
Miben másabb az, amit leírtál, mint egy saját munkamenetkezelő?
store_token($_POST['username'], $token);
setcookie('authtoken', $token);
store_id($_POST['username'], session_id());
setcookie('PHPSESSID', session_id());
Miért fájdítsa ezzel a fejét egy kezdő? Világos-e mindenki számára, hogy a pecsét ismeretében bárhonnan, akár többszörösen be lehet jelentkezni? A PHP a munkamenethez kínál biztonsági beállításokat, a fenti megoldásodnál viszont nekünk kell ezeket lefejleszteni.
Nem értem..
Türelem
Bocsanat
Szoval, alapvetoen en ugy gondolom, hogy aki sajat login rendszert ir, az nezzen utana hogy mit hogyan csinal. A PHP adta biztonsagi (?) megoldasokra alapozni szerintem nem olyan nyero.
Az, hogy HTTPonly sutiket hasznalsz-e, vagy megengeded-e a login tokenek kozlekedeset IP, bongeszo, stb. kozott az egyedi dontes. Siman lehet olyan helyzet ahol JS-bol is kell matatni a tokeneket.
Ha nekem kellene biztonsagi megoldast epitenem, akkor valoszinuleg a bongeszo tipusat neznem (pl. Chrome, Firefox, stb) es a belepesi orszagot (GeoIP alapon). Ezen felul beallitanam a secure flaget a sutin, mert LetsEncrypt ota nem bocsanatos bun SSL nelkul weboldalt futtatni.
mi biztonságos?
Erre akkor lehet válaszolni, ha meghatározod, hogy számodra mit jelent a biztonság.
Ha azt, hogy "sohasemlehetkijátszani/feltörni/átverni/stb", akkor mondj le a szoftverfejlesztésről, mert olyan nincs. :)
Ha azt szeretnéd, hogy a sütiben tárolt adatodat (token, sessionid, kisnyuszifarka, bármi) a böngésző - jellemzően javascript - ne tudja felhasználni, állítsd be a httponly flaget is rajta.
Ha pl. IP változáskor "kidobod" a user-t, akkor számíthatsz némi reklamációra a mobileszközzel utazóktól (is)...
Mindig alaposan meg kell gondolni az ilyesmit, általában ami biztonsági szempontból kicsit jobb, az user happiness téren sokkal rosszabb.
Nyilván olyat nem szabad megengedni, hogy a Vér Pistike is 2 perc alatt be tudjon jelentkezni a Mariska helyett, de nem is szabad látszólag random (IP changed) okból kidobálni.
User agent: átlagosan havonta 1-2 alkalommal frissülnek a modern böngészők. Ilyenkor ez a string is változik, mégis ugyanaz a böngésző. Emiatt megint (havi 1-2 esetben) indokolatlanul ki tudod dobni user-t, ha teljes egyezőséget vizsgálsz. Nem rossz dolog vizsgálni / ellenőrizni, de pl verzió felfelé növekedést tudni kell kezelni. (Itt feltételeztem, hogy van / lesz "remember me" feature is, a böngészők újraindulnak update-kor.)
Az, hogy session-t használsz-e, vagy mást, a te döntésed kell legyen, mellette és ellene is vannak érvek.
Én azt javaslom, hogy ha már Janoszen ennyi időt áldozott rá(d), hallgass rá. :)
Alap biztonság
Tehát ha van egy ilyen generált token-em. amit elmentek adatbázisba, a megfelelő user mellé, elmentem kliens gépére sütibe. Beállítok pl 30 perc lejárati időt a sütinek(amit minden oldalfrissítéskor újra beállítok), akkor azzal a token-nel, onnantól bárki beléphet. Vagy valamit nagyon rosszul értelmezek? Ha nem, akkor ez ellen mi a teendő?
HTTP
Problema
Egyebkent szerintem a Te celjaidra ez a megoldas tokeletesen elegendo.
User agent: átlagosan havonta
Amit én még ellenőriznék, azok az egyéb HTTP fejlécek, amik ugyancsak a böngésző ujjlenyomatai: Accept, Accept-Encoding, Accept-Language
nem
Nem tudom te mennyit foglalkoztál ezzel a gyakorlatban, de nekem userenként havi 1-2 hiba nagyon sok.
Nem értem
Miert?
Visszatérve
Persze a sok-sok ellenőrzés, adatbázis művelet ebben sincs benne, csak maga a session-user azonosítás. Remélem ez már egy fokkal jobb.
Github