Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Logowanie
Forum PHP.pl > Forum > PHP
seba199696
  1. <?php
  2. include 'dbc.php'; //polaczenie z baza danych
  3. $user_login = htmlspecialchars(stripslashes(strip_tags(trim($_POST['username']))));
  4.  
  5.  
  6. $pass = md5(htmlspecialchars(stripslashes(strip_tags(trim($_POST['password'])))));
  7. $user_password = sha1($pass.$user_login);
  8.  
  9.  
  10. $user_log = "user_login='$user_login'";
  11. $user_pass = "user_password='$user_password'";
  12.  
  13. $result = mysql_query("SELECT `id`,`user_login`,`user_password`,`banned` FROM users WHERE
  14. $user_log AND $user_pass AND `banned` = '0'
  15. ") or die (mysql_error());
  16.  
  17.  
  18. if (mysql_num_rows($result) == 1) {
  19.  
  20. $_SESSION['user_name'] = $user_login;
  21. header('Location: index2.php');
  22.  
  23. } else {
  24. echo "Logowanie się nie powiodło :(";
  25.  
  26. }
  27. ?>


Witam, napisałem skrypt logujący użytkownika wszystko działa prawidłowo lecz chcę się dowiedzieć w jaki sposób zabezpieczyć taki skrypt przed atakami. Robię coś źle? Jakieś propozycję?

Dzięki
tehaha
a to co za wynalazek?
  1. $pass = md5(htmlspecialchars(stripslashes(strip_tags(trim($_POST['password'])))));


wepchałeś tu całą masę funkcji a i tak nie zabezpieczyłeś:
  1. $user_login = htmlspecialchars(stripslashes(strip_tags(trim($_POST['username']))));


W taki sposób do niczego nie dojdziesz...dowiedz się co robią te funkcje i w jakich sytuacjach je używać i rób to z głową, a nie na zasadzie "wepcham wszystko to będzie ok", do zabezpieczania zapytań używa się mysql_real_escape_string() dla string oraz np. rzutowanie na int (int) dla int, poczytaj sobie o sql injection, bo nawet ta funkcja w pewnych sytuacjach może nie być wystarczająca
bastard13
  1. $pass = md5(htmlspecialchars(stripslashes(strip_tags(trim($_POST['password'])))));

To, co robisz w tym kodzie jest całkowicie zbędne. Wystarczy, że użyjesz funkcji haszującej, jest to wystarczające zabezpieczenie.

  1. $user_password = sha1($pass.$user_login);

A takie zabawy są już ciekawsze:) Tylko zamiast $user_login używa się zazwyczaj soli, czyli jakiegoś indywidualnego ciągu znaków, który również zapisujesz do bazy. Możesz użyć np. funkcji http://pl2.php.net/manual/en/function.microtime.php do jego generowania.

  1. $user_login = htmlspecialchars(stripslashes(strip_tags(trim($_POST['username']))));

Wystarczy, że użyjesz metody:
http://pl2.php.net/manual/en/function.mysq...cape-string.php
Jednak osobiście uważam, że co do loginu, to walidacja powinna wyglądać trochę inaczej. Chodzi o to, że zazwyczaj login ma pewien określony zbiór znaków, z których może się składać np. litery, cyfry, _, -, spacja itp. W każdym razie zbiór dozwolonych znaków jest określony dlatego też lepiej walidować login użytkownika, a nie (tak jak ty) filtrować.
Do walidacji przydaje się funkcja:
http://pl2.php.net/manual/en/function.preg-match.php
seba199696
ok dzięki zrobie tak ja mówicie smile.gif

"Możesz użyć np. funkcji http://pl2.php.net/manual/en/function.microtime.php do jego generowania."

