Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [MySQL][PHP]poprawność skryptu logowania
Forum PHP.pl > Forum > Przedszkole
gawar
Witam, Napisałem skryp który odpowiada za zalogowanie do systemu. Prosiłbym o sprawdzenie czy jest on bezpieczny i co jeszcze można w nim zmienić żeby był bardziej bezpieczny.
Na początku jest formularz logowania którego przedstawiać nie będę. dalej jest sprawdzenie czy dane użytkownika i hasło jest ok sprawdz_log.php:
  1. <?php
  2.  
  3. include_once ('polacz.php'); // dane logowania do bazy
  4.  
  5. //error_reporting(E_ALL);
  6.  
  7. if (!isset($_POST['login'], $_POST['pass'])) {
  8.  
  9. echo'Błąd brak dane nie istnieją.';
  10.  
  11. exit();
  12. }
  13. if (!empty($_POST['login']) && !empty($_POST['pass'])) {
  14.  
  15. $login_l = filter_var($_POST['login'], FILTER_SANITIZE_STRING);
  16. $pass = filter_var($_POST['pass'], FILTER_SANITIZE_STRING);
  17. $sol='sas@#ść123';
  18. $password_l = sha1($pass . $sol);
  19.  
  20. echo $passwod_l;
  21. try {
  22. $stmt = $sth->prepare('SELECT id_user, login FROM logowanie
  23.  
  24. WHERE login = :login_l AND pass = :password_l');
  25.  
  26. $stmt->bindParam(':login_l', $login_l, PDO::PARAM_STR);
  27.  
  28. $stmt->bindParam(':password_l', $password_l, PDO::PARAM_STR, 40);
  29.  
  30. $stmt->execute();
  31.  
  32. if ($stmt->rowCount() == 1) {
  33. foreach ($stmt as $r)
  34. {
  35. $login = $r["login"];
  36. $id_user = $r["id_user"];
  37. }
  38. $_SESSION['id_user'] = $id_user;
  39. $_SESSION['login'] = $login;
  40. header("Location: ../index.php");
  41. }
  42. else{
  43. echo'Wprowadź poprawne dane logowania';
  44. echo' <br/><a href=../login.php>Zaloguj</a>';
  45. }
  46. } catch (PDOException $e) {
  47. echo 'Error!: Wystąpił błąd', $e->getMessage();
  48. die();
  49. }
  50. }
  51. else {
  52. echo "Wprowadź dane logowania";
  53. echo' <br/><a href=../login.php>Zaloguj</a>';
  54. }
  55. ?>

następnie plik index.php a w nim:
  1. <?php
  2. if (!isset($_SESSION['generated']) || $_SESSION['generated'] < (time() - 30))
  3. {
  4. $_SESSION['generated']= time();
  5. }
  6.  
  7. //error_reporting(E_ALL);
  8. include_once ('go/polacz.php');
  9. include_once ('go/sesje.php');
  10.  
  11. echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  12. <html xmlns="http://www.w3.org/1999/xhtml">
  13. <head>
  14. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  15. <title>system</title>
  16. <link href="go/style.css" rel="stylesheet" type="text/css" media="screen"/>
  17. <link rel="stylesheet" href="go/drukuj.css" type="text/css" media="print" />
  18. </head>
  19. <body>
  20. <div class="container">
  21. </br>Zalogowany jako: '.$_SESSION['login'].'</br><a href=go/wyloguj.php>Wyloguj</a></div>
  22. <div class="sidebar1">
  23. <ul class="nav">';
  24. include_once 'go/menu.php';
  25. echo'</ul>
  26.  
  27. <!-- end .sidebar1 --></div>
  28.  
  29. <div class="content">';
  30.  
  31. if (isset( $_GET['id'])){
  32.  
  33. $nr = $_GET['id'];
  34.  
  35. include_once "go/$nr";
  36.  
  37. } else include "go/start.html";
  38.  
  39. </div>
  40. </div>
  41. </body>
  42. </html>';

i plik sprawdzania sesji sesje.php :
  1. <?php
  2. if(!isset($_SESSION['id_user']))
  3. {
  4. echo "Proszę się zalogować!!!.";
  5. exit();
  6. }
  7. else
  8. {
  9. try
  10. {
  11. $stmt = $sth->prepare('SELECT login FROM logowanie
  12. WHERE id_user = :user_id');
  13. $stmt->bindParam(':user_id', $_SESSION['id_user'], PDO::PARAM_INT);
  14. $stmt->execute();
  15. $phpro_username = $stmt->fetchColumn();
  16. if($phpro_username == false)
  17. {
  18. echo "błąd dostępu!!!.";
  19. exit();
  20. }
  21. else
  22. {
  23. $message = 'Witamy '.$phpro_username;
  24. }
  25. }
  26. catch (Exception $e)
  27. {
  28. $message = 'Błąd zapytania"';
  29. }
  30. }
  31. ?>


1.Teraz mam pytanie czy np jak mam podłączone menu w index.php ( include_once 'go/menu.php';) to czy w pliku menu.php powinienem dodawać session_start(); i sprawdzać je za pomocą pliku sesje.php? i tak w każdym przypadku czyli każdy plik do którego jest odnośnik w menu? Pytam bo pliki ładuje do głownego pliku index.php za pomocą tego kodu z index.php:
  1. <div class="content">';
  2.  
  3. if (isset( $_GET['id'])){
  4.  
  5. $nr = $_GET['id'];
  6.  
  7. include_once "go/$nr";
  8.  
  9. }

I potem z danej pod strony mam odnośniki czy formularze które prowadzą do następnych pod stron czy danych pobieranych z bazy ale wszystko ląduje do index.php do konkretnego diva.

2. Jak powinna wyglądać struktura tych plików? Plik login.php w kórym jest formularz logowania w głównym katalogu wraz z index.php czy bez niego? a pozostałe pliki już w pod katalogach? Czy powinny mieć inne prawa dostępu? Jeżeli tak to jakie żeby były wykonywalne tylko przez serwer?

Nigdy wcześniej nie pisałem takigo logowania więc proszę o wyrozumiałość i pomoc:) Z góry bardzo dziękujęexclamation.gif!
ZaXaZ
Na oko bezpieczne,
Turson napisał w tym poscie link do jego artykułu, myślę że się przyda jak chodzi o strukturę, a co do menu nie musisz dawać session_start tak samo do footer.php jeśli masz itd. Powinno wystarczyć że dasz w pliku na którym jest logowanie/rejestracja oraz w pliku na który przechodzisz session_start(); (np index.php, podstrona.php) no chyba że masz dostęp do apache, i możesz zmienić żeby samo włączało sesję.

edit: ps. polecam przy okazji przeczytać pierwsze parę postów w linku który dałem, bo trochę jest o bezpieczeństwie;
nospor
$pass = filter_var($_POST['pass'], FILTER_SANITIZE_STRING);
Czemu ograniczasz uzytkownikowi trudnosc jego hasla? Jak koles chce miec skomplikowane haslo to powinienie miec do tego prawo. A Ty tym swoim czyszczeniem zabierasz mu te prawo
kartin
Sama idea logowania wygląda poprawnie. Jednak jak zauważył nospor filtrowanie hasła (FILTER_SANITIZE_STRING) jest bezcelowe.

Hasło można solić w pętli:
  1. <?php
  2.  
  3. $login_l = filter_var($_POST['login'], FILTER_SANITIZE_STRING);
  4. $sol = 'sas@#ść123';
  5.  
  6. $password_l = '';
  7. for ($i = 0; $i < DUZA_LICZBA; $i++) {
  8. $password_l = sha1($_POST['pass'] . $password_l . $sol);
  9. }
lub użyć hash_pbkdf2()

  1. if (isset( $_GET['id'])){
  2.  
  3. $nr = $_GET['id'];
  4.  
  5. include_once "go/$nr";
  6.  
  7. } else include "go/start.html";
W ciągu ograniczonym znakiem " PHP szuka zmiennych, w ograniczonym ' nie szuka niczego a przez to działa minimalnie szybciej:
  1. if (isset($_GET['id'])) {
  2. $nr = $_GET['id'];
  3. include_once 'go/' . $nr;
  4. } else
  5. include 'go/start.html';
  6. }


