PHP přihlašování

Ahoj,
chci udělat přihlašování pořádně a nevím, jak to udělat nejlíp :-)
Většinou používám HTTP autentizaci (WWW-Authenticate: Basic), protože je to asi nejrychlejší a nejjednodušší na implementaci. Ale používám to jen v základní podobě, a tudíž to má mouchy s bezpečností (heslo v plaintextu) a s odhlašováním (rozumně to imho nejde).
Koukal jsem na digest verzi, ale ta imho neřeší problém s odhlašováním, je na první i druhý pohled relativně komplikovaná, a navíc nemá tak dobrou podporu v prohlížečích (a v PHP koneckonců také ne, je k tomu potřeba tuším aspoň PHP 5.1).
Koukal jsem na variantu s cookies, ale tam je bezpečností problém imho stejný. Navíc je to imho trochu chození s komárem na velblouda, když potřebuju akorát to přihlašování - za cenu možných sekundárních problémů, např. na WZ průběžně docházející místo pro ukládání session proměnných, nebo nutnost použití cookies, popřípadě použít ošklivé URL obsahující SSID.
Apačí autentikace mi připadá zastaralá a nepružná, nikdy jsem nenašel odvahu to zkusit a moc o tom nevím, můžete mi někdo napsat, jestli to má smysl, pokud s tím máte zkušenost.
Z výše uvedeného mi vyplývá, že se mi asi nejvíc chce zůstat u WWW-Authenticate: Basic, akorát k tomu dořešit ty mouchy.
Tu bezpečnost by imho mělo dostatečně řešit použití HTTPS, je to tak nebo se pletu? Pač https je k dispozici na každym rohu, pokud člověku nevaděj ty hlášky o nedůvěryhodnosti - ale stejně v tý aplikaci budu přenášet i jiný důvěrný údaje, takže stejně s nasazením https počítám (o jiné rozumné variantě nevím).
Na odhlašování jsem teď v Koskovi našel trik s generováním unikátního realm pro každé přihlášení a jeho změnou při odhlášení - máte s tím někdo zkušenost? Funguje to dobře, nebo je to taky nějaká pakárna? Teď na to používám různá kouzla s posíláním HTTP 401, ale pořád to blbne, nevychytal jsem to natolik aby to dobře a pohodlně fungovalo i vypadalo.

Děkuji předem za libovolné komentáře, čím konstruktivnější, tím víc děkuji.
edit: "Koukal jsem na variantu s cookies" má být samozřejmě "Koukal jsem na variantu se sessions"
Přidám svou trošku do mlýna.

Na zabezpečení přenášených údajů by mělo stačit https - z klasicky ochytaných packetů (pokud se nepodvrhne certifikát) žádné (posílané) informace získat nelze -- alespoň já to takto řeším.

Přihlášení řeším (vymyslel jsem si ho pár let zpátky sám, možná bude mít nějaké mouchy :) s pomocí náhodně generovaného stringu. Pro každé přihlášení vygeneruju náhodný string (anglická abeceda a čísla) délky X znaků a uložím čas posledního přístupu (timestamp). Potom do cookie/session (kterou držím celou dobu během ůpřihlášení) uložím ten náhodně generovaný (a uložený) string a doplním jej o hash nějakého UID (jména uživatele, e-mailu nebo prostého identifikačního čísla).
Při každém přístupu ke stránce (od uživatele) potom kontroluju přítomnost cookie, obsah rozdělím na 2 části a kontroluju, jestli odpovídá náhodně generovaný string a hash UID. Pokud odpovídá (tedy souhlasí), tak upravím uložený čas posledního přístupu.
Při odhlášení smažu cookie a vymažu náhodný řetězec - nebo jej přepíšu tak, ať mu nemůže odpovídat obsah cookie.

Délka X je pevně zvolená, ale v praxi je jedno jaká.

___
Možná to není úplně dokonalé, ale už to pár let u jednoho trochu systému s přihláškama používám.
Hm, to je celkem pěkný, je to ála sessions řešení ale bez nutnosti tam použít celej sessions mechanismus - vlastně si to co je z toho pro tenhle účel potřeba děláš ručně... Nicméně i tak to má pořád ten drawback, že jsou k tomu potřeba cookies (nebo ošklivé a nebezpečné url). Ale mimoto je to hezké řešení:-) Není to to dělání kanónu z vrabce, o kterém jsem mluvil v souvislosti se sessions. Vcelku stačí tam prostě vrazit nějakej random (třebas md5) hash, kterej se uloží do databáze - a začíná se to podezřele podpobat SESSID ;-)

