Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Logowanie dwuskładownikowe
Forum PHP.pl > Forum > PHP
inomi13
Witam ma poniższy kod, który po wpisaniu poprawnego hasła wysyła na skrzynkę e-milową kod weryfikacyjny w celu zalogowaniu do Panelu. Proszę o sugestie i ewentualne uwagi czy to co zrobiłem zdaje egzamin i czy kod jest bezpieczny

index.php
  1. <?php
  2. if ((isset($_SESSION['logged'])) && ($_SESSION['logged']==true))
  3. {
  4. header('Location: panel.php');
  5. exit();
  6. }
  7. if (isset($_SESSION['e_error']))
  8. {
  9. echo $_SESSION['e_error'];
  10. unset($_SESSION['e_error']);
  11. }
  12. ?>
  13. <!DOCTYPE HTML>
  14. <html lang="pl">
  15. <head>
  16. <title>Panel logowania</title>
  17. </head>
  18. <body>
  19. <main>
  20. <?php
  21. if(!isset($_SESSION['email']))
  22. {
  23. ?>
  24. <div class="container">
  25. <form action="login.php" method="post">
  26. <input type="email" name="email" placeholder="Adres e-mail:" onfocus="this.placeholder=''" onblur="this.placeholder='login:'" required ><br />
  27. <input type="password" name="pass" placeholder="Hasło:" onfocus="this.placeholder=''" onblur="this.placeholder='hasło:'" pattern="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[?!@#$%^&*])[A-Za-z\d!@#?$%^&*]{8,}$" title="Hasło musi zawierać minimum 8 znaków składających się z co najmniej jednej cyfry, jednej wielkiej i małej litery oraz znaku specjalnego:" required><br />
  28. <button type="submit">ZALOGUJ <i class="fas fa-sign-in-alt"></i></button><br/>
  29. <a href="pass_reset.php">Zapomniałeś hasła</a>
  30. </form>
  31. <?php
  32. if (isset($_SESSION['error']))
  33. {
  34. echo '<div class="error">'.$_SESSION['error'].'</div>';
  35. unset($_SESSION['error']);
  36. }
  37. }
  38. else
  39. {
  40. ?>
  41. </div>
  42. <div class="container">
  43. <form action="login.php" method="post">Kod weryfikacyjny został wysłany na adres e-mail powiązany z Twoim kontem.<br />
  44. <input type="password" name="code_verify" placeholder="Kod weryfikacyjny:" onfocus="this.placeholder=''" onblur="this.placeholder='Kod:'" minlength="8" ><br />
  45. <button type="submit" name="submit_code">ZALOGUJ <i class="fas fa-sign-in-alt"></i></button><br/>
  46. </form>
  47. <?php
  48. if (isset($_SESSION['error']))
  49. {
  50. echo '<div class="error">'.$_SESSION['error'].'</div>';
  51. unset($_SESSION['error']);
  52. }
  53. }
  54. ?>
  55. </div>
  56. </main>
  57. </body>
  58. </html>