jeśli tego użyje to co z saltem w rejestracji?
bastard13
Sorry, z tą solą to trochę pokręciłem. Tak to jest jak się robi dziesięć rzeczy na raz:P
Sól to jest unikalny string (zazwyczaj). Może on być zahardcodowany w pliku lub zapisany w bazie. Dzięki niej ciężej jest odkryć hasło, które zostało przepuszczone przez funkcję haszującą.
Twoją solą może być np. 'sad8%$9sdk' lub cokolwiek zechcesz. Im bardziej przypadkowy jest to zbiór znaków, tym lepiej.
I tą właśnie sól doklejasz do hasła, które przesłał użytkownik, nie ważne czy to rejestracja, czy logowanie.
http://en.wikipedia.org/wiki/Salt_%28cryptography%29
seba199696
Mógłbyś mi wytłumaczyć o co chodzi z mysql_real_escape_string? Czytałem tego manuala ale coś nie bardzo smile.gif

  1. $query = sprintf("SELECT * FROM users WHERE user='%s' AND password='%s'",


o co chodzi?
bastard13
Cytat
mysql_real_escape_string() calls MySQL's library function mysql_real_escape_string, which prepends backslashes to the following characters: \x00, \n, \r, \, ', " and \x1a.

a tutaj jak chcesz masz po polsku:
http://php-manual.skryptoteka.pl/function....ape-string.html
seba199696
Poprawiłem skrypt, teraz dobrze?

  1. <?php
  2. // Connect
  3. define ("DB_HOST", "xxx"); // set database host
  4. define ("DB_USER", "xxx"); // set database user
  5. define ("DB_PASS","xxx"); // set database password
  6. define ("DB_NAME","users"); // set database name
  7.  
  8. $link = mysql_connect(DB_HOST, DB_USER, DB_PASS) or die("Couldn't make connection.");
  9. $db = mysql_select_db(DB_NAME, $link) or die("Couldn't select database");
  10.  
  11. $uzytkownik = stripslashes($_POST['login']);
  12. $haslo = stripslashes(sha1($_POST['password'].'sad8%$9sdk'));
  13. } else {
  14. $uzytkownik = $_POST['login'];
  15. $haslo = sha1($_POST['password'].'sad8%$9sdk');
  16. }
  17. $query = sprintf("SELECT * FROM users WHERE user_login='%s' AND user_haslo='%s'",
  18.  
  19. mysql_query($query, $link);
  20.  
  21. if (mysql_affected_rows($link) > 0) {
  22.  
  23. $_SESSION['user_name'] = $uzytkownik;
  24. $_SESSION['HTTP_USER_AGENT'] = sha1($_SERVER['HTTP_USER_AGENT'].'dsd#$%^');
  25. header('Location: index2.php');
  26.  
  27. } else {
  28. echo "Logowanie nie powidło się :)";
  29. }
  30. ?>
bastard13
Tak na pierwszy rzut oka to ok.
Usunąłbym jednak te constant value. Po co ci one? I tak z bazą łączysz się raz. Już prędzej wykorzystałbym to do przechowywania soli.
A następny krok to OOP:)
seba199696
Ok smile.gif Mam jeszcze jedno pytanie, przeczytałem gdzieś "Nie trzymaj w sesji nazwy użytkownika tylko np. wspomniany już losowy identyfikator..." to jak użytkownik będzie edytował treści itp.?
tehaha
w sesji trzymasz to co potrzebujesz oprócz hasła. Przeważnie trzyma się id, nazwa użytkownika, e-mail, czas ostatniego logowanie i co tam jeszcze potrzebne. Poza tym nigdy nie identyfikuj użytkownika po jego nazwie, ani w ogóle żadnego innego rekordu po nazwie - zawsze używaj do tego celu unikalnego numeru ID.
seba199696
Czyli jak użytkownik dodaje komentarz to będzie ... WHERE iduser=$id?
tehaha
tak, ale dla zabezpieczenia dajesz jeszcze rzutowanie na int czyli
  1. " WHERE iduser=".(int)$id
i analogicznie odwołujesz się do innych rekordów z pozostałych tabel czyli np.
  1. UPDATE news WHERE news_id = ".(int)$id itd.
