Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> Logowanie, pomoc przy logowaniu
seba199696
post 7.09.2011, 17:40:13
Post #1





Grupa: Zarejestrowani
Postów: 119
Pomógł: 0
Dołączył: 4.01.2011

Ostrzeżenie: (20%)
X----


  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
Go to the top of the page
+Quote Post
tehaha
post 7.09.2011, 17:48:16
Post #2





Grupa: Zarejestrowani
Postów: 1 748
Pomógł: 388
Dołączył: 21.08.2009
Skąd: Gdynia

Ostrzeżenie: (0%)
-----


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
Go to the top of the page
+Quote Post
bastard13
post 7.09.2011, 17:52:22
Post #3





Grupa: Zarejestrowani
Postów: 664
Pomógł: 169
Dołączył: 8.01.2010
Skąd: Kraków

Ostrzeżenie: (0%)
-----


  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


--------------------
Go to the top of the page
+Quote Post
seba199696
post 7.09.2011, 18:26:27
Post #4





Grupa: Zarejestrowani
Postów: 119
Pomógł: 0
Dołączył: 4.01.2011

Ostrzeżenie: (20%)
X----


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?

Ten post edytował seba199696 7.09.2011, 18:26:54
Go to the top of the page
+Quote Post
bastard13
post 7.09.2011, 19:00:12
Post #5





Grupa: Zarejestrowani
Postów: 664
Pomógł: 169
Dołączył: 8.01.2010
Skąd: Kraków

Ostrzeżenie: (0%)
-----


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

Ten post edytował bastard13 7.09.2011, 19:01:22


--------------------
Go to the top of the page
+Quote Post
seba199696
post 7.09.2011, 19:17:48
Post #6





Grupa: Zarejestrowani
Postów: 119
Pomógł: 0
Dołączył: 4.01.2011

Ostrzeżenie: (20%)
X----


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?

Ten post edytował seba199696 7.09.2011, 19:21:01
Go to the top of the page
+Quote Post
bastard13
post 7.09.2011, 19:33:26
Post #7





Grupa: Zarejestrowani
Postów: 664
Pomógł: 169
Dołączył: 8.01.2010
Skąd: Kraków

Ostrzeżenie: (0%)
-----


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


--------------------
Go to the top of the page
+Quote Post
seba199696
post 8.09.2011, 21:22:01
Post #8





Grupa: Zarejestrowani
Postów: 119
Pomógł: 0
Dołączył: 4.01.2011

Ostrzeżenie: (20%)
X----


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. ?>


Ten post edytował seba199696 8.09.2011, 22:24:01
Go to the top of the page
+Quote Post
bastard13
post 8.09.2011, 22:29:24
Post #9





Grupa: Zarejestrowani
Postów: 664
Pomógł: 169
Dołączył: 8.01.2010
Skąd: Kraków

Ostrzeżenie: (0%)
-----


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:)


--------------------
Go to the top of the page
+Quote Post
seba199696
post 10.09.2011, 09:53:38
Post #10





Grupa: Zarejestrowani
Postów: 119
Pomógł: 0
Dołączył: 4.01.2011

Ostrzeżenie: (20%)
X----


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.?
Go to the top of the page
+Quote Post
tehaha
post 10.09.2011, 11:52:45
Post #11





Grupa: Zarejestrowani
Postów: 1 748
Pomógł: 388
Dołączył: 21.08.2009
Skąd: Gdynia

Ostrzeżenie: (0%)
-----


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.
Go to the top of the page
+Quote Post
seba199696
post 10.09.2011, 11:56:22
Post #12





Grupa: Zarejestrowani
Postów: 119
Pomógł: 0
Dołączył: 4.01.2011

Ostrzeżenie: (20%)
X----


Czyli jak użytkownik dodaje komentarz to będzie ... WHERE iduser=$id?
Go to the top of the page
+Quote Post
tehaha
post 10.09.2011, 12:24:30
Post #13





Grupa: Zarejestrowani
Postów: 1 748
Pomógł: 388
Dołączył: 21.08.2009
Skąd: Gdynia

Ostrzeżenie: (0%)
-----


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
Go to the top of the page
+Quote Post
seba199696
post 10.09.2011, 13:00:09
Post #14





Grupa: Zarejestrowani
Postów: 119
Pomógł: 0
Dołączył: 4.01.2011

Ostrzeżenie: (20%)
X----


a przy poprawnym logowaniu przypisać id używając:

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

?
Go to the top of the page
+Quote Post
tehaha
post 10.09.2011, 13:08:19
Post #15





Grupa: Zarejestrowani
Postów: 1 748
Pomógł: 388
Dołączył: 21.08.2009
Skąd: Gdynia

Ostrzeżenie: (0%)
-----


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ę
Go to the top of the page
+Quote Post
seba199696
post 10.09.2011, 22:10:56
Post #16





Grupa: Zarejestrowani
Postów: 119
Pomógł: 0
Dołączył: 4.01.2011

Ostrzeżenie: (20%)
X----


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?

Ten post edytował seba199696 10.09.2011, 22:23:50
Go to the top of the page
+Quote Post
tehaha
post 11.09.2011, 00:13:48
Post #17





Grupa: Zarejestrowani
Postów: 1 748
Pomógł: 388
Dołączył: 21.08.2009
Skąd: Gdynia

Ostrzeżenie: (0%)
-----


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

Ten post edytował tehaha 11.09.2011, 00:18:40
Go to the top of the page
+Quote Post
bastard13
post 11.09.2011, 00:31:56
Post #18





Grupa: Zarejestrowani
Postów: 664
Pomógł: 169
Dołączył: 8.01.2010
Skąd: Kraków

Ostrzeżenie: (0%)
-----


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.


--------------------
Go to the top of the page
+Quote Post
tehaha
post 11.09.2011, 10:02:56
Post #19





Grupa: Zarejestrowani
Postów: 1 748
Pomógł: 388
Dołączył: 21.08.2009
Skąd: Gdynia

Ostrzeżenie: (0%)
-----


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
Go to the top of the page
+Quote Post
Fifi209
post 11.09.2011, 15:04:27
Post #20





Grupa: Zarejestrowani
Postów: 4 655
Pomógł: 556
Dołączył: 17.03.2009
Skąd: Katowice

Ostrzeżenie: (0%)
-----


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.


--------------------
Zainteresowania: C#, PHP, JS, SQL, AJAX, XML, C dla AVR
Chętnie pomogę, lecz zanim napiszesz: Wujek Google , Manual PHP
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Wersja Lo-Fi Aktualny czas: 10.06.2024 - 14:00