login.php
  1. <?php
  2. require_once "connect.php";
  3. $connect = @new mysqli($host, $db_user, $db_password, $db_name);
  4.  
  5. if ($connect->connect_errno!=0)
  6. {
  7. $cod_error = $connect->connect_errno;
  8. $error = '<div class="alert alert-danger"><strong>Błąd '.$cod_error.'!</strong> Przepraszamy za niedogodności i prosimy o wykonanie operacji w innym terminie!</div>';
  9. $_SESSION['e_error'] = $error;
  10. header('Location: index.php');
  11. exit();
  12. }
  13. else
  14. {
  15. if (isset($_POST['submit_code']))
  16. {
  17. $all_ok=true;
  18. $code_verify=$_POST['code_verify'];
  19. $result_code = $connect->query("SELECT id, name, roles FROM persons WHERE code_verify='$code_verify' AND email='{$_SESSION['email']}'");
  20.  
  21. if (!$result_code) throw new Exception($connect->error);
  22.  
  23. $how_code = $result_code->num_rows;
  24.  
  25. if($how_code>0)
  26. {
  27. unset($_SESSION['error']);
  28. $row = $result_code->fetch_assoc();
  29. $_SESSION['logged'] = true;
  30. $_SESSION['id'] = $row['id'];
  31. $_SESSION['name'] = $row['name'];
  32. $_SESSION['roles'] = $row['roles'];
  33.  
  34. switch($row['roles'])
  35. {
  36.  
  37. case "1":
  38. header('Location: admin/panel.php');
  39. break;
  40.  
  41. case "0":
  42. header('Location: panel.php');
  43. break;
  44. }
  45. }
  46. else
  47. {
  48. $all_ok=false;
  49. $_SESSION['error']='Wprowadzono błędny kod weryfikacyjny';
  50. header('Location: index.php');
  51. exit();
  52. }
  53. }
  54. else
  55. {
  56. $email = $_POST['email'];
  57. $pass = $_POST['pass'];
  58. $email = htmlentities($email, ENT_QUOTES, "UTF-8");
  59. if ($result = @$connect->query(sprintf("SELECT email, pass FROM persons WHERE email='%s'",mysqli_real_escape_string($connect,$email))))
  60. {
  61. $users = $result->num_rows;
  62. if($users>0)
  63. {
  64. $row = $result->fetch_assoc();
  65.  
  66. if (password_verify($pass, $row['pass']))
  67. {
  68. $codeAlphabet= substr(str_shuffle("0123456789"), 0, 8);
  69.  
  70. if ($connect->query("UPDATE `persons` SET `code_verify` = '$codeAlphabet' WHERE email='$email'"))
  71. {
  72. require "PHPMailer/PHPMailerAutoload.php";
  73.  
  74. $mail = new PHPMailer();
  75. $mail->CharSet = "UTF-8";
  76. $mail->IsSMTP();
  77. $mail->SMTPAuth = true;
  78.  
  79. $mail->SMTPSecure = 'ssl';
  80. $mail->Host = '***********';
  81. $mail->Port = 465;
  82. $mail->Username = '***********';
  83. $mail->Password = '***********';
  84.  
  85. $mail->IsHTML(true);
  86. $mail->From='***********';
  87. $mail->FromName='Tytuł';
  88.  
  89. $mail->AddReplyTo('***********');
  90. $mail->Subject = 'Tytuł';
  91. $mail->AddEmbeddedImage('img/logo.png', 'logo');
  92. $mail->Body ="<center><img class=logo src=\"cid:logo\" width=250px height=60px width=20%>
  93. <br/>Wprowadź $codeAlphabet aby się zalogować.</a><br />";
  94. $mail->AddAddress($email);
  95. if(!$mail->Send())
  96. {
  97. echo '<div class="alert alert-danger"><strong>Błąd!</strong> Kod nie został wysłany, prosimy o wykonanie operacji w innym terminie!</div>';
  98. }
  99. else
  100. {
  101. $_SESSION['email'] = $row['email'];
  102. header('Location: index.php');
  103. }
  104. }
  105. }
  106. else
  107. {
  108. $_SESSION['error'] = 'Błędny login lub hasło!';
  109. header('Location: index.php');
  110. }
  111. }
  112. }
  113. $connect->close();
  114. }
  115. }
  116. ?>
