logowanie z funkcją 'zapamiętaj mnie'

0

cześć,
mam pytanie, w jaki sposób powinienem rozwiązać problem, gdy podczas logowania użytkownik zaznaczy opcje 'zapamiętaj mnie'.
wiem, że będzie potrzebne ciastko, tylko co powinno być w tym ciastku zawarte, żeby system był dosyć bezpieczny?
https://paragonie.com/blog/2015/04/secure-authentication-php-with-long-term-persistence#title.2 tu znalazłem jakiś pomysł, ale nie do końca go rozumiem, w takim razie czy ktoś mógłby mi wytłumaczyć jak to powinno wyglądać?
z góry dziękuję

1
  1. logujesz uzytkownika, generujesz sobie długi, losowy string (czyli NIE md5(time()) czy uniqid() tylko coś bezpiecznego np. openssl_random_pseudo_bytes) - dalej nazwijmy to token logowania
  2. zapisujesz do bazy, że ten token oznacza logowanie tego użytkownika
  3. w ciasteczku zapisujesz token
  4. potem po prostu porównujesz dane z ciastka z tym co masz w bazie

ten sposób pozwala na zapamiętanie użytkownika, nie wymaga zapisania w ciastku ani loginu, ani tym bardziej hasła czy jego hashu (co się widuje czasem), dodatkowo możesz dobudować do tego inne mechanizmy, np. weryfikacja czy bieżące ip zgadza się z zapisanym razem z tokenem ip, możesz też łatwo wymusić wylogowanie użytkownika, bo po prostu kasujesz token z bazy

0

czyli wystarczy, że zapamiętam jedną zmienna (losowo wygenerowana, oczywiście odpowiednio długą, ale JEDNĄ zmienna) w ciastku i szukam jej w bazie, a jeżeli pasuje to loguje użytkownika? i to koniec?

0

Tak, natomiast dobrze jest sprawdzać jeszcze IP, albo coś. Zwiększysz w ten sposób bezpieczeńśtwo.

1

@Desu: Większość serwisów nie sprawdza IP, bo ludzie ze zmiennym IP mieliby problem. Ja bym raczej pomyślał o zerowaniu sesji jeżeli drastycznie zmienił się User Agent (np. z Firefoxa na Chrome, podbicie wersji nie - nikt ciastek nie przenosi, więc sugeruje to kradzież sesji) albo drastycznie zmienił się IP (czyli zmiana z 188.1.100.100 na 188.1.200.200 nie jest problemem, bo to w obrębie typowego zmiennego IP się mieści, ale na 91.251.100.100 już tak).

0

przy kazdym zalogowaniu powinienem od nowa generowac token i umieszczac go w ciastku uzytkownika?

0

jak nie dostaniesz żadnego tokena, a dostaniesz dane logowania to tak, twórz nowy - rozróżnisz sobie wtedy dwie sesje (np. z telefonu i komputera)

0

to teraz mi trochę namotałeś... jak wygeneruję od nowa token to stary będzie nieaktywny, czyli jak ktoś zaloguje się na telefonie to token zapisany na komputerze przepadnie czy coś nie tak myślę?
w dodatku jak sprawdzać i porównywać user agenta? tzn. które dane w user agencie są istotne, a które nie? logując się na telefonie user agent będzie zupełnie inny, prawda? już się pogubiłem

0

weryfikacje user agenta na razie sobie odpusc

a tokeny nie zapisuj w tabeli z uzytkownikiem, tylko osobno, dwie kolumny wystarczją: id_user, token

0

no dobra, to w takim przykład:

  1. ktoś loguje się na komputerze ustawiam mu token: 1 i jest zalogowany
  2. ta sama osoba loguje się na telefonie ustawiam jej nowy token: 2 i jest zalogowany

teraz jak wchodzi na komputerze to jest wylogowany bo token jest nieprawidłowy. czy dalej coś mylę?

0

Możesz zrobić też żeby logowanie było zapamiętane na wielu urządzeniach (do tabeli z tokenami dodajesz kolejne, powiązane z id usera).

0

to ma sens :) dzieki

0

mam problem z odczytaniem umieszczonego wcześniej openssl_random_pseudo_bytes w bazie danych...
Notice: Trying to get property of non-object in D:\xampp\htdocs\projekt\funkcje\logowanie.php on line 18
dostaje taki błąd

