Fórumok
Üdv!
Elnézést, hogy ilyen kezdő kérdést teszek fel, de érdekel a nálam jobban hozzáértők véleménye.
A kérdés egyszerű: hogyan érdemes megoldani beléptetést PHP-val? Egyszerű login, semmi extra dolog.
A kérdés kicsit pontosabban:
1. Hogyan továbbítjuk biztonságosan a begépelt jelszót a szerverre?
2. Érdemes-e a webszerverre bízni (http authentication)?
Hozzászólások
Igazából az egész cucc fejlesztéshez használj egy modern framework-öt és az megoldja. Nem érdemes házilag barkácsolni efféle kényes dolgokat.
Csak egy példa:
http://symfony.com/doc/current/components/security/authentication.html#…
a biztonságos továbbításhoz ott a https .
Igen, ez is egy opció lehetne, hogy az egészet egy meglevő keretrendszerre bíznám, talán (vagy inkább biztos) ez lenne a legegyszerűbb.
Viszont ez a kis egyszerű (legalábbis remélem, hogy egyszerű) projekt a hasznos eszköz szerepen túl némi tanulás szerepet is játszana. Ez az egész projekt elég egyszerű ahhoz, hogy framework nélkül is meg lehessen oldani kevés szívással.
Nem biztos, hogy a Symfony a legjobb megoldás egy ilyen "egyszerű" helyzet kezelésre, van nála pár jóval egyszerűbb framework.
____________________
PasswordBox: http://j.pbox.io/SfFTBEJT | http://szoftvervasarlas.co.hu - szoftverek legjobb áron
A Symfony2 komponensei külön is felhasználhatók, a feladathoz elég lehet a SecurityBundle is.
Először is leszögezném, hogy nincs általános válasz a kérdésedre, viszont van pár alap tipp, amit érdemes megfogadni.
1. Jelszó tárolás
A jelszó tárolás az első kritikus pontja a rendszerednek. Sok féle adatbázisban tudod tárolni a jelszavaidat, lehet az akár LDAP vagy MySQL, sima szövegfájl. Amire figyelni kell, az a jelszavak megfelelő titkosítása. Ez két dologből tevődik össze. Az egyik maga az egyirányú titkosító algoritmus, pl MD5, SHA1, SHA256, Blowfish, etc. Ezek közül olyat érdemes választani, ami lassú és nincs ismert kriptoanalízis rá (tehát az MD5 kiesett). A második fontos pont az úgynevezett sózás. Ez annyit tesz, hogy nem magát a jelszót hash-eled le, hanem hozzáteszel egy felhasználónként egyedi véletlen generált karaktersorozatot, amit plain textben is eltárolsz. Ennek az a célja, hogy megakadályozza a rainbow table jelszótörést arra az esetre, hogy kikerül az adatbázisod.
2. Beléptetés
Amikor belépteted a felhasználót az oldaladra, alapvetően érdemes a HTTP autentikációt elkerülni, mert ez minden egyes lekérdezésre elküldi a jelszót a szervernek. Ehelyett úgynevezett munkamenetet vagy sessiont érdemes használni. A session úgy működik, hogy a szerver oldalon létrehozol egy adatbázis bejegyzést vagy fájlt, amiben eltárolod az adott munkamenethez kapcsolódó adatokat, például azt, hogy be van-e lépve és ha igen, milyen felhasználónéven. Ezek után kiküldesz egy sütit (cookie-t), ami tartalmazza a session azonosítót. Itt érdemes arra figyelni, hogy ha nem létezik a szerver oldalon a felhasználó által küldött munkamenet azonosító, akkor mindenképpen érdemes újat generálni.
Amellett, hogy az adatbázisok használatánál természetesen vigyázni kell az SQL injection kivédésére, fokozottan kell ügyelni az XSS elleni helyes védelemre is, hiszen egy beillesztett JavaScript kóddal a munkamenet azonosító adott esetben könnyen ellopható.
Érdemes arra is figyelni, hogy a beléptető oldalad kizárólag HTTPS-en legyen elérhető és az megfelelően legyen konfigurálva. Ha a teljes oldal HTTPS-en elérhető, érdemes a sütinél a secure jelzőt és a fejlécekben a HSTS fejléceket beállítani. Emellett a sütiknél mindenképpen érdemes használni a httpOnly jelzőt.
3. Hosszú távú bejelentkezés
Ha olyan funkciót szeretnél beépíteni, mint a Facebook, hogy hosszú távon megjegyzi a böngészőt, akkor erre külön adatbázis bejegyzést kell létrehoznod a felhasználóhoz kapcsolva. Amikor az alkalmazásod meglátja ezt az azonosítót és nincs élő munkamenet, akkor megnézheto, hogy az adott kulcs melyik felhasználóhoz tartozik és automatikusan beléptetheti.
4. Véletlen karaktersorozatok generálása
Volt szó sok féle véletlen karaktersorozatról. Itt érdemes vagy a uniqid() függvényt vagy az openssl_random_pseudo_bytes() függvényt használni és a saját hákolásokat elkerülni.
5. Általános jótanácsok
Ha PHP-s alkalmazást gyártasz, érdemes a 10 évvel ezelőtti praktikákat és tévhiedelmeket elfelejteni. Mostanában már egy modern PHP-s alkalmazás OOP szemlélettel épül fel és megfelelően központosítja az adatbázis-kezelést valamint a beléptetést. Ez csökkenti a hibalehetőségeket és növeli a hatékonyságot. Erről bővebben a blogomon olvashatsz.
Remélem, segítettem. Ha valamivel kapcsolatban kérdésed van, állok rendelkezésedre.
--
Pásztor János
Üzemeltető Macik
Óóóóó, nagyon jó összefoglaló! Szerintem a blogodon más érdekes dolog is van, ami engem érdekelhet. Hálás köszönet!
Ha még lesz kérdésem, tuti számíthatsz rá :)
Első kérdésem: ha POST-ot használok jelszó küldésére https-sel, az elegendő pl. biztonság szempontjából? Vagy kell még más, esetleg nem is így érdemes csinálni?
A POST itt viszonylag keveset tesz hozza a dologhoz, bar teny, hogy sokkal szerencsesebb mint az URL-ben elkuldeni. Ha forgalmasabb az oldalad, mindenkeppen erdemes egy csuszoablakos IP limitet is tenni, hogy ne lehessen tobb ezer brute force probalkozast neki kergetni masodpercenkent.
--
Pásztor János
Üzemeltető Macik
Értem. Köszönöm.
Az egyes ponthoz egy rövid kiegészítés: a legbiztosabb, ha használod a PHP 5.5-ben megjelent, de egy compat php fájllal a korábbiakhoz is elérhető password_hash, password_needs_rehash, password_verify függvényeket. Ha terv szerint használod őket (létrehozáskor PASSWORD_DEFAULT-al hash, utána ellenőrzéskor verify és lekérdezed, hogy kell-e rehash, ha igen, akkor újra hasheled és elmented a DB-be), akkor a kódodtól függetlenül is fejlődhet a usereid biztonsága, ha frissítik a PHP verziót. - és ezzel gyakorlatilag mindent megcsináltál, amit janoszen írt az 1-es pontban.
BlackY
--
"en is amikor bejovok dolgozni, nem egy pc-t [..] kapcsolok be, hanem a mainframe-et..." (sj)
Lehet ezeket hasznalni, bar sajnos pont a PHP core fejleszok azok, akik neha kepesek az ilyen dolgokat is elberhelni, lasd amikor megjelentek a filterek, mindenki lengette a ... zaszlot, hogy na ezt kell hasznalni $_GET, $_POST, stb helyett, aztan par honapra ra egy ordas nagy sechole figyelt pont ezekben a fuggvenyekben.
Nekem az a sokeves tapasztalatom, hogy minel kevesebbet hagysz a PHP-ra es minel inkabb kerulod az "egzotikus" funkciokat, annal uzembiztosabb lesz a kodod. Plane, hogy igy jol dokumentalt jelszo hashelesed van, amit adott esetben mas platformrol is tudsz hasznalni, amig mondjuk a PHP-s megoldas eseteben semmilyen garancia nincs arra, hogy "default" algoritmus ugyanaz marad a kovetkezo verzioban.
--
Pásztor János
Üzemeltető Macik
Semmilyen garancia nincs rá, sőt a doksi kifejezetten írja, hogy azt bármikor megváltoztathatják, ha a default már kevésnek bizonyulna. Ha nincs "másik oldal" (más nyelv, amihez crypto algo implementációt kellene keresni, hogy tudja ugyanazokat a hash-eket olvasni), akkor szvsz. ennyi "ismeretlen" belefér abba, hogy a kódomtól függetlenül "magától" javuljon a rendszerem biztonsága.
BlackY
--
"en is amikor bejovok dolgozni, nem egy pc-t [..] kapcsolok be, hanem a mainframe-et..." (sj)
Jól értem, hogy az általad javasolt függvények gyakorlatilag a jelszavak titkosítását csinálják meg? Ha igen, akkor a "bármikor megváltoztathatják" csak okozhat gondot, hiszen a php által titkosított jelszavakat (mondjuk egy) adatbázisban tárolod. Ha változik a titkosító függvény, akkor elég nagy valószínűséggel az adatbázisban tárolt titkosított jelszavak nem fognak stimmelni.
Vagy félreértek valamit?
Hát, ha jól van ez kitalálva, attól ezek a függvények még működni fognak.
Akkor lehet szopás, ha te ezt egy másik alkalmazásodból, nem PHP-val is használnád. S ha egyszer megváltoztatják, akkor mehetsz doksit túrni, meg kódolni, hogy újra működjön minden. Míg, ha magad írod, ilyen gond sosem lesz.
--
blogom
Az ún. Modular Crypt Format-tal tárolják a hash-eket ($$ formában), így mindig lehet róluk tudni, hogy milyen algoritmussal készültek - ez alapján fogja tudni eldönteni a password_needs_rehash is, hogy kell-e újat készíteni (ill. pl. belenézhet, hogy megfelelően sokszor lett-e iterálva az algoritmus etc., de magát az algoritmust ebből nézheti meg).
BlackY
--
"en is amikor bejovok dolgozni, nem egy pc-t [..] kapcsolok be, hanem a mainframe-et..." (sj)
Ezt a doksi leirja? Mert sztem nem, avagy barmikor a nagyhatalmu PHP levlistan ugy gondoljak, akkor megvaltoztatjak a tarolasi formatumot es buktad a kompatibilitast a tobbi programoddal. Nem ez lenne az elso.
--
Pásztor János
Üzemeltető Macik
A crypt()-jük meg MCF.
BlackY
--
"en is amikor bejovok dolgozni, nem egy pc-t [..] kapcsolok be, hanem a mainframe-et..." (sj)
Azt hiszem, érteni vélem :)
Tehát elvileg PHP berkein belül (visszafele) kompatibilis a dolog, gond csak akkor kezdődhet, ha esetleg nem php-val akarod az adatokat kiszedni. Mondjuk ez a veszély (szerintem) nem fenyeget*, de azért biztos, ami biztos, kihagyom ezeket a függvényeket, ha jól értem, azok nélkül is teljesen jól meg lehet oldani.
* Volt azért már pár eset, mikor úgy gondoltam, hogy tuti nem, aztán mégis.
Tehát ha mondjuk van uzsolt felhasználó, aki majd beléphet, választja jelszónak, hogy password, akkor generálok egy karaktersorozatot, mondjuk legyen az, hogy "kutyagumi", akkor a "kutyagumipassword"-ra csinálok egy sha256-ot, és ezt tárolom el mysql-ben. A kutyagumi szót meg kirakom pl. egy uzsolt.salt fájlba, és amikor valaki megpróbálkozik egy jelszóval, eljön a szerverre, elécsapom az uzsolt.salt fájl tartalmát, arra képzem az sha256-ot, és hasonlítom a mysql-ben tárolttal?
Nézd meg a crypt függvény leírását, talán segít jobban megérteni a dolgot! (nem tudom, szokás-e használni, szóval azt nem mondom, hogy használd is...)
Ez a sózás egyébként egy dologra jó ismereteim szerint: ha valaki illetéktelen hozzáfér a kódolt jelszavakat tartalmazó táblát, ne tudja ú.n. szivárványtáblák használatával megtalálni a kódolt jelszó eredetiét.
De a szakértő urak talán tudnak más okot is rá.
janoszen leírásából én is úgy látom, a sózás alapvetően adatbázistábla kikerülésekor jó.
Amennyire értelmezem, a crypt() is kb. ilyesmit csinál, csak amit janoszen is írt, egy picit "aggaszt" (tehát eléggé php-specifikus, tehát az adatbázis ezen részét más nyelven nemigen tudom használni).
Bocs, janoszen hozzászólását nem vettem észre... :)
(a tiéd volt az első hozzászólás a böngészőmben és nem lapoztam feljebb)
Szóval a crypt-nek megvan az az előnye, hogy sok nyelven elérhető (PHP, python, C biztosan, szerintem Java-ban is van megfelelője)
Ja, a crypt akkor multi
platformlanguage? :)Én elsősorban onnan ismerem, hogy man 3 crypt ;)
(java egyébként nem biztos, rákerestem, de nem találtam egyelőre a megfelelőjét)
Hehe... ebből úgy érzem, sok mindenki számára kiderült, hogy nemigen vagyok járatos ezekben. Azért egy apróság még van: ez a sokféle crypt ugyanúgy működik? Tehát a php-s crypt ugyanarra a bemenetre ugyanazt a kimenetet dobja, mint a többi?
Tapasztalataim szerint (PHP-t és pythont próbáltam) igen.
Na, akkor miutan nincs kedvem egyesevel valaszolgatni:
- A PHP crypt implementacioja az alatta levo libeket hasznalja, ergo jol dokumentalt es crossplatform / crosslanguage
- A sot altalaban vagy magaba a jelszo hashbe taroljuk, mint pl a crypt, vagy mellette egy mezobe. Fajlba tarolni folosleges, mert a sok fajl menedzselese problemas lesz. A so mashol tarolasa nem segit sokat, mert elvben ha kikerul a DB-d, akkor minden kikerulhet.
- Egyebkent jol ertetted a lenyeget.
--
Pásztor János
Üzemeltető Macik
Oh, oké. Tehát gyakorlatilag a crypt() függvényt teljesen nyugodtan használhatom. Köszönöm!
Apró észrevétel: a blowfish nem egyirányú.
Fuszenecker_Róbert
Jogos, whirlpoolra gondoltam, csak tulsagosan el voltam foglalva a koncepcio leirasaval.
--
Pásztor János
Üzemeltető Macik
*5, feliratkozom
Rábízhatod az authtot a webszerverre is, és eldöntheted, hogy milyen backendet használsz - htpasswd, ldap, kerberos, mysql, stb.
Ha a PHP nem fér hozzá az auth adatokhoz, akkor nagyobb biztonságban vannak a jelszavak is.
--
PtY - www.onlinedemo.hu, www.westeros.hu
Pont ezt akartam "elkerülni", márhogy "rábízhatom" ("ha rám hallgatsz, akkor úgy csinálod, ahogy jónak látod").
Azt akartam kérdezni, hogy érdemes-e rábízni, milyen előnyökkel illetve hátrányokkal jár. Meg egyáltalán milyen értelmes megoldások vannak.
Előny:
- nem kell bajlódni a kódolással, csak lekérdezed a HTTP usert, és kész vagy, max. az ACL-eket kell kezelned saját db alapján.
- cserélheted a backendet (htpasswd-ről LDAP-ra vagy bármi másra, ahogy szeretnéd 0 kódolással).
- kombinálhatod a backendet autholhatsz több rendszerből is egyszerre pl. LDAP/htpasswd (szintén 0 kódolással).
Hátrány:
- nem lesz szép, egyedi auth formod
--
PtY - www.onlinedemo.hu, www.westeros.hu
Plusz hatrany: a jelszo minden lekeressel utazik a droton.
--
Pásztor János
Üzemeltető Macik
Alapértelmezés: jelszót csak HTTPS alatt. És ebben a tekintetben mindegy, hogy hányszor utazik a dróton.
A PHP oldalnak a jelszót nem kell lekérni (bár komoly hátrány, hogy az adott session-ben a usernév mellett a jelszó is lekérdezhető PHP-ból, de ez a fejlesztő felelőssége.
--
PtY - www.onlinedemo.hu, www.westeros.hu
A PHP akkor is megkapja a jelszot, ergo ha valami inszignifikans oldalon van sechole, akkor is kiolvashato. El lehet donteni hogy melyik a nagyobb riziko.
--
Pásztor János
Üzemeltető Macik
Inszignifikáns oldalon sechole sessionön belül? Ha ilyen van, akkor mindegy, hogy ott-e a jelszó, vagy sem, fel lesz nyomva.
--
PtY - www.onlinedemo.hu, www.westeros.hu
Ezt mar a sechole jellege valogatja. En annak a hive vagyok, hogy lehetoseg szerint minel kevesebbszer menjen at a jelszo a halozaton.
--
Pásztor János
Üzemeltető Macik
Off: Egy mod_auth_form és mod_session_dbd-vel ez nem oldható meg (mmint. hogy "szép" form legyen és csak egyszer utazzon a credential?)
BlackY
--
"en is amikor bejovok dolgozni, nem egy pc-t [..] kapcsolok be, hanem a mainframe-et..." (sj)
Nem tudom, de ezt majd megnézem. A mod_auth_session_dbd jónak tűnhet.
--
PtY - www.onlinedemo.hu, www.westeros.hu
Ennyire azért nem vagyok perfekt, hogy a backend-eket cserélgessem. Egy egyszerű php+mysql okosság lenne az egész, csak kellene egy felhasználónév-jelszó alapú belépés.
[Feliratkozás]