Należy poprawić </br> na <br />. include nie jest funkcją a konstrukcją języka więc nie trzeba używać ()

Wyświetlanie kodu HTML za pomocą echo jest niewłaściwe (należy oddzielać kod aplikacji od jej wyglądu), jednak nie wpływy na bezpieczeństwo.
Ostatecznie można zrobić:
  1. <?php
  2. if (!isset($_SESSION['generated']) || $_SESSION['generated'] < (time() - 30)) {
  3. $_SESSION['generated'] = time();
  4. }
  5.  
  6. //error_reporting(E_ALL);
  7. include_once 'go/polacz.php';
  8. include_once 'go/sesje.php';
  9. ?>
  10. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  11. <html xmlns="http://www.w3.org/1999/xhtml">
  12. <head>
  13. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  14. <title>system</title>
  15. <link href="go/style.css" rel="stylesheet" type="text/css" media="screen"/>
  16. <link rel="stylesheet" href="go/drukuj.css" type="text/css" media="print" />
  17. </head>
  18. <body>
  19. <div class="container">
  20. </br>Zalogowany jako: <?php echo $_SESSION['login'] ?><br /><a href=go/wyloguj.php>Wyloguj</a>
  21. </div>
  22. <div class="sidebar1">
  23. <ul class="nav">';
  24. <?php
  25. include_once 'go/menu.php';
  26. ?>
  27. </ul>
  28. <!-- end .sidebar1 -->
  29. </div>