w bazie danych kolumna przetrzymująca dane jest typu varbinary
próbowałem dodawać/odczytywać ciągi z funkcją mysql_real_escape_string i bez tego i dalej nic
rekord normalnie dodaje się do bazy, ale podczas sprawdzania czy token z ciastka jest taki sam jak w bazie dostaje ten błąd...

0

wrzuć kod, nie będziemy zgadywać

0
if (!isset($_SESSION['log']['uzytkownik']) && isset($_COOKIE['tunes_token'])) {
		$token = $_COOKIE['tunes_token'];

		$bd = polacz_bd();

		$query = $bd->query("select uzytkownik from uzytkownik_pamietaj where token='".$token."'");

		if (!$query) {
			wystapil_blad();
		}

		if ($query->num_rows==1) {
			$dane=$query->fetch_object(); // fetch_row(); taki sam efekt daje
			$_SESSION['log']['uzytkownik'] = $dane[0];
			$_SESSION['log']['pamietaj'] = 1;
		} else {
			setcookie('tunes_token', $_COOKIE['tunes_token'], time()-1);
		}
	}

i w razie potrzeby dodawanie tokenu do bazy

if ($zalogowanie==1) {
			if (isset($_POST['log_pamietaj']) && $_POST['log_pamietaj']=='tak') {
				$bd = polacz_bd();

				$tokenok=0;
				while ($tokenok==0) {
					$token = openssl_random_pseudo_bytes(50);

					$query = $bd->query("select * from uzytkownik_pamietaj where token = '".$token."'");
					if (!$query) {
						wystapil_blad();
					}

					if ($query->num_rows > 0) {
						$tokenok=0;
					} else {
						$tokenok=1;
					}
				}
				
				$query = $bd->query("insert into uzytkownik_pamietaj values('".$log_login."', '".$token."')");
				if (!$query) {
					wystapil_blad();
				}

				//dodaje ciastko jak wszystko ok i wrzucone juz do bazy danych 
				setcookie("tunes_token", "'".$token."'", NULL, NULL, NULL, NULL, TRUE);
			}
0

no to jeszcze pokaż która to linijka jest u Ciebie 18 w logowanie.php

0

Notice: Trying to get property of non-object in D:\xampp\htdocs\projekt\funkcje\logowanie.php on line 18

if ($query->num_rows==1) {
  • sprawdzanie tokena

Notice: Trying to get property of non-object in D:\xampp\htdocs\projekt\funkcje\logowanie.php on line 130

if ($query->num_rows > 0) {
  • dodawanie tokena do bazy
0

a co masz w wystapil_blad? jeżeli nie kończysz skryptu przez die/exit no to sam popatrz

                    if (!$query) {
                        wystapil_blad();
                        // $query jest false
                    }
                    
                    // tu nie ma else, więc może się zdarzyć, że w tym miejscu $query jest false
                    // próbujesz się odwołać do false->num_rows
                    if ($query->num_rows > 0) {
                        $tokenok=0;
                    }

ale z drugiej strony - wystapil_blad zakładam, że pokazuje Ci, że jest jakiś błąd - i chyba tego nie przeoczyłeś?

0

ok masz racje, co nie zmienia faktu, że jakimś cudem query jest false, a więc select uzytkownik from uzytkownik_pamietaj where token='".$token."' nie zwraca zadnego rekordu, a co się z tym wiąże token dodany chwilę wcześniej do ciastka po sprawdzeniu go z tokenem z bazy danych nie pasuje, a jak dam echo $token to wyskakują mi bardzo dziwne znaczki, a w bazie danych wygląda normalnie, może jakoś inaczej powinienem go zapisywać/wczytywać? bo myślę, że jak zmienię openssl_random_pseudo_bytes na inną funkcję generującą losowy ciąg znaków, ale używającą normalnych znaków to wszystko będzie działać

0

Potraktuj to jeszcze jakimś sha-1 albo md5, żeby uzyskać tylko alfanumeryczne znaki

swoją drogą aż prosisz się o sql injection (poważna dziura), nie powinieneś tak robić zapytań. ogarnij temat PDO i bindowania zmiannych.

no i jakąś sensowną obsługę błędów zrób (tutaj nawet nie pokazujesz sobie widzę komunikatu zwracanego przez mysql o błędzie)

1 użytkowników online, w tym zalogowanych: 0, gości: 1