A doufám že to https je prostě postačující odpověď na technologické bezpečnostní problémy ohledně odposlechu informací po cestě. I takové to nedůvěryhodné co člověk dostane zadarmo s hostingem (nesedí CA ani jméno serveru) - pro účely šifrování komunikace imho nezáleží na tom, jestli je to důvěryhodný certifikát, ne?
Pro účely šifrování by to vadit nemělo. Jen musíš donutit prohlížeč certifikát použít (některé prohlížeče jsou schopné "nedůvěryhodné" certifikáty ignorovat a posílat plaintext). Tedy zakázat přístup přes klasické http (neboli všechno směrovat na https).

Jinak ke způsobu přihlašování mě ještě napadá provázat celý obsah formulářema.. tedy všechny odkazy uvnitř stránky dělat jako formulářové submity a posílat parametry (včetně všech uživatelských údajů) POSTem. Tím se zbavíš i cookies i parametrů v url. Ale... na přesměrování mezi stránkama uvnitř systému už nebude stačit "header('Location:');", horší reloady stránek apod.

A ještě další možností je použití AJAXu - používají jej například internetová bankovnictví několika českých (určitě i zahraničních) bank. V praxi pak provedeš všechno jako jedno přihlášení a všechny další údaje posíláš na server POSTem skrz AJAXem. Ovšem i toto má své mouchy - musíš zobrazovat čekání na odpověď (a v průběhu znemožnit clicky na ostatní prvky stránky), reload stránky pro uživatele nemožný apod. Pokud ale nechceš cookie ani url, je to asi nejlepší volba ;)
Varianta session bez sessionu je dobrý nápad a taky mně to napadlo. Řešení drawbacku se dá v tomto také vyřešit, ale nebude to úplně košer. Jde o to, že v podstatě uživatel a prohlížeč jsou svým způsobem unikátní. Takže by stačilo zjístit od uživatele informace odlišních od ostatních a vytvořit z něj otisk. Jde především o IP adresu, podpis prohlížeče a případně dalších. Šance, že by dva měli stejné parametry je malá.
Ovšem říkal jsem, že to není úplně ono. Hlavičky se dají změnit a neřeší to problém s NATem. Příkladem jsou fíremní nebo úřední síťě. Používají v podstatě identické počítače a jsou propojeny s vnitřní síti, takže z venku se tváří jako jeden.
Kromě HTTP autentizaci pomoci digestu (heslo posílá šifrovaně) je druhou nejlepší variantou použít session. Nejlépe se zákazáným posíláním SESSID přes url, kvůli odposlechu. Session v sobě obsahuje unikátní otisk platný pouze pro daný prohlížeč a času, takže útočník jej nemůže použít.

Posilání plain hesla přes síť, by se dal vyřešit jako u digestu. Prostě se před odesláním zašifruje. V tomto případě pomoci javascriptu. Můžeš to okořenit o použití klíče, takže při šlohnutí by bylo šifrované heslo bez klíče k ničemu.
Tomík: Šifrováním u uživatele bez použití kliče se dostáváš tam, kde jsi s plaintextovým heslem -- problém potom není zjisit heslo, ale zjistit odesílanou (šifrovanou) informaci ;)

Tedy šifrování u uživatele klidně, ale jedině s použitím klíčů (ale jak říká klasik "za hodně peněz, málo muziky")..
Všechno směrovat na https bude asi nejjednodušší přes $_SERVER['HTTPS'] a Location; zkoušel jsem to přes mod_rewrite ale furt to řve že je tam nekonečný přesměrovávání...
To s těma formulářema neni úplně blbej nápad, vzhledem k povaze toho, co chci dělat, by to možná šlo :-) Díky, zkusím to :-)
AJAX je fajn, ale je to ještě větší kanón na vrabce než sessions...
Pokud to nebude ono, tak mi asi nezbyde než použít cookies.
Unikátnost uživatele má přesně ty problémy, které píšeš - jednak firmy, školy a podobné věci, a jednak možnost falšování těchto údajů.
Digest: opět problém s odhlašováním, jinak bych to překous.
SESSID se dá posílat i v URL, ale pak je nutné ho pro jistotu po každém requestu měnit - což jako sideeffect znemožňuje otevření více tabů z jedné stránky. Ale jako nouzová varianta pro prohlížeče s vypnutými cookies se to asi dá použít...
Šifrovat heslo u uživatele by šlo, ale co z toho? Musím pak stejně nějak při každém requestu ověřovat, že je to zrovna tenhle uživatel. Tzn. uložit si do cookies nějaké SESSID či tak něco - a už zase potřebuju použít https, jinak je to na houby - a tím pádem použiju https rovnou a nemusím to heslo šifrovat javascriptem...
S nekonečným přesměrováním na https jsem se také setkal. Problém dělá právě $_SERVER['HTTPS']. I když je https povolen, tak tato proměnna nemusí existovat. Jedním řešením je tvrdé přesměrování. Pokud příjde požadavek na http, tak server požadavek automaticky přesměruje na https.
session + https mi prijde jako jednoducha varianta
v konfiguraci si povol transitid nebo, jak se to jmenuje, aby ti automaticky pridaval k odkazum a formularum session id.

slozitejsi varianta je pouzit vlastni sifrovany prenos, kdy https pouzijes jen na prihlasovani a vlastni data uz odesilas unikatnim klicem a algoritmem sifrovana. cili, i kdyby je nekdo zcizil, tak vidi houbec. musel by zcizit session, kde bude v promenne dekodovaci klic k datum. Posilani provadis pres ajax a desifrovani pres js, heslo vytahnes z cookies (session). Cili potrebujes mit povolene kukiny.
A nebo to jeste muzes propojit s https, dvoji sifrovani.

HTTP autentizace - se jevi jako bezpecna, ale ty jsi prihlaseny na cookies a i kdyz spadne server, stale ses prihlasenej. Hlavne IE ma s odhlasovanim problemy :) (dokud nezavres posledni okno, tak jsi stale prihlasen). V ostatnich prohlizecich se to da vyresit tim, ze se prihlasis jakoby na neexistujiciho uzivatele a heslo.
Tomík: no právě mě překvapilo, že když jsem si dumpnul $_SERVER, tak tam byla, při http byla prázdná (ale byla tam) a při https tam měla "on"! Ale stejně to někde zgychalo... Ale šak ono se to podá.

peta:
Leccos je jednoduché, ale tohle by mělo fungovat za co nejširších podmínek, bezpečně a kvalitně. Takže pro https už jsem pevně rozhodnutý, a způsob přihlášení ještě dorozhodnu.
SESSID v url je security leak jako kráva, to tě pak nezachrání ani použití https. Má to tu zajímavou vlastnost, že se to dá hacknout i nechtěně :-) (Už párkrát mi někdo poslal link, ve kterym bylo jeho SESSID, no tak jsem na to klik a rázem jsem byl přihlášenej jako on :-D). Neznám na to jiné řešení než jednorázová SESSID, což má zase jako nevýhodu nemožnost práce ve více oknech/tabech.
Vlastní šifrování je dělání komára z velblouda, proč se s tím srát sám když máme https. Navíc se mi nezdá "heslo vytahnes z cookies", to jsem nějak nepochopil - cookies přece letěj normálně textově s tim requestem...
HTTP autentizace má jako zásadní problém odhlašování, to už jsem psal, jinak bych neváhal a použil ji, pač je to imho nejjednodušší. Ale s cookies to nesouvisí, to se pleteš, naopak to funguje i bez cookies.
R.U.R.: Ani jednorázová SESSID není řešením. Pokud by totiž uživatel někomu poslal odkaz, co má na stránce a ještě na něj nekliknul, přihlášený najednou bude někdo jiný. To taky není zrovna bezpečné.

peta: SESSID v url má navíc tu vlastnost, že se ukládá v prohlížeči (který ji pak nabízí jako navštivenou stránku). A pokud se uživatel neodhlásí (ve výsledku nezmění SESSID), tak se za něj můžou "přihlásit" i jiní uživatele jeho PC.

peta: Šiforvání s klíči je dobré, ale musíš ten klíč nějak doručit. Pokud uživateli pošleš klič zároveň se šifrovanými daty, tak to je lepší šifrování zrušit úplně. Klič bys musel uložit třeba v den registrace do cookie, a až by cookie nebyla (smazána, jiný prohlížeč) uložit novou. Ale i tak je to zbytečně pracné a výsledek nebude adekvátní námaze..

