O przepraszam, mając hash masz spore szanse odzyskania hasła. Poczytajcie o tęczowych tablicach. W internecie są też strony typu
http://md5.rednoize.com/ które zawierają 50 000 000 najpopularniejszych haseł i hashy. Więc to nie jest takie trudne. Najlepszą obroną jest solenie hashowanych stringów.
Ale to była taka mała dygresja.
Wracając do tematu. Najlepsze są rozwiązania najprostsze.
Przy rejestracji zapisujesz w bazie: id, login, hash hasła.
Prz próbie zalogowania robisz: SELECT * FROM user WHERE `login`='$login' AND `pass`=MD5('$pass');
Jeśli to zapytanie zwróci ilość rekordów różną od 1 to znaczy, że coś jest nie tak: nie ma usera, złe hasło etc.
Jeśli wszystko jest OK, apisujemy do sesji np id i login. Nie ma sensu niczego więcej, chyba że jest to dla Ciebie wygodne.
Teraz, żeby sprawdzić czy user jest zalogowany sprawdzamy czy te dane istnieją w sesji.
Aby wylogować usera usuwamy jest z sesji.
Najsłabszym ogniwem tego rozwiązania jest zapytanie do bazy, mamy tu dane które pochodzą od użytkownika. Dlatego najaważniejsz rzeczą jest taka konfiguracja serwera i fitlrowanie zapytań, aby uniemożliwić SQL injection.
To wszystko, nie ma sposobu, żeby oszukać taki system jeśli jest dobrze zaprojektowany.
Istnieją jeszcze dwa niebezpieczeństwa, jednemu możesz zapobiec, drugiemu możesz tylko próbować:
1) Zła konfiguracja serwera, która pozwoliłaby w jakiś sposób uzyskać atakującemu do katalogu z sesjami (czy do bazy z sesjami, jeśli masz własny mechanizm obsługi sesji) Ale szczerze wątpie żeby istniał tak lamowaty admin serwera

2) Zdobycie przez atakującego identyfikatora sesji ofiary. To już poważniejszy problem, bo atakujący może działać na koncie ofiary. Musisz tak przygotować swój serwis, aby nie dało się dokonać Code Insertion. (konkretnie chodzi o wstrzyknięcie javascriptu lub innego języka skryptowego który pozwala na dostęp do ciasteczek) Ale to już jest temat rzeka, bo nawet największe serwisy sobie z tym nie zawsze radzą.
Pozdrawiam!