viking
Nic tu nie jest w porządku. Zaczynając od ogromnego bałaganu, pomieszania kodu. Wstawiasz dane z POST do zapytania - sql injection.
inomi13
Poprawiłem bałagan w kodzie jednak mam problem ponieważ utknąłem i nie wiem czy idę dobrą drogą tzn. jeżeli występuje użytkownik i został zweryfikowany to następuje wysłanie kodu weryfikacyjnego na skrzynkę e-mail. I teraz rodzi się problem czy sprawdzenie kodu zrobić w osobnym pliku? w części tego kodu? jak się do tego zabrać? Czy w ogóle ma sens bawienie się w dwu składnikowe logowanie... sad.gif


  1. <?php
  2. if ((!isset($_POST['email'])) || (!isset($_POST['pass'])))
  3. {
  4. header('Location: index.php');
  5. exit();
  6. }
  7.  
  8. require_once "connect.php";
  9. $connect = @new mysqli($host, $db_user, $db_password, $db_name);
  10.  
  11. if ($connect->connect_errno!=0)
  12. {
  13. $cod_error = $connect->connect_errno;
  14. $_SESSION['e_error'] = '<div class="alert alert-danger"><strong>Błąd '.$cod_error.'!</strong> Przepraszamy za niedogodności i prosimy o wykonanie operacji w innym terminie!</div>';
  15. header('Location: index.php');
  16. exit();
  17. }
  18. else
  19. {
  20. $email = htmlentities($_POST['email'], ENT_QUOTES, "UTF-8");
  21.  
  22. if ($result = @$connect->query(sprintf("SELECT * FROM persons WHERE email='%s'", mysqli_real_escape_string($connect,$email))))
  23. {
  24. $row = $result->fetch_assoc();
  25. if (($result->num_rows == 1) && (password_verify($_POST['pass'],$row['pass'])))
  26. {
  27. $codeAlphabet= substr(str_shuffle("0123456789"), 0, 8);
  28. if (@$connect->query(sprintf("UPDATE `persons` SET `code_verify` = '$codeAlphabet' WHERE email='%s'", mysqli_real_escape_string($connect,$email))))
  29. {
  30. require "PHPMailer/PHPMailerAutoload.php";
  31.  
  32. $mail = new PHPMailer();
  33. $mail->CharSet = "UTF-8";
  34. $mail->IsSMTP();
  35. $mail->SMTPAuth = true;
  36.  
  37. $mail->SMTPSecure = 'ssl';
  38. $mail->Host = '***********';
  39. $mail->Port = 465;
  40. $mail->Username = '***********';
  41. $mail->Password = '***********';
  42.  
  43. $mail->IsHTML(true);
  44. $mail->From='***********';
  45. $mail->FromName='***********';
  46.  
  47. $mail->AddReplyTo('***********');
  48. $mail->Subject = 'Tytuł';
  49. $mail->AddEmbeddedImage('img/logo.png', 'logo');
  50. $mail->Body ="<center><img class=logo src=\"cid:logo\" width=250px height=60px width=20%>
  51. <br/>Wprowadź $codeAlphabet aby się zalogować.</a><br />";
  52. $mail->AddAddress($email);
  53. }
  54. if(!$mail->Send())
  55. {
  56. $_SESSION['e_error'] = '<div class="alert alert-danger">Błąd!</strong> Kod nie został wysłany, prosimy o wykonanie operacji w innym terminie!</div>';
  57. header('Location: index.php');
  58. exit();
  59. }
  60. else
  61. {
  62. $_SESSION['logged'] = true;
  63. $_SESSION['id'] = $row['id'];
  64. $_SESSION['name'] = $row['name'];
  65. $_SESSION['email'] = $row['email'];
  66. $_SESSION['roles'] = $row['roles'];
  67.  
  68. unset($_SESSION['error']);
  69. $result->free_result();
  70.  
  71. switch($_SESSION['roles'])
  72. {
  73. case "1":
  74. header('Location: admin/panel.php');
  75. break;
  76. exit();
  77.  
  78. case "0":
  79. header('Location: panel.php');
  80. break;
  81. exit();
  82. }
  83. }
  84. }
  85. else
  86. {
  87. $_SESSION['error'] = '<div class="error">Błędny login lub hasło!</div>';
  88. header('Location: index.php');
  89. }
  90. }
  91. $connect->close();
  92. }
  93. ?>
nospor
Cytat
Czy w ogóle ma sens bawienie się w dwu składnikowe logowanie...

No wlasnie juz wczoraj sie ciebie chcialem zapytac: a po grzyba ci to dwuskladnikowe logowanie biggrin.gif

Co do kodu:
jak widze takie kwiatki
$email = htmlentities($_POST['email'], ENT_QUOTES, "UTF-8");
od osoby, ktora juz pisze jakis czas, to nie wiem co mam myslec.... Po co robisz htmlentities przed wlozeniem do warunku w bazie? Po co ja sie pytam? Wiesz co robi ta funkcja? A wiesz co robi mysqli_real_escape_string?
Bo najwyrazniej nie wiesz. Jakbys wiedzial, to bys pierwszej nie uzywal wink.gif

A po drugie: skoro uzywasz mysqli to wez poczytaj o BINDowaniu i zapomnisz w ogole o takich cudach na kiju
inomi13
  1. $email = htmlentities($_POST['email'], ENT_QUOTES, "UTF-8");