to id w bazie ustawiasz pole INT może być UNSIGNED, autoincrement i primary key, oczywiście są też sytuacje gdzie robi się primary key z kilku kolumn ale na początek powinno Ci wystarczyć, że rozróżnianie rekordów, edycja usuwanie na podstawie pola ID

Jak użytkownik dodaje komentarz to w tabeli trzymasz jego ID
czyli masz tabelę:
comments:
- comment_id (int)
- comment_text (text)
- comment_date (timestamp)
- comment_user (int) - i tutaj trzymasz jego numer ID
seba199696
a przy poprawnym logowaniu przypisać id używając:

  1. $row = mysql_fetch_assoc($query);
  2. $_SESSION['user_id'] = $row['user_id'];

?
tehaha
dokładnie, możesz również przypisać inne przydatne rzeczy, np. przypiszesz sobie nazwę użytkownika to będziesz mógł zrobić
  1. echo 'Witaj '.$_SESSION['user_name']
generalnie tego typu kwestii jest jeszcze mnóstwo to co tu wspomnieliśmy to zaledwie wierzchołek góry lodowej, dlatego polecałbym bym Ci poszukać sobie w dziale Książki jakąś fajną książkę bo to najlepszy sposób na opanowanie podstaw i wbrew pozorom o wiele szybszy niż takie mozolne kombinowanie na własną rękę
seba199696
Dzięki smile.gif

Mam jeszcze jedno pytanko smile.gif

w bazie mam user_id, user_login, user_haslo

1. user_id pole typ INT UNSIGNED autoincrement primary key
2. user_login typ?
3. user_haslo typ?

Co najlepiej wybrać do loginu i hasła? VARCHAR?
tehaha
tak oba varchar, ponieważ zezwalasz na użycie dowolnych znaków( various characters) na początek możesz dawać varchar(255), no chyba, że wprowadzasz walidację odnośnie maksymalnej długości wtedy pole nieodpowiednio mniejsze, jak już będziesz bardziej zaawansowany to warto precyzyjniej dobierać długość. W przypadku hasła pozwalasz na użycie dowolnych znaków, natomiast w przypadku loginu przeważnie zezwala się wyłącznie na znaki alfanumeryczne, czyli litery i cyfry
bastard13
A ja mam tylko pytanie po co to rzutowanie na integer przy id użytkownika? Przecież ta wartość jest pobierana z bazy i trzymana w sesji, a więc wiemy, że jest poprawna. A w zapytaniu tak samo na zadziała '1'(string) oraz 1(integer). Nie widzę żadnego powodu, aby robić coś takiego.
tehaha
Cytat
A ja mam tylko pytanie po co to rzutowanie na integer przy id użytkownika? Przecież ta wartość jest pobierana z bazy i trzymana w sesji, a więc wiemy, że jest poprawna.

no może akurat w tym przypadku w kodzie proceduralnym nie będzie to konieczne, ale przecież w praktyce zmienne są podawane do metody jako argumenty i zapytanie trzeba odpowiednio zabezpieczyć bez wnikania skąd to będzie pochodziło bo różnie może być metoda użyta. Wydaje mi się, że też jako początkujący lepiej jak się nauczy zabezpieczać 100% przypadków, bo potem są takie sytuacje, gdzie bez namysłu skopiuje sobie gotowe zapytanie na inną podstronę zamieni $_SESSION na $_GET i luka gotowa

Cytat
A w zapytaniu tak samo na zadziała '1'(string) oraz 1(integer).
Tak, w mysql tak samo zadziała
  1. user_id = 1 oraz user_id = '1'
więc, tutaj można mówić jedynie o dobrym nawyku programowania, skoro mamy pole typu int to powinniśmy podawać int, a nie parsować string
Fifi209
Chciałbym dodać do wypowiedzi tehaha, co to typów, że jeżeli hashujesz hasło, to warto zastosować pole o stałej długości czyli char zamiast varchar.
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.