R.U.R.: Odhlašování při HTTP autentizaci lze teoreticky řešit (i když není dobře jasné, jestli funguje úplně všude) a to s pomocí AJAXu - v metodě open existují totiž i parametry user a password (4. a 5. parametr):
xmlhttprequest.open("GET", './skript.php', true, 'jméno', 'heslo');
A pokud se toto použije s jiným jménem (a místo hesla třeba mezera) než je aktuálně člověk přihlášen, tak by jej to mělo "odhlásit".
Freeze: no vida, tahle díra mě nenapadla; málokdy někdo posílá adresu odjinud než z adressbaru, ale ta možnost tu samozřejmě je

Freeze: to jsem nevěděl, zkusim jestli to k něčemu bude dobrý (i když se spíš obávám že ne)
R.U.R.: Nejlepší způsob přihlašování je tenhle: http://nettephp.com/cs/nette-web-user
hm, hezký, podívám se :-)
R.U.R. (jsrosa.wz.cz) - pokud nedas do url session id nebude ti to bez JS/ cookies fungovat. On si prohlizec to sessionid musi nekde ulozit a prave cookies jsou to misto. Pokud nekdo ma zvysene zabbezpeceni, tak ti napise mail, ze mu tva stranka nefunguje a ze si rusi u tebe ucet a chce zpet penize.

Uz jsem psal, do session uloz kod zalozeny na ip a nejakych dalsich udajich o uzivateli. Pokud udaje nesedi, odhlas ho nebo mu nedovol pristup. Pak nezalezi na tom, co je v url.
Treba, podari se ti zjistit uzivatelovu ip, podari se ti zjistit prohlizec, datum posledni prace<5min... , pokud ne, ma uzivatel smulu a na jeho session se muze prihlasit kdokoliv.
Pokud tam das ten datum a uzivatel odbehne od pc, muzes zarucit, ze do 5 min se stava jeho session neplatna i pres to, ze mas server nastaven jinak. Ostatne ten cas muzes uzivateli nechat nastavovat.
Nejjednodussi hackovani probiha prave tak, ze uzivatel odbehne od pocitace.
Doprdele čti sakra než něco napíšeš, odmítám odpovídat na ten první odstavec.

IP apod. do toho zakomponovat, to je sice zvýšení zabezpečení, ale ne řádové, pořád to neni nic moc. Představ si školu, tam typicky tyhle údaje budou všechny stejný, a lidi si tam s velkou pravděpodobností budou posílat odkazy mezi sebou navzájem. Už se to tu (= v tomhle tématu) taky řešilo, i když možná ne přesně v těchhle souvislostech.

"Pokud tam das ten datum a uzivatel odbehne od pc, muzes zarucit, ze do 5 min se stava jeho session neplatna"
To je hezký upsání se :-)) Ale jinak ano, timelimit po kterym vyprší platnost přihlášení je samozřejmě vhodný a pochopitelně tam bude taky. Ale to zase nezvyšuje bezpečnost řádově, je to spíš takový něco navíc - už proto, že nemůžeš nijak poznat okamžik, kdy ten člověk od toho počítače odběh. Když dáš timelimit krátkej, bude ho to furt odhlašovat a bude ho to srát. A když dlouhej, tak odběhne a ostatní budou mít móře času se mu v tom vrtat.
Jak to tak pozoruju, tak to přeháníš. Základ "rozumně" bezpečného přihlašování je asi takovýhle:
1) SESSID ukládat pouze do cookies
2) odhlašovat automaticky (podle toho. co přijde dřív):
2a) po uplynutí nastavené doby
2b) po zavření prohlížeče
3) odstranění všech děr v aplikaci
Pokud to nemáš na nějaký obrovský projekt, tak to bohatě stačí. Dokonalé přihlašování neexistuje a dokud bude lidstvo existovat tak ani existovat nebude, protože lidi jsou hovada a vždy je nějaká pravděpodobnost že se najde nějaký blbec který si svým chováním nechá účet nabourat:
a) nastaví si heslo typu RČ, 123456789, ...
b) odejde od veřejně přístupného počítače když je přihlášen
c) má PC plný bordelu (keylogery,...)
...atd...