oraz mysqli_real_escape_string- aby nie było SQL injection oraz pozbyć się html'ów. Oczywiście trochę jest to nie potrzebne skoro określiłem w inpucie że ma to być input type="email".
nospor
Jak juz pisalem htmlentities jest totalnie zbedne tutaj.
inomi13
Ok przekonaliście mnie że lepiej skupić się na popranym kodzie
viking
Cytat(inomi13 @ 17.02.2021, 16:31:07 ) *
skoro określiłem w inpucie że ma to być input type="email".

A jak sobie w twoim formie zmienię na text?
dublinka
Rejestracja z podanem kodu czy kliknieciem w link w majlu to rozumiem ale logowanie ?

Kiedys napisalem takie cos.

register, login i plik confirm gdzie sprawdzisz czy user istnieje, zmienisz w bazie jego status na "zarejestrowany" zamiast "tmp" i inne wg uznania.
inomi13
Uprościłem kod oraz dodałem bindowanie. Proszę o sprawdzenie czy teraz jest wszystko ok.

  1. <?php
  2. if ((!isset($_POST['email'])) || (!isset($_POST['pass'])))
  3. {
  4. header('Location: index.php');
  5. exit();
  6. }
  7.  
  8. require_once "connect.php";
  9. $connect = @new mysqli($host, $db_user, $db_password, $db_name);
  10.  
  11. if ($connect->connect_errno!=0)
  12. {
  13. $cod_error = $connect->connect_errno;
  14. $_SESSION['e_error'] = '<div class="alert alert-danger"><strong>Błąd '.$cod_error.'!</strong> Przepraszamy za niedogodności i prosimy o wykonanie operacji w innym terminie!</div>';
  15. header('Location: index.php');
  16. exit();
  17. }
  18. else
  19. {
  20. $result = $connect->prepare("SELECT * FROM persons WHERE email=?");
  21.  
  22. $result -> bind_param('s', $_POST['email']);
  23.  
  24. $result->execute();
  25. $result_bind = $result->get_result();
  26.  
  27. $row = $result_bind->fetch_assoc();
  28. if (($result_bind->num_rows == 1) && (password_verify($_POST['pass'],$row['pass'])))
  29. {
  30. $_SESSION['logged'] = true;
  31. $_SESSION['id'] = $row['id'];
  32. $_SESSION['name'] = $row['name'];
  33. $_SESSION['email'] = $row['email'];
  34. $_SESSION['roles'] = $row['roles'];
  35.  
  36. unset($_SESSION['error']);
  37. $result->free_result();
  38.  
  39. switch($_SESSION['roles'])
  40. {
  41. case "1":
  42. header('Location: admin/panel.php');
  43. break;
  44. exit();
  45.  
  46. case "0":
  47. header('Location: panel.php');
  48. break;
  49. exit();
  50. }
  51. }
  52. else
  53. {
  54. $_SESSION['error'] = '<div class="error">Błędny login lub hasło!</div>';
  55. header('Location: index.php');
  56. }
  57. $connect->close();
  58. }
  59. ?>
viking
Teraz jeszcze dodaj https://www.php.net/manual/en/filter.filters.validate.php (FILTER_VALIDATE_EMAIL)
Zastanów się po co użytkownikowi systemu kod błędu mysql? Dzięki temu mógłbyś się pozbyć htmla z tego kodu.
Ten adres email jest jakiś unikalny w bazie? Poczytaj też o wyjątkach - na całe szczęście trwa obecnie dyskusja żeby były domyślnie włączone w mysqli.
inomi13
muszę robić walidacje adresu e-mail skoro wmam ustawione type inputa ?
  1. <input type="email" name="email" placeholder="Adres e-mail:" required />

Wcześniej miałem ustawione logowanie za pomocą identyfikatora jednak stwierdziłem że lepiej będzie zrobić logowanie za pomocą adresu e-mail.
nospor
Uzytkownik moze bez najmniejszego problemu zmienic ten typ pola i wstawic tam co mu sie zywnie podoba.
Generalnie do logowania nie widze potrzeby fitrowania/walidacji. Ale do rejestracji juz obowiazkowo
dublinka
A najlepiej daj adres strony to bedziesz mial jak na dloni bledy
inomi13
faktycznie w przeglądarce podmieniłem type="email" na type="text"a w bazie zmieniłem login nie będący adresem e-mail i się zalogowałem facepalmxd.gif
W takim razie jednak trzeba zrobić (FILTER_VALIDATE_EMAIL)
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.