Autor Zpráva
Martin Brodecký
Profil
Ahoj,
řeším trvalé přihlášení uživatelů. Prosím o radu. Nejprve jsem si vytvořil zápis trvalého přihlášení resp. ID a tokenu do databáze, to funguje v pohodě:

$token = md5(uniqid(mt_rand(), true));
setcookie("trvale_prihlaseni", "$_SESSION[id]:$token", strtotime("+1 month"));
mysql_query("
INSERT INTO users_logged (id_user, token)
VALUES ($_SESSION[id], '$token')
");

Při přihlášení uživatele se do tabulky user_logged zapíše potřebná hodnota tokenu a ID. Jenže teď potřebuji na začátku nejlépe v hlavičce celého webu ověřit, zda je či není ten který uživatel přihlášen a pokud je, tak např. definovat nějakou proměnnou na hodnotu true a pokud není, tak na hodnotu false a také uložit do nějaké proměnné hodnotu ID uživatele, abych dále věděl, který je přihlášený a mohl dle toho zobrazovat věci na stránce.

Mám tu toto:
list($id_user, $token) = explode(":", $_COOKIE["trvale_prihlaseni"], 2);
  mysql_result(mysql_query("
  SELECT COUNT(*)
  FROM users_logged
  WHERE id_user = " . intval($id_user) . "
  AND token = '" . mysql_real_escape_string($token) . "'
  "), 0);

Jenže $id_user i $token jsou prázdné..... A ani pořádně netuším, jak je vypsat, můžete mi někdo poradit?
Martin Brodecký
Profil
Aktualizace:

tak jsem si při zjišťování hodnoty v cookies ve srovnání s databází napsal toto:

list($id, $token) = explode(":", $_COOKIE["trvale_prihlaseni"], 2);
  $autologin = mysql_result(mysql_query("
  SELECT COUNT(*)
  FROM users_logged
  WHERE id_user = " . intval($id) . "
  AND token = '" . mysql_real_escape_string($token) . "'
  "), 0);
  
  echo "$autologin";

Bohužel proměnná $autologin má i v případě, že zápis do databáze proběhl dobře hodnotu nula. To znamená, že hodnota cookie "trvale_prihlaseni" je prázdná, zatím nevím, proč...
Martin2
Profil *
Pořiď si PHP editor s debuggerem, podívej se na hodnoty proměnných a přestaň používat funkce md5, uniqid a mysql_*.

Mimochodem, tímto způsobem trvalé autentizace vytváříš bezpečnostní slabinu. Kompromitace tokenů dokáže úplně obejít přihlášení.
Martin Brodecký
Profil
Martin2:
Ahoj, tak vše jsem nakonec rozchodil, ale docela by mě zajímalo, pokud tedy říkáš, že tento způsob je děravý, jaký způsob tedy mám používat? Na celém googlu se nedá o tomhle nic najít a tento způsob je všude uveden jako bezpečný. Jak konkrétně myslíš "kompromitovat" token? Vždyť ten token se nedá vyčíst jinak než zneužitím dat z databáze - value v cookie samozřejmě neodpovídá tokenu tzn. ten token je možno číst uvnitř PHP skriptu vypsáním hodnoty proměnné (a to uživatel těžko udělá) a nebo je přítomen v databázi a plkud se mi už někdo dostane do databáze, tak už může zneužít v podstatě vše.. Nebo mi naznač, jak, ať přemýšlím jak přemýšlím, tak nemohu nic vymyslet.
TomasJ
Profil
Martin2:
Věděl jsi, že když ti někdo z prohlížeče "ukradne" SESSION ID, obejde přihlášení úplně stejně jako když ukradne jiný token?

Martin Brodecký:
Podle mě to až tak děravé není, ale...

Máš tam zbytečné to ID. Token by měl být unikátní, čímž jsi schopen z databáze vytáhnout právě jeden záznam pro daný token (a u něj bude zapsáno i ID).

Opravdu používej raději mysqli, než mysql (je zastaralé a možná už i nefunkční). Pokud jsi zvyklý na zápis mysql_*, v mysqli je to v podstatě totožné, až na přidané písmeno "i" za "mysql". Je třeba počítat s tím (snad se nepletu), že cookie nastavené skriptem PHP, je dostupné až při dalším načtení stránky. Ovšem tím už si nejsem jistý, PHP se již nějaký čas nevěnuji.

Edit:
Udělal bych ověření, jestli jsou či nejsou prázdné proměnné $id a $token. Pokud ano, cookie je prázdné. Pokud ne, zkusil bych dotaz na DB, ale místo COUNT(*) bych nechal * (všechny sloupce) a následně si vypsal, co to vlastně vrátí (mysql_fetch_*). Pak ještě zkus vypsat mysql_error a zjistit jestli v tom někde nemáš chybu.
Martin2
Profil *
TomasJ:
Věděl jsi, že když ti někdo z prohlížeče "ukradne" SESSION ID, obejde přihlášení úplně stejně jako když ukradne jiný token?
Ne tak docela. Session je většinou krátkodobá, v řádu hodin, nikoliv dnů nebo dokonce týdnů. Kromě toho – session id je odděleno od databázových dat. Umístěním autentizačního tokenu do databáze je v podstatě popření smyslu hashování hesla – je to věc, kterou lze ukrást a použít k přihlášení do aplikace.
TomasJ
Profil
Martin2:
Myslíš, že když někdo ovládne přístup k tvé DB, bude ho zajímat pouhý přihlašovací token? V tomto okamžiku už si s DB může dělat co chce. Pokud někdo udělá SQL inject, je chyba programátora že to neošetřil. Od toho je *_real_escape_string.
Martin2
Profil *
TomasJ:
Myslíš, že když někdo ovládne přístup k tvé DB, bude ho zajímat pouhý přihlašovací token?
To není relevantní. Umístěním autentizačního tokenu do databáze oslabuješ bezpečnost své aplikace, protože vytváříš něco, co lze ukrást a použít k přihlášení (což může být MNOHEM horší než pouhá ztráta dat).
TomasJ
Profil
Martin2:
Mohli bychom se o tom, co je horší, dohadovat měsíc. Vím, jak funguje OAuth2 zabezpečení. Funguje na něm i Google autorizace. Ukládá do DB přístupový (access) a obnovovací (refresh) token. Přístupový platí obvykle platí jen hodinu, obnovovací klidně 7 dní a déle. Pomocí obnovovacího se dá vygenerovat nový přístupový. Představ si, že jim někdo ukradne data. Je to jen o tom, jak máš zabezpečený přístup do DB a ošetřený vstup od uživatele. Pokud ani jedno nemáš dokonale, pak máš opravdu větší problém než ztrátu tokenů, které můžeš z DB smazat a vše bude fungovat dál bez problémů.

Vaše odpověď


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: