Zabezpieczenie profilu przed logowaniem na to samo konto w php


(hatezit) #1

Witam,

Mam takie pytanie, jak zabezpieczyć profil, aby przed próbą logowania na to samo konto nie można było wejść?

Mam napisane sesje i logowanie, ale niestety, jak odpalę chrome i firefox, to moge z obu zalogować sie na to samo konto.

Tak mam sesje napisaną przy logowaniu:

session_start();



if(isset($_SESSION['logged_in']) === 1) {



    $username = $_SESSION['username'];



    header("Location: profile.php?username=$username");



    exit();



}







zmienne 







i zapytanie:







$query = $db->query("SELECT * FROM members WHERE username='".$username."' AND password='".$pwrd."'");



      if($query->num_rows === 1){



	     $_SESSION['logged_in'] = 1;



		 $_SESSION['username'] = $username;



		 header("Location: profile.php?username=$username");



		 exit(); 



      }else{



	    $msg = "Błędna nazwa użytkownika lub hasło !!!";



      }

A tak w profilu:

session_start();



include('db_conn.php');



if(isset($_SESSION['logged_in']) && $_SESSION['username']){



    $profile_name = $_GET['username'];



   }else {



   echo 'Brak dostępu do profilu! Musisz się zalogować!';



   exit();



   }

dalej w pliku profilu jest pobieranie danych tego usera.

Co jest źle lub powinienem zmienić?

P.S. Po edycji nadal robią sie duże odstępy w liniach a je zmieniałem.


(Drobok) #2

Tego nie da się zrobić w sposób w który chcesz to zrobić. W wypadku wyczyszczenia ciastka nie zalogowałbyś się na konto. Co najwyżej możesz blokować logowanie o ile nie nastąpiło wylogowanie i aktywność w przeciągu czasu t


(hatezit) #3

To w takim razie pozostaje mi dodać kolumnę do tabeli użytkownika o nazwie status i wprowadzić update na 1, gdy loguje się. Gdy wyloguje się, to w pliku logout dać ponownie update, który zmienia na 0 (jest wylogowany). Dobry pomysł?


(Drobok) #4

No nie koniecznie, gdy ktoś straci sesje nie będzie mógł się wylogować i już się nie zaloguje :wink:


(hatezit) #5

Z czasem też może nie zadziałać. Jak skorzystam z innej przeglądarki, to i tak zaloguje się, gdy będzie setcookie i time. A chodzi mi o to, aby nie można było zalogować się na konto, na którym już jest zalogowany użytkownik, bez względu z jakiej przeglądarki sie loguje.


(Pablo_Wawa) #6

Chyba nie rozumiesz jednej rzeczy - skąd wiesz (po stronie serwera), że dany użytkownik jest w danym momencie zalogowany - i nie chodzi mi tu o sam fakt, że się zalogował, ale że jest na stronie serwisu?
Rozpatrz przypadek, że po zalogowaniu łazi sobie po serwisie, ale zawiesi mu się przeglądarka, albo posypie komputer - i co wtedy? Z innej przeglądarki czy komputera już się wtedy nie zaloguje, bo… już jest zalogowany?
Poprawne rozwiązanie problemu to zapisywanie w bazie czasu ostatniej aktywności użytkownika (timestamp) - domyślnie jest pusty (np. NULL lub lepiej 0), po zalogowaniu ustawia się na bieżący czas/datę i przy każdorazowym otwarciu dowolnej strony serwisu to pole jest aktualizowane*. A jeśli się oficjalnie wylogowuje, to zerujesz po prostu to pole i gotowe.

I teraz, przy logowaniu, sprawdzasz to pole i jeśli różnica tej wartości i bieżącego czasu jest mniejsza od ustalonej wartości (np. 5-10 minut), to dajesz komunikat o niemożności podwójnego zalogowania. A jak go logujesz, to pamiętaj o zresetowaniu zmiennej sesyjnej (wygenerowanie nowej), żeby w innej przeglądarce nie mógł przeglądać tego serwisu, jeśli wcześniej już tam był i się zalogował.

* dodatkowo możesz (powinieneś nawet?) na każdej stronie serwisu, poprzez JavaScript, wysyłać informację na serwer co ustalony czas (np. co 1 minutę), że dany użytkownik cały czas przebywa na stronie serwisu - wtedy będziesz miał dokładniejszą kontrolę jego bytności (bo np. może mieć przez godzinę lub dłużej otwartą jedną stronę serwisu).


(hatezit) #7

Czyli wychodzi na to, co wcześniej pisałem, ale moderator napisał, że nie koniecznie. Przy logowaniu by był update do pola czasu a dokładnie w liniach logowania po zapytaniu query  i między instrukcją if. A w polu profilu czas cookies. Przy wylogowaniu zerowanie do 0 i wstawiania czasu. Dobra, porobię to. Teraz inne opcje robię w aplikacji.


(Fizyda) #8

Ehhh ale kombinujecie, zrób pole dla użytkownika, jak session_id, w momencie logowania zapisujesz je, gdy odwiedzający ma session_id to wiesz kom on jest, a gdy zaloguje się z innego urządzenia, session_id zostanie nadpisany nowym i nastąpi automatyczne wylogowanie w starej sesji.

W praktyce powinieneś stworzyć nową tabelę gdzie będziesz trzymał sesje, wyżej masz proste rozwiązanie które ma ułatwić zrozumienie problemu oraz w jaki sposób należy to rozwiązać. W praktyce na dłuższą metę się nie sprawdzi.


(hatezit) #9

Ja wolałbym aby rozwiązanie sprawdzało się bardzo dobrze, a nie na chwilę. Dlatego pokazałem kod i pytałem co zmienić, ewentualnie inaczej napisać. Ważne, że do profilu nie można dostać się, gdy nie jest się zalogowanym. Tylko mam jeden problem, o którym wyżej pisałem.