nospor
Cytat
Hasło można solić w pętli:
A co to niby ma dac procz faktu, ze latwiej bedzie mozna wpasc na kolizje a co za tym idzie latwiej "zlamac" haslo?
kartin
Rzeczywiście pętla nie wniesie nic dla bezpieczeństwa.

Warto jednak byłoby dodatkowo dla każdego użytkownika stosować inną losowa sól zapisaną w bazie obok skrótu hasła. Można też użyć funkcji generującej dłuższy skrót np. SHA-256
gawar
dziękuję Wam bardzo za odpowiedźsmile.gif
1.Rozumiem że w przypadku hasła powinienem sprawdzić tylko czy te pole zostało czymś uzupełnione?
2. Jak z tymi prawami dostępu do plików i gdzie jakie pliki powinny być umieszczone?
3. Czy warto dla każdego użytkownika systemu dawać osobną sól? Użytkowników będzie raptem może 3 osoby.
4. Na co muszę zwrócić jeszcze uwagę odnośnie bezpieczeństwa? Będę korzystał dla swojego systemu z serwera współdzielonego
5. Czy należy o czymś wiedzieć jak się wykupuje SSL dla domeny?
ZaXaZ
Cytat(gawar @ 26.04.2014, 11:06:34 ) *
3. Czy warto dla każdego użytkownika systemu dawać osobną sól? Użytkowników będzie raptem może 3 osoby.
4. Na co muszę zwrócić jeszcze uwagę odnośnie bezpieczeństwa? Będę korzystał dla swojego systemu z serwera współdzielonego

3. zależy gdzie będziesz trzymał informacje jaki użytkownik ma jaką sól, bo jak w jednej bazie to jak ktoś się wlamie będzie miał łatwiej złamać hasła, bo na tacy by miał podane;
4. Poczytaj o DDoS, SpamAssasin - więcej nie wiem.
gawar
Mam jeszcze jedno pytanie aby się upewnic że dobrze rozumuje. Jeżeli Mam plik index.php w nim dołączony plik menu.php i w nim odnośniki takiego typu:

<a href="index.php?id=link.php">link</a> to rozumim że w pliku link.php nie musze dawac session_start()? i jeżeli na tej podstronie mam np formularz i po kliknięciu wyślij on przenosi użytkownika do następnej podstrony (wszystko w ramach jednego diva w index.php) to też nie jest potrzebne session_start()?

Żeby uniknąć tych DDOS zrobić mechanizm captcha czy np 3 błędne logowania i blokada? Co by było najlepsze a jednocześnie nie zatrudne do napisania?
Turson
session_start() ma być tam gdzie potrzebna jest sesja.
Jeżeli masz index.php i includujesz menu.php zawierające jedynie link, to w menu.php session_start nie musi być.

DDoS z logowaniem ma mało wspólnego, jak już to brute force.
Co do zabezpieczenia logowania - https://www.google.com/recaptcha/intro/index.html
gawar
Dostęp do systemu ma być tylko dla zalogowanych użytkowników, rozumiem że w takim razie w każdym pliku do którego potem prowadzi osnośnik ma być session_start() i sprawdzenie czy jest ok? to że wszystko jest includowane do jednego diva w pliku głównym index.php nie wyklucza z tych plików session_start()?

Co do
Cytat
Co do zabezpieczenia logowania - https://www.google.com/recaptcha/intro/index.html
to wolałbym korzystać z własnych funkcjonalności niż z propozycji google gdyż w tym serwisie będą dane osobowe i nie chciałbym żeby google to czytało.
Turson
Najprościej będzie jak stronę zbudujesz na podstronach oparty o zmienną $_GET
Np. index.php
  1. <?php
  2. if(isset($_SESSION['logged')){
  3. echo '<a href="index.php?page=podstrona">Podstrona</a>/<a href="index.php?page=podstrona2">Podstrona2</a>';
  4. switch($_GET['page']){
  5. case "podstrona": include('podstrona.php');break;
  6. case "podstrona2": include('podstrona2.php');break;
  7. default: include('home.php');
  8. }
  9. }

tym sposobem session_start() umieszczasz tylko w index.php, w podstrona i podstrona2.php już nie.
gawar
a jak na pod stronie potem mam następny odnośnik albo formularz i coś potem dalej przetwarza to jak to wtedy zrobić?
Turson
Jeżeli odnośnik lub formularz odnosi się poza index.php to w docelowym pliku znowu session_start(), ale kolejny odnośnik możesz zbudować znowu w $_GET['page'], np. index.php?page=podstrona&action=dodaj - wtedy to dalej jest w index, więc sesji inicjować nie trzeba. Najprościej jak sobie sam to sprawdzisz na kilku przykładach.
gawar
korzystam z GET tylko mam to inaczej rozwiązane
  1. if (isset( $_GET['id'])){
  2.  
  3. $nr = $_GET['id'];
  4.  
  5. include_once "go/$nr";
  6.  
  7. } else include "go/start.html";

Czy ktoś mógłby jeszcze coś podpowiedzieć odnośnie
2. Jak z tymi prawami dostępu do plików i gdzie jakie pliki powinny być umieszczone?
4. Na co muszę zwrócić jeszcze uwagę odnośnie bezpieczeństwa? Będę korzystał dla swojego systemu z serwera współdzielonego
5. Czy należy o czymś wiedzieć jak się wykupuje SSL dla domeny?
Turson
include_once "go/$nr";
To jest niebezpieczne, bo nie filtrujesz w żaden sposób $_GET['id'] i można dowolnie poruszać się między katalogami! Dlatego właśnie podałem przykład ze switch case
gawar
Nie wiem czy dobrze zrozumiełm.
  1. <div class="menu">
  2. <p>Menu:</p>
  3. <?php
  4. include_once('page/menu.php'); // w menu znjadują się te dwa odnośniki<a href="index.php?page=podstrona">Podstrona</a>
  5. //<br/><a href="index.php?page=podstrona2">Podstrona2</a>
  6. ?>
  7.  
  8. </div>
  9. <div class="reszta">
  10. <?php
  11.  
  12.  
  13. switch($_GET['page']){
  14. case "podstrona": include('page/1.php');break; //do tej podstrony można się dostać poprzez link z menu
  15. case "podstrona2": include('page/2.php');break;//do tej podstrony można się dostać poprzez link z menu i
  16. //w niej jest formularz który po nacisnięciu przycisku wyślij prowadzi do pliku dodaj.php a jego akcja to action="index.php?page=podstrona2&page=dodaj"
  17. case "dodaj": include('page/dodaj.php');break; //to rozumiem też ma się znaleźć w głównym pliku index.php? tak jak teraz
  18. default: include('home.php');
  19.  
  20. }?>
  21. </div>

Czy poniższy kod jest poprawny jeżeli chce się dostać z jednej podstrony do innej której nie ma w menu?? To działa, ale czy jest bezpieczne?
Turson
Rozwiązanie dużo lepsze niż poprzednie. Jest ok.
gawar
Witam, Muszę odświeżyć temat bo te sesje chyba nie działają tak jak powinny działaćsad.gif

Jeżeli ktoś ma czyste intencje i wchodzi do systemu tak jak należy to jest ok, ale w przypadku gdyby ktoś próbował odgadnąć nazwę katalogu w którym są inne pliki php to mu się to uda:(
załóżmy że mamy katalog public_html a w nim
-login.php
-index.php //tylko dla zalogowanych
#katalog //tutaj pozostałe pliki php z funkcjami itd.

I teraz jakby ktoś odgadł nazwę tego katalogu z plikami i nazwę pliku jak i parametr z którym plik wyświetli jakieś dane to jest kiszka:(
dodałem sesion_start do załózmy pliku x.php który jest w "katalog" jak i includowany plik sesje.php który jest wyżej ale to nie rozwiązuje problemu, a na dodatek dla zalogowanego użytkownika jak wejdzię po zalogowaniu do pliku x.php (oczywiście poprzez menu) to wyskakuje notice.
Notice: A session had already been started - ignoring session_start()

Dodałem też do pliku x.php tylko include_once ('sesje.php'); bez session_start() i to chyba załatwia sprawę teraz jak próbuje wbić się na "hama" to wyskakuje komunikat proszę się zalogować.

Ale czy tak właśnie powinno to wyglądać? Jak prawidłowo powinno to być zrobione? Jakie prawa nadać na te katalogi? Czy przenieść ważne pliki które tylko sa includowane poprze sam kod gdzies do innego katalogu?questionmark.gif Bardzo proszę o pomoc
nospor
Katalog, ktory zawierac bedzie niepubliczne dane/pliki ma byc:
albo poza katalogiem dostepnym z przegladarki
albo mniec np. plik .htaccess o takiej tresci:
Kod
order deny,allow
deny from all
gawar
A czy te rozwiązanie które według mnie działa dobrze jest OK?
nospor
Od biedy moze byc.... ale to zalezy tez od tego co te includowane pliki robią.
Najbezpieczeniej by bylo jakbys zrobil jak pisalem.
gawar
Dziękuję za pomoc:)

a Czy możliwe że na localhost mi to zadziała w sensie .htaccess
Kod
order deny,allow
deny from all

a na hostingu już nie?
nospor
A nie mozesz sprawdzic?

Na normalnych hostingach to dziala.
gawar
No właśnie nie działa i mnie to troche dziwi. Czy temu plikowi się nadaje jakieś prawa dostępu? plik ten ma 644 a katalog w którym się on znajduje 755
nospor
No ale czym sie objawia to niedzialanie?
No i czy hosting ma w ogole apache?
gawar
tak ma apache. Jak próbuje wpisać z palca ścieżkę do pliku, który znajduje się w tym katalogu z .htaccess to mam do niego dostęp. A na localhost mi blokuje.
nospor
Moze twoj hosting wylaczyc obslugie htaccess
kartin
Jeszcze odnośnie haseł: Safe Password Hashing
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.