Jestli ti můžu poradit, využij odkazované části Nette Frameworku. Je to nejjednodušší cesta jak získat dostatečně bezpečné přihlašování na míru.
JJ, tady je akorát ještě ve hře rozšíření podmínek funkčnosti, tj. aby to fungovalo i bez zapnutých cookies. Se zapnutýma cookies je to v pohodě a mám z čeho vybírat (Nette, sessions, pseudosessions...) - děkuji všem za zajímavé a konstruktivní podněty, sám bych tolik možností nevymyslel; a pravděpodobně pokud se mi bude chtít, tak pak přidám rozšíření, stylem že pokud nejsou cookies, tak se spustí alternativní mechanismus, třeba WWW-Authenticate nebo POST komunikace.
A samozřejmostí je https.
Samozřejmě pokud někdo ještě přijdete s dalším zajímavým nápadem, rád ho zde uvítám, mám na ten projekt ještě nějaký čas. Ale myslím, že to snad už není potřeba :-)
RUR - u WWW-Authenticate: Basic neexistuje v IE zpusob, jak se odhlasit nez uplne pozavirat prohlizecova okna.
Mame tu kiosky (to jsou takove ty pocitace na chodbe s dotykovym displejem). Funguje to tak, ze je spusteny program, ktery blokuje pristup do win a blokuje otevreny prohlizec. Nastesti na nasich neni IE. Z klavesnice jsou odstraneny klavesy pro dostani do win. Takze jsem dodelal na vychozi stranku kiosku odhlasovaci tlacitko. Je to vlastne normalni odkaz, kde se prihlasis na jineho uzivatele, ktery vsak v db neni
https://uzivatel:heslokvuliodhlaseni@webstag.slu.cz/apps/stag/portal/index
Mame tu znamou aplikaci Stag. Stavajici verze prave funguje na autentizaci. Stava se, ze studenti na ucebne pouziji IE a nechaji jedno okno otevrene. Takze v ucebne je to ztracene, ale na kiosku, kdyz se odhlasi, tak je to oki.

Tim chci rici, ze autentizaci nedoporucuji.
peta: Přemýšlel jsi někdy o tom, co je to autentizace?
RUR: "tady je akorát ještě ve hře rozšíření podmínek funkčnosti, tj. aby to fungovalo i bez zapnutých cookies"

Doporučuji Ti tenhle přístup: Nemáš zapnuté Cookies? Tak se vrať až si je zapneš...
Přijde mi zbytečné úmyslně vkládat do aplikace slabé místo jenom kvůli několika případům s vypnutými cookies...
... nevím jak ty, ale já už jsem vyrostl z toho, abych se přetrhnout jenom kvůli tomu abych se zavděčil všem. Prostě pro správnou funkčnost mám tyhle a tyhle požadavky, které většina splňuje. Patříš k menšině co nesplňuje - poraď si jak chceš! :)
Tady se postavím za Toma. Od chvíle, kdy si větu "aplikace vyžaduje povolené cookies" připsaly k sobě většina internetových bankovnictví, webmailů a jiných služeb (přihlašovací systémy, registrace apod.. - pracující s důvernými informacemi) nikomu nic nebrání si ji připsat také.

Z vlastní zkušenosti napíši toto.. dělali jsme větší přihlašovací systém, pro maximální přistupnost měl pro přihlašování 2 režimy - s cookies a bez cookies. Kvůli tomu se všechno stalo jenom složitější. (Mezera, jak se se získanou url pak dostat dovnitř je totiž vždycky..) Navíc "bezcookie" uživatelům jsme museli k odhlašovacímu formuláři připsat červené vykřičníky..(protože neodhlášení uživatele - tedy čekání na nějaký timout - je nejhorší období). Ale.. chystá se kompletní upgrade toho systému a jedna ze změn je...zrušit přístup bez cookie (vedli jsme si totiž "tajnou" logovací statistiku - za 2 roky provozu bylo přístupu bez cookie méně než 1/15 celkového počtu).
Takže z mého pohledu: cookie ano, vyžadovat.
<HTML>Navíc - cookie umí každý používaný prohlížeč - ba i ten nepřehledný textový Lynx. To jen moje podpora argumentu - dělat web bez podpory session (která bývá podepřená právě pomocí cookies) dnes nemá smysl. Že jsou lidi, co mají cookies vypnuté? Mohou si je zapnout ;)</HTML>