(Fizyda) #10

Przecież Ci napisałem jak to zrealizować. Pierwsze proste rozwiązanie tylko w celach podglądowych byś zrozumiał o co chodzi, później powiedziałem Ci jak to zrobić by było dobrze.


(hatezit) #11

To co pogrubione jest, to tak napisałeś, stąd moja odpowiedź. Ja rozumiem o co Ci chodzi, ale zauważyłem, że jedna strona też ma taką lukę, tylko nie jest to strona informatyczna;) I wolę nie pisać tu publicznie.


(Drobok) #12

Pytanie czy chcesz by nowe logowanie usuwało stare, czy stare blokowało nowe :wink:

Oba sposoby się sprawdzą na dłuższą metę (tyle że sposób Fizydy mniej obciąża serwer)


(hatezit) #13

Raczej to pierwsze, gdy jest już ktoś zalogowany, to nie może zalogować się, nawet z innej przeglądarki. To co Fizda napisał jest dobrym rozwiązaniem.

Jednak dziś usłyszałem, że mój problem, o którym piszę, nie jest luką w zabezpieczeniach i że jest to norma. A ja twierdzę, że nie jest normą.


(Fizyda) #14

Ok więc jeszcze prościej.

HTTP jest protokołem bezstanowym dlatego można zalogować się z wielu urządzeń/przeglądarek w jednym serwisie.

Aby ograniczyć to ze względów bezpieczeństwa np wiadomo że tylko jedna osoba może zalogować się do banku i chcieć zrobić przelew i ta osoba będzie to robić z jednego urządzenia na raz bo raczej nie możliwym jest by się rozdwoiła na dzień dzisiejszy, można zrobić to na dwa sposby

Rozw1 (Twoje)

Po zalogowaniu się do systemu nie można się zalogować do niego ponownie do czasu wylogowania się. - tak się nie robi bo ludzie są ludźmi i zablokują sobie konta, nikomu nie chce się siedzieć i odblokowywać 60% kont bo ktoś zgubił sesję albo zapomniał się wylogować i nie wie gdzie się zalogował. Stara czasu i pieniędzy oraz masa problemów - o których już się rozpisali inni.

Rozw2 (Moje)

W momencie zalogowania się (utworzenia nowej sesji) stara sesja jest usuwana. Tak się robi bardzo często jest to bezpieczne i bezproblemowe rozwiązanie.

PodRozw2.1

Dodać pole w tabeli z użytkownikami z id sesji - tak jak pisałem w pierwszym poście, lecz rozwiązanie jest to na krótką metę - pisałem o tym w pierwszym poście, dlatego lepsze jest rozwiązanie kolejne

PodRozw2.2

Dodać osobną tabelę w której będziesz trzymał sesje i informacje o tym jakiego konta ona dotyczy - nie wchodzę w szczegóły bo rozwiązań jest wiele, jest ono lepsze od 2.2 bo jest wydajniejsze ponieważ session_id jest kluczek głównym a takie wyszukiwanie jest szybsze niż to w 2.1

 

Nie widzę sensu robienia takiego systemu logowania i utrzymywania sesji jak Ty to opisałeś, nie jestem w stanie sobie wyobrazić potrzeby istnienia takiego systemu dodatkowo nigdy się z czymś takim nie spotkałem. Co nie oznacza że nie da się tego zrobić, da się bardzo prosto, bierzesz PodRozw2.2 i zamiast usuwać starą sesję nie tworzysz nowej i blokujesz logowanie jeśli jakaś stara sesja istnieje. DB wygląda tak różnica jest na poziomie logiki aplikacji.


(hatezit) #15

Moja propozycja, która napisałem wcześniej i to na początku, była strzałem, ale nie chce jej używać:) A tym bardziej pisać. Pisałem też, że zapis do tabeli z sesjami i użytkownikami dałbym po zapytaniu query i umieścił bym między IF i tu nie otrzymałem odpowiedzi, czy to dobre było rozwiązanie.

Fizda, nie jestem głupi, aby mi tak tłumaczyć. Wiem, że starasz się tak napisać i zobrazować, ale wiem o co Ci chodzi:)


(Pablo_Wawa) #16

Ale z tego, co powyżej napisał drobok wynika, że raczej to drugie (a nie pierwsze) - sam się gubisz?

Z propozycji opisanych przez Fizyda wynika, że nie bardzo pasuje to dla tego, co chcesz (chyba?) osiągnąć - tj. jak ktoś już jest zalogowany do serwisu, to nie może zalogować się ponownie , nawet z innej przeglądarki (bo w końcu tego chcesz?). Tylko moja propozycja rozwiązania pasje do tego i daje rozwiązanie problemu. Tzn. szczegóły po stronie serwera (co jest trzymane) to jedno, a odświeżanie lub przedział czasowy nieaktywności w serwisie to drugie - bo przy tym swoim założeniu o blokadzie zalogowania po raz drugi musisz uwzględnić utratę dostępu do serwisu i brak wylogowania z sesji - zatem ustalenie przedział czasu ostatniej aktywności da Ci możliwość “wywalenia” starej sesji i możliwość zalogowania się na nowo.


(hatezit) #17

Pablo_Wawa, racja to drugie. Czy ja się gubię? Raczej nie, tylko nie to napisałem, co trzeba:) Odpowiedź z twojego pytania w nawiasie za pogrubionym tekstem brzmi tak, to chcę uzyskać. Po co mam blokować usera? Ja tylko chce uniemożliwić logowania na to samo konto. Tylko teraz usłyszałem, że wiele serwisów ma tak, więc nie wiem, czy to będę pisać:)