Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Identyfikator sesji a bezpieczenstwo
Forum PHP.pl > Forum > PHP > Pro > Archiwum Pro
blasfemia
Czesc.
Zrobilem sobie swoj wlasny mechanizm sesji i uwierzytelniania, z uzyciem bazy danych (MySQL). Gdy ktos chce skorzystac z mojego serwisu musi sie zalogowac, czyli podac nazwe uzytkownika, haslo i nazwe bazy danych z ktorej chce korzystac (to ostatnie to akurat sprawa "tematyki' mojego serwisu). Konta uzytkownikow i ich uprawnienia, a takze dane otwartych sesji sa zapisane w jednej "specjalnej" bazie danych.
Po podaniu odpowiednich danych rozpoczyna sie sesja, w odpowiednich tabelach w tej "specjalnej" bazie jest zapisywana nazwa zalogowanego uzytkownika, numer IP komputera z ktorego sie zalogowal oraz wygenerowany identyfikator, a takze aktualne zmienne sesji. Identyfikator sesji jest przekazywany miedzy skryptami poprzez GET'a, w URL'u. No i tu wlasnie moj problem/pytanie. Czy wedlug Was ta metoda (przekazywania sid'a) jest bezpieczna?
W kazdym skrypcie na samym poczatku pobieram z tablicy $_GET identyfikator sesji z URL'a i przekazuje go do funkcji ktora sprawdza jego "autentycznosc", czyli sprawdza czy w tabeli z danymi otwartych sesji istnieje rekord z danym sid'em a takze sprawdza czy numer IP z ktorego delikwent probuje uruchomic skrypt z podanym sid'em zgadza sie z numerem IP zapisanym w trakcie procesu logowania. Jesli ktos probuje uruchomic skrypt i wklepal recznie "jakos" zdobyty identyfikator sesji, ale numer IP kompa, z ktorego probuje uruchomic skrypt jest inny niz ten zapisany w tabeli o danych "legalnie otwartych" sesji no to ... stosowny komunikacik i koniec.
Czy wedlug Was to zabezpieczenie z numerem IP jest wystarczajace? Nie jestem ekspertem od metod atakow na serwisy www smile.gif
spenalzo
Wydaje mi się że tak, ale pewnym problemem są modemowcy, którym czasami się rozłącza modem, a co za tym idzie zmienia się IP i tracą swoją sesję. Chociaż to się zmienia, i jest nas coraz mniej :-)

Co do przekazywania zmiennej przez GET - wrzuć sobie to w sesje php, a pozbędziesz się kłopotu p[rzekazywania zmiennych przez GET, albo wręcz skorzystaj z identyfikatora sesji.
blasfemia
Cytat
Wydaje mi się że tak, ale pewnym problemem są modemowcy, którym czasami się rozłącza modem, a co za tym idzie zmienia się IP i tracą swoją sesję. Chociaż to się zmienia, i jest nas coraz mniej :-)


Pracuje jako programista/ksiegowy w dziale ksiegowosci w pewnej firmie i jestem w trakcie tworzenia systemu obslugi ksiegowosci a takze pewnych "nieksiegowych" obszarow dzialalnosci firmy. System ten bedzie dzialal glownie w sieci lokalnej. Bedzie rowniez dostepny "z zewnatrz". Niektorzy pracownicy beda mieli do niego dostep "z domu", np. wlasnie przez modem. Jednak ten system to, ze tak powiem, "powazna sprawa" i problem ponownego logowania po zerwaniu lącza to wlasciwie nie problem. Jesli lacze zostanie zerwane to taki delikwent musi sie ponownie zalogowac i juz, koniec kropka smile.gif

Cytat
Co do przekazywania zmiennej przez GET - wrzuć sobie to w sesje php, a pozbędziesz się kłopotu p[rzekazywania zmiennych przez GET, albo wręcz skorzystaj z identyfikatora sesji.


No wlasnie problem w tym ze nie chcialem korzystac z wbudowanych mechanizmow php, m.in. mechanizmow sesji czy uwierzytelniania. Chcialbym aby moj serwis byl jak najmniej zalezny od ustawien konfiguracyjnych serwera www, php itd. Wlasne sesje, brak zmiennych globalnych a juz na pewno nie zamierzam korzystac z cookies i innych takich smile.gif
itsme
mozesz to dwojako zrobic ale:
:arrow: przedewszystkim SSL
:arrow: kazdy uzytkownik moze sie laczyc z odpowiednigo hosta czyli mozesz wpisac do bazy danych i porownywac - natomiast co do modemowcow tam zmienia sie tylko jeden nr pozostala czesc reszte adresu mozesz porownac z baza danych
:arrow: ciasta odpadaja
:arrow: po wlaczeniu SSL mozesz zrobic ID_sesji w INPUT typu hidden
za kazdym razem sperawdzasz czy $_POST['nazwa_inputu']==ID_sesji w bazie nastepnie wyciagasz id_usera i sprawdzasz czy host z ktorego sie laczy jest w bazie danych i tak za kazdym wywolaniem abys muial pewnosc ze strona nie zostala skopiowana lacznie z INPUTEM i wywolanie nastapilo z innego adresu. Oczywiscie co jakis czas (5 minu, 10 Twoja opcja) usuwaj sesje z bazy danych czyli musisz trzymac czas ostatniego wywolania

ps. tez pisalem wlasny system logowania gdzie id_sesji jest przekazywane w GET myk jest taki ze te ID zmienia sie toz po zalogowaniu na inny

ps2. forum phpBB ma system logowania oparty na sesjach i jakos nie slyszalem aby ktos zlamal te zabezpieczenia.

ps3. proponuje logowanie z phpBB + SSL
blasfemia
Yyyyy, zeby nie bylo nieporozumien ... piszac "Zrobilem sobie swoj wlasny mechanizm sesji" nie mialem na mysli tego ze napisalem swoje handlery do zdarzen zwiazanych z sesjami (rozpoczecie, zakonczenie, rejestrowanie zmiennej itd). Moj mechanizm nie ma nic wspolnego z sesjami php.
blasfemia
Cytat
kazdy uzytkownik moze sie laczyc z odpowiednigo hosta czyli mozesz wpisac do bazy danych i porownywac


Takie rozwiazanie raczej odpada. Chcialbym zeby logowanie sie do systemu bylo "uniwersalne". Jak prezes pojedzie do Krakowa na spotkanie z kontrahentem i siada sobie w knajpce na Rynku to chcialbym zeby mial mozliwosc zalogowania sie do systemu czy to ze swojego kompa czy z kompa kontrahenta, a nie musze wiedziec jakie ip dostanie w dzialajacej tam sieci radiowej smile.gif

Cytat
Oczywiscie co jakis czas (5 minu, 10 Twoja opcja) usuwaj sesje z bazy danych czyli musisz trzymac czas ostatniego wywolania


Kazda moja funcja zwiazana z sesjami wywoluje funkcje "czyszczaca" ktora usuwa z tabeli (powiedzmy "sessions") rekordy z sesjami "starszymi" niz ustalony w konfiguracji czas.

Cytat
ps. tez pisalem wlasny system logowania gdzie id_sesji jest przekazywane w GET myk jest taki ze te ID zmienia sie toz po zalogowaniu na inny


W mom mechanizmie wyglada to tak. Delikwent podaje swoje dane logowania. System sprawdza czy w tabeli (powiedzmy "users") jest taki koles i czy ma odpowiednie uprawnienia. Jesli tak to jest otwierana dla niego nowa sesja. System generuje NOWY unikalny identyfikator i zapisuje w tabeli "sesions" nowy rekord z tym identyfikatorem. Gdy delikwent sie wyloguje to rekord jest usuwany, lub po jakims ustalonym czasie "nieaktywnosci". Tak wiec za kazdym razem jest to nowy identyfikator. Problem w tym ze ktos moze podgladac ruch w jakiejs tam sieci i przechwicic ten identyfikator uzywany w danym momencie przez "legalnie" zalogowanego uztykownika, i probowac ze swojego kompa uruchamiac skrypty podajac ten identyfikator. Stad ten pomysl z zapisywaniem ip komputera z ktorego uzytkownik sie loguje. Oczywiscie gdy uzytkownik sie wyloguje to ip tez jest usuwane. Wszystkie dane dotyczace sesji sa usuwane.
adwol
Cytat
:arrow: ciasta odpadaja

Dlaczego? Chodzi Ci o to, że można z innej strony wyciagnąć je javascriptem? Bo na takie argumenty jest jedna odpowiedź: security bug w przeglądarce, prosze zgłosić to jej autorowi.
IMHO cookie są wygodniejsze od podawania id w urlu, pomijając fakt, że w urlu można go podglądnąć i zostaje w historii.
Cytat
ps2. forum phpBB ma system logowania oparty na sesjach i jakos nie slyszalem aby ktos zlamal te zabezpieczenia.

I z tego co widze opaty jest na cookie, więc tym bardziej nie wiem czemu napisałeś, że cookie odpadają.

W/g mnie podstawa to:
:arrow: SSL
:arrow: dobry algorytm generujący id sesji
:arrow: autentykacja po parze id sesji, IP
:arrow: timeouty
Wybór usadowienia samego id jest w zasadzie dowolny, ale wygoda też się liczy. :wink:
Omega
Myslę że niepotrzebnie chcesz się uniezależnic od konfiguracji php jeżeli chodzi o sesje... Może jestem w błędzie, ale te są bardzo dobrze bsługiwane i nie ma sie co bać, po to są aby z nich kozystać, to jest bezpieczne... biggrin.gif
blasfemia
No niby racja, ale jak robie cos sam to wiem jak to dokladnie dziala, moge to sobie sam rozbudowywac stosownie do wlasnych potrzeb itd. Poza tym jesli chcialbym umiescic gdzies swoja stronke (niekoniecznie ten serwis co teraz robie tylko tak w ogole) to nie moge zakladac, ze na serwerze, na ktorym chcialbym ja umiescic, php, apache czy inne "elementy" sa tak czy inaczej skonfigurowane smile.gif
Poza tym ... ciagle sie ucze.
cagrET
Cytat
:arrow: ciasta odpadaja  


HUH !
podawanie id w urlu jest bezpieczniejsze ? smile.gif
itsme
istnieje tez POST oraz SSL
mozna wszystko zastosowac ja poprostu mowie o swoich doswiadczeniach

castkami sie nie bawie :-)
Omega
Obojętnie gdzie by nie było, to i tak szansa że strzelisz numer sesji i trafisz taki który ci coś da jest bardzo małe... biggrin.gif
blasfemia
Cytat
HUH !
podawanie id w urlu jest bezpieczniejsze ? smile.gif


No wlasnie to mial byc, wedlug moich zamierzen, temat tej dyskusji czyli bezpieczenstwo/zagrozenia zwiazane z przekazywaniem sid-a w URL-u smile.gif

Cytat
Obojętnie gdzie by nie było, to i tak szansa że strzelisz numer sesji i trafisz taki który ci coś da jest bardzo małe... smile.gif


Wklepywania sid-a tak na "chybil trafil" raczej nie traktuje powaznie. Jak powiedziales, prawdopodobienstwo "trafienia" jest naprawde niewielkie.
Realnym zagrozeniem jest natomiast taka sytuacja: uzytkownik A zalogowal sie do serwisu, uzytkownik B "jakos" przechwycil sid-a i chcac namieszac wklepuje go recznie ze swojego kompa. Dlatego pomyslalem o tym zapisywaniu numeru ip. Gdy uzytkownik A loguje sie, do bazy jest zapisywany jego numer ip (razem z identyfikatorem sesji). Gdy uzytkownikA sie wylogowuje to jego sesja sie konczy i jej rekord zostaje usuniety, i wtedy uzytkownik B nic nie zrobi bo jego "przechwycony" sid jest "nieaktualny". Moze on nieszac wtedy gdy zalogowany jest uzytkownik A (z aktywna sesja) Gdy uzytkownik B chce uruchomic jakikolwiek skrypt (z podanym recznie sid-em) to jest sprawdzany numer ip z ktorego probuje to robic i jak sie nie zgadza z tym wpisanym w bazie to go "wywala". I to na razie dziala, poniewaz moj system dziala na razie tylko w sieci lokalnej. W niej moge sobie uzywajac php odczytac numer ip delikwenta (chocby odczytujac go z tablicy $_SERVER, pole "REMOTE_ADDR"). Problem pojawia sie w sytuacji logowania sie z zewnatrz sieci lokalnej. Posluze sie przykladem wspomnianej w poprzednim poscie sieci radiowej na Krakowskim rynku. Nie laczylem sie stamtad nigdy ale podejrzewam, ze koles, ktory sie podepnie do tej sieci, dostaje tymczasowy, dynamicznie przydzielony numer, ktory jest unikalny jedynie w ramach tej sieci radiowej. Na zewnatz tej sieci wszyscy jej uzytkownicy sa widoczni pod jednym numerem ip. I przykladowo jesli wspomniany prezes zaloguje sie do mojego systemu, to drugi pracownik firmy probujacy zalogowac sie z tej sieci nie zostanie wpuszczony bo bedzie mial ten sam numer ip, co wczesniej zalogowany prezes. I to dotyczy wszystkich sieci, podsieci, z ktorych ruch idzie przez proxy, maskarady i inne takie. I dlatego sa takie same numery ip, a czasami php nawet nie potrafi tego numeru odczytac sad.gif
adwol
Cytat
No wlasnie to mial byc, wedlug moich zamierzen, temat tej dyskusji czyli bezpieczenstwo/zagrozenia zwiazane z przekazywaniem sid-a w URL-u smile.gif

W/g mnie największym jest to, że można go łatwo zobaczyć podczas pracy u kogoś na monitorze. Cookie nie widać.
Zostaje też w historii, ale powiedzmy, że wtedy jest już bezużyteczny.
Cytat
Realnym zagrozeniem jest natomiast taka sytuacja [...]

Nie za bardzo rozumiem o co Ci chodzi. Nie możesz nie wierzyć niczemu. Jeśli id sesji zostanie przejęte to koniec. Można wprawdzie wprowadzić dodatkowe zabezpieczenia, ale id jest jak hasło -- masz hasło/id, masz wejście. Musisz czemuś zaufać, na czymś sie oprzeć, bo inaczej nigdy nie zrobisz meritum serwisu tylko będziesz się zastanawiał co będzie jak Ci ID sesji ukradną.
Nie należy myśleć co zrobić gdy ktoś przejmie identyfikator tylko co zrobić aby go nie przejął.

IMHO najważniejsze jest (już to tu pisałem):
:arrow: SSL, żeby wyeliminować sniffing, ataki na TCP i zachować spójność połączenia
:arrow: dobry algorytm generujący identyfikatory, aby miały dużą entropię i były naprawdę bardzo trudno zgadywalne.
:arrow: autentykacja po parze: (ID, IP), aby zawęzić ew. możliwości z ukradzionego identyfikatora do jednego IP
:arrow: timeout, aby przypadkowo zostawiona przez uzytkownika przeglądarka nie dawała cały czas wejścia do serwisu
:arrow: gdy uzywamy cookie, czas wygaśnięcia ustawiony na 0 (do zamknięcia przeglądarki), żeby cookie nie lądowały na dysku, a zamknięcie działało praktycznie jak wylogowanie

Wtedy nie ma różnicy czy ktoś się loguje z sieci lokalnej czy z zewnątrz.

Problem można oczywiście rozwijać o autoryzację hasłami jednorazowymi, wielokrotną autoryzację różnymi kanałami, itd. ale to jest temat-rzeka i na początek wystarczy to co napisałem wyżej.
Michal P.
Zainteresowal mnie ten temat i czytajac go troszke sie ciekawych rzeczy dowiedzialem smile.gif

Ale mam takie pytanko co do tego:
Cytat
I to dotyczy wszystkich sieci, podsieci, z ktorych ruch idzie przez proxy, maskarady i inne takie. I dlatego sa takie same numery ip, a czasami php nawet nie potrafi tego numeru odczytac sad.gif


Nie wiem jak to dziala z maskarada, ale adres goscia siedzacego za serwerem proxy ja uzyskiwalem w ten sposob:
Kod
(isset($_SERVER['HTTP_X_FORWARDERD_FOR'])) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'];

Wiem, bo sam jestem za proxiakiem.
adwol
Cytat
Nie wiem jak to dziala z maskarada, ale adres goscia siedzacego za serwerem proxy ja uzyskiwalem w ten sposob:

Ten sposób może być zawodny. Poszukaj na forum, problem był już dyskutowany.
gosciu
Cytat
dobry algorytm generujący identyfikatory, aby miały dużą entropię i były naprawdę bardzo trudno zgadywalne

Jesli hashowanie md5 nie wystarcza mozna uzyc sha1.

Do postulatow kolegi adwol'a dorzucil bym jeszcze wprowadzenie losowo generowane id dla formularzy (przechowywane tymczasowo w bazie).
Bakus
Proponuję następujące generowanie SID:
[php:1:72f6817ddb]<?php
// SID ma 32 znaki:
$sid = md5(base64_decode(time()));

// SID ma 64 znaki:
$sid = md5(base64_decode(time()));
$sid .= md5(base64_decode(date("dmYHis")));
?>[/php:1:72f6817ddb]

W przykładach specjalnie zastosowałem decode, by jako ciąg byłu podawane krzaczki...

Taki system gwarantuje Ci (przy drugiej możliwości) 79 228 162 514 264 337 593 543 950 336 kombinacji...
To gwarantuje bezpieczeństwo... spróbój zgadnąć jaki ja mam teraz SID w panelu administracyjmym mojej stronki, (gdzie stosuje poniższy kod)...

[php:1:72f6817ddb]<?php
// to jest początek mojej stronki (występuje na wszystkich stronach wymagających autoryzacji)
session_start(); // startujemy sesje
if(strlen(session_id()) < 64) // sprawdzamy, czy to jest nasz SID, czy wygenerowany przez php
session_id(md5(base64_decode(time())) . md5(base64_decode(date("dmYHis")))); // SID wygenerowany przez php jest zastępowany moim - 64 znakowym
?>[/php:1:72f6817ddb]

Dorzuć jeszcze SSL i nikt tego nie wykorzysta (W 99% przeglądarek to co przeglądasz przez SSL nie jest zapisywane na dysku, a tylko nieliczne zapisują adresy stron w historii - adresy - nie zawartość!)

Powyższe wskazuje chyba wyraźnie, że NIE NALEŻY przesyłać SID przez GET...

P.S. Przy pierwszym masz 1 208 925 819 614 629 174 706 176 rozwiązań... mało Ci questionmark.gif?
adwol
Cytat
W przykładach specjalnie zastosowałem decode, by jako ciąg byłu podawane krzaczki...

Nie zmieniło to w żaden sposób entropii tego źródła.
Cytat
Taki system gwarantuje Ci (przy drugiej możliwości) 79 228 162 514 264 337 593 543 950 336 kombinacji...
To gwarantuje bezpieczeństwo...

Nie wiem skąd wziąłeś taką liczbę ale jest nieprawdziwa i naprawdę mocno przesadzona. Ten algorytm, który podałeś potrafi teoretycznie wygenerować conajwyżej 2^32 różnych ID (drugi jest trochę lepszy, ale niewiele). Dodatkowo znając dzień w jakim dana osoba się zalogowała ograniczamy ten zakres do 86400, a znając godzinę do 3600. Jest to nędzna iluzja generatora identyfikatorów sesji.
Cytat
mojej stronki, (gdzie stosuje poniższy kod)...

Moje najszczersze współczucia.
Cytat
Dorzuć jeszcze SSL i nikt tego nie wykorzysta (W 99% przeglądarek to co przeglądasz przez SSL nie jest zapisywane na dysku, a tylko nieliczne zapisują adresy stron w historii - adresy - nie zawartość!)

Adresy? Używam MSIE i Mozilli i w obu z nich adresy SSLowe są tak samo zapisywane w historii jak zwykłe. Chyba, że uważasz, że te przeglądarki to jakiś marginalny segment rynku (1%).

Wybacz szczerość, ale widzę, że w którymś z kolei poscie piszesz bzdury i wprowadzasz tym samym innych w błąd.
Bakus
Niewiem czemu 2^32?? Z kąd te dwa ?
Jeżeli na każdym miejscu może być 16 znaków, to czemu 2 questionmark.gif
Jak możesz, to uzasadnij...

Czemu współczucia?? Uważasz, że jest to złe rozwiązanie?
Zaproponuj lepsze!

Cytat
Adresy? Używam MSIE i Mozilli i w obu z nich adresy SSLowe są tak samo zapisywane w historii jak zwykłe. Chyba, że uważasz, że te przeglądarki to jakiś marginalny segment rynku (1%).


U mnie (w IE) stronki zaszyfrowane są pokazywane przy offline jako niedostępne do przeglądania...
DeyV
coś mi sie wydaje, że zamiast kombinować, lepiej wykorzystać po prostu
[php:1:cf2232c2e0]<?php
mt_srand();
$sid = md5( mt_rand () );
?>[/php:1:cf2232c2e0]
spenalzo
A ja któryś raz z kolei rzucę przykład z książki PHP4. Aplikacje:
[php:1:9c912190a4]<?php
srand((double) microtime()*100000);
$id=md5(unqid(rand()));
?>[/php:1:9c912190a4]
adwol
Cytat
Niewiem czemu 2^32?? Z kąd te dwa ?
Jeżeli na każdym miejscu może być 16 znaków, to czemu 2 questionmark.gif
Jak możesz, to uzasadnij...

Co z tego, że robisz sobie z tego md5-tke, skoro tak naprawdę jedynym źródłem entropii jest u Ciebie funkcja time(), która ma właśnie tyle możliwych wartości (z czego większość można od razu odrzucić jako nieważne, o czym już pisałem). To że potem sobie ją przekształcasz za pomocą base64 czy md5 nie ma już żadnego znaczenia. Równie dobrze mógłbyś z tym czasem nawyprawiać jeszcze cuda na 100 KB kodu, ale dopóki przekstałcasz jednoznacznie jedne dane w inne nie zwiększa to ilości możliwych wyników. Elementarne aksjomaty teorii zbiorów.

Samo użycie funkcji md5 w dowolnym miejscu generatora identyfikatorów nie poprawia bezpieczeństwa. To nie jest jakaś magiczna funkcja, która podnosi bezpieczeństwo i zaawansowanie autora. Skrajnym przypadkiem nieprzemyślanego jej użycia jest:
[php:1:f41128f73d]<?php
$sid = md5('staly ciag znakow');
?>[/php:1:f41128f73d]
To też uznasz za wystarczające? Twój przykład jest bliski temu.
Cytat
Uważasz, że jest to złe rozwiązanie?

Tak
Cytat
Zaproponuj lepsze!

Podawałem już kiedyś na forum, inni też podawali.

Np.:
[php:1:f41128f73d]<?php
$sid = md5(md5(uniqid(mt_rand(), 1)) . microtime() . $_SERVER['REMOTE_ADDR'] . $_SERVER['REMOTE_PORT'] . serialize($_SERVER));
?>[/php:1:f41128f73d]
Bakus
Macie kurcze racje...

Tato podał mi wzór jak to policzyć i wyszło zaledwie 601 080 390...
faktycznie mniej... :?

Cytat
A ja któryś raz z kolei rzucę przykład z książki PHP4. Aplikacje:
[php:1:2ca76ba61e]<?php
srand((double) microtime()*100000);
$id=md5(unqid(rand()));
?>[/php:1:2ca76ba61e]


To jest chyba lepciejsze rozwiązanie...

A co do MD5 - chodzi o zawsze taką samą ilość znaków (32)...
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.