Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770
Форумы портала PHP.SU :: Версия для печати :: Безопасный логин
Форумы портала PHP.SU » » Вопросы новичков » Безопасный логин

Страниц (1): [1]
 

1. jaroslav.tavgen - 02 Января, 2015 - 20:10:46 - перейти к сообщению
Понадобилось решить тривиальную задачу: сделать так, чтобы пользователь получил доступ к странице на сайте только если введёт правильные логин и пароль.

Посмотрел в Google, как сделать этот процесс наиболее безопасным. И ахнул: Google мне выдал вот такую бандуру: http://www[dot]wikihow[dot]com/Create-a-[dot][dot][dot]in-PHP-and-MySQL (первый результат по запросу в Google "PHP secure login")

У меня вопрос: действительно ли для безопасной авторизации нужно делать ВСЁ ЭТО? Или можно обойтись чем-то попроще, и безопасность всё равно будет соблюдена?

(при этом их вариант не работает: редирект на нужную страницу делается с помощью header, который не передаёт сессии, а проверка на то, залогинился ли пользователь, делается именно по сессии).
2. kotyara1979 - 02 Января, 2015 - 20:39:19 - перейти к сообщению
Цитата:
при этом их вариант не работает: редирект на нужную страницу делается с помощью header, который не передаёт сессии, а проверка на то, залогинился ли пользователь, делается именно по сессии


Переадресация через header и не должна передавать сессию. Сессия вообще не передается никак. Это сгенерённая кука в браузере. И при старте сессии пхп просто проверяет есть такая запись и соответствует ли она существующим записям на сервере.

А вообще безопасность - это та вещь, где не экономят. Вопрос только в целесообразности накручивания механизмов: насколько "вкусные" вещи лежат за паролем, сколько времени люди захотят потратить на взлом, сколько времени вам понадобится на восстановление сломанного.

Короче каждый решает сам.
3. jaroslav.tavgen - 02 Января, 2015 - 21:00:26 - перейти к сообщению
kotyara1979 пишет:
Переадресация через header и не должна передавать сессию. Сессия вообще не передается никак. Это сгенерённая кука в браузере. И при старте сессии пхп просто проверяет есть такая запись и соответствует ли она существующим записям на сервере.

В их варианте после того, как пользователь ввёл правильные логин и пароль, делается переадресация:

PHP:
скопировать код в буфер обмена
  1.    if (login($email, $password, $mysqli) == true) {
  2.         // Login success
  3.         header('Location: ../protected_page.php');


А страница protected_page.php вызывает функцию из другого файла, в которой делается следующая проверка:

PHP:
скопировать код в буфер обмена
  1.     if (isset($_SESSION['user_id'],
  2.                         $_SESSION['username'],
  3.                         $_SESSION['login_string'])) {


Переменной $_SESSION при этом не существует (проверял с помощью echo get_defined_vars()), поэтому страница всегда выдаёт надпись "You are not logged in".

kotyara1979 пишет:
А вообще безопасность - это та вещь, где не экономят. Вопрос только в целесообразности накручивания механизмов: насколько "вкусные" вещи лежат за паролем, сколько времени люди захотят потратить на взлом, сколько времени вам понадобится на восстановление сломанного.

Короче каждый решает сам.

Я ничего не имею против максимального обеспечения безопасности. Проблема в том, что я не понимаю, что должен делать тот код, а если его просто тупо скопировать (что я и сделал) - он не работает... Ну вот проверяет этот код наличие superglobal $_SESSION, которой не существует независимо от того, залогинен ты или нет - и как мне понять, почему этот скрипт не работает так, как должен?
4. esterio - 02 Января, 2015 - 21:13:24 - перейти к сообщению
jaroslav.tavgen пишет:
(при этом их вариант не работает: редирект на нужную страницу делается с помощью header, который не передаёт сессии, а проверка на то, залогинился ли пользователь, делается именно по сессии).

передаються не сессии а кука с ИД сессии. передаете не вы, а браузер в заголовках запроса (исключением являеться инициализация сессии).
jaroslav.tavgen пишет:
Переменной $_SESSION при этом не существует (проверял с помощью echo get_defined_vars()), поэтому страница всегда выдаёт надпись "You are not logged in".

Это суперглобальный массив. он всегда существует
jaroslav.tavgen пишет:
залогинен ты или нет - и как мне понять, почему этот скрипт не работает так, как должен?
jaroslav.tavgen пишет:
if (isset($_SESSION['user_id'],
$_SESSION['username'],
$_SESSION['login_string'])) {

примерно так проверяеться, а не проверкой ести ли массив $_SESSION. правда достаточно просто проверить ИД
5. kotyara1979 - 02 Января, 2015 - 21:15:01 - перейти к сообщению
Проверьте как отрабатывается старт сессии. В вашем случае, за это отвечает функция sec_session_start(). Посмотрите, что она делает, доходит ли там до старта сессии.

Глобальный массив _SESSION будет доступен только при старте сессии.
6. jaroslav.tavgen - 02 Января, 2015 - 21:20:57 - перейти к сообщению
esterio пишет:
Это суперглобальный массив. он всегда существует

echo (get_defined_vars()) не показывает его. А указанный мной выше "if isset..." даёт FALSE.

kotyara1979 пишет:
Проверьте как отрабатывается старт сессии. В вашем случае, за это отвечает функция sec_session_start(). Посмотрите, что она делает, доходит ли там до старта сессии.

Как это можно проверить?
7. esterio - 02 Января, 2015 - 21:25:34 - перейти к сообщению
jaroslav.tavgen пишет:
echo (get_defined_vars()) не показывает его. А указанный мной выше "if isset..." даёт FALSE.

а session_start не забили?
8. jaroslav.tavgen - 02 Января, 2015 - 21:26:52 - перейти к сообщению
Весь процесс происходит так: заходишь на файл login.php. Вводишь логин и пароль. Скрипт перенаправляет тебя на страницу /includes/process_login.php, которая выглядит очень просто:

PHP:
скопировать код в буфер обмена
  1. <?PHP
  2. include_once 'db_connect.php';
  3. include_once 'functions.php';
  4.  
  5. sec_session_start(); // Our custom secure way of starting a PHP session.
  6.  
  7. if (isset($_POST['email'], $_POST['p'])) {
  8.     $email = $_POST['email'];
  9.     $password = $_POST['p']; // The hashed password.
  10.  
  11.     if (login($email, $password, $mysqli) == true) {
  12.         // Login success
  13.        header('Location: ../protected_page.php');
  14.     } else {
  15.         // Login failed
  16.         header('Location: ../login.php?error=1');
  17.     }
  18. } else {
  19.     // The correct POST variables were not sent to this page.
  20.     echo 'Invalid Request';
  21. }


(Если в ней поставить echo (get_defined_vars()), то переменная $_SESSION существует, а вот на protected_page.php - уже нет)

Проверка осуществляется с помощью функции login - функция, которая находится в functions.php и выглядит так:

PHP:
скопировать код в буфер обмена
  1. function login($email, $password, $mysqli) {
  2.     // Using prepared statements means that SQL injection is not possible.
  3.     if ($stmt = $mysqli->prepare("SELECT id, username, password, salt
  4.        FROM members
  5.       WHERE email = ?
  6.        LIMIT 1")) {
  7.         $stmt->bind_param('s', $email);  // Bind "$email" to parameter.
  8.         $stmt->execute();    // Execute the prepared query.
  9.         $stmt->store_result();
  10.  
  11.         // get variables from result.
  12.         $stmt->bind_result($user_id, $username, $db_password, $salt);
  13.         $stmt->fetch();
  14.  
  15.         // hash the password with the unique salt.
  16.         $password = hash('sha512', $password . $salt);
  17.         if ($stmt->num_rows == 1) {
  18.             // If the user exists we check if the account is locked
  19.             // from too many login attempts
  20.  
  21.             if (checkbrute($user_id, $mysqli) == true) {
  22.                 // Account is locked
  23.                 // Send an email to user saying their account is locked
  24.                 return false;
  25.             } else {
  26.                 // Check if the password in the database matches
  27.                 // the password the user submitted.
  28.                 if ($db_password == $password) {
  29.                     // Password is correct!
  30.                     // Get the user-agent string of the user.
  31.                     $user_browser = $_SERVER['HTTP_USER_AGENT'];
  32.                     // XSS protection as we might print this value
  33.                     $user_id = preg_replace("/[^0-9]+/", "", $user_id);
  34.                     $_SESSION['user_id'] = $user_id;
  35.                     // XSS protection as we might print this value
  36.                     $username = preg_replace("/[^a-zA-Z0-9_\-]+/",
  37.                                                                 "",
  38.                                                                 $username);
  39.                     $_SESSION['username'] = $username;
  40.                     $_SESSION['login_string'] = hash('sha512',
  41.                               $password . $user_browser);
  42.                     // Login successful.
  43.                     return true;
  44.                 } else {
  45.                     // Password is not correct
  46.                     // We record this attempt in the database
  47.                     $now = time();
  48.                     $mysqli->query("INSERT INTO login_attempts(user_id, time)
  49.                                    VALUES ('$user_id', '$now')");
  50.                     return false;
  51.                 }
  52.             }
  53.         } else {
  54.             // No user exists.
  55.             return false;
  56.         }
  57.     }
  58. }
  59.  

Функция старта сессии sec_session_start() тоже находится в functions.php и выглядит так:
PHP:
скопировать код в буфер обмена
  1. function sec_session_start() {
  2.     $session_name = 'sec_session_id';   // Set a custom session name
  3.     $secure = SECURE;
  4.     // This stops JavaScript being able to access the session id.
  5.     $httponly = true;
  6.     // Forces sessions to only use cookies.
  7.     if (ini_set('session.use_only_cookies', 1) === FALSE) {
  8.         header("Location: ../error.php?err=Could not initiate a safe session (ini_set)");
  9.         exit();
  10.     }
  11.     // Gets current cookies params.
  12.     $cookieParams = session_get_cookie_params();
  13.     session_set_cookie_params($cookieParams["lifetime"],
  14.         $cookieParams["path"],
  15.         $cookieParams["domain"],
  16.         $secure,
  17.         $httponly);
  18.     // Sets the session name to the one set above.
  19.     session_name($session_name);
  20.     session_start();            // Start the PHP session
  21.     session_regenerate_id();    // regenerated the session, delete the old one.
  22. }

(Добавление)
esterio пишет:
jaroslav.tavgen пишет:

echo (get_defined_vars()) не показывает его. А указанный мной выше "if isset..." даёт FALSE.


а session_start не забили?


protected_page.php:
PHP:
скопировать код в буфер обмена
  1.  
  2. <?PHP
  3. include_once 'includes/db_connect.php';
  4. include_once 'includes/functions.php';
  5. sec_session_start();
  6. ?>
  7. <!DOCTYPE html>
  8. <html>
  9.     <head>
  10.         <meta charset="UTF-8">
  11.         <title>Secure Login: Protected Page</title>
  12.         <link rel="stylesheet" href="styles/main.css" />
  13.     </head>
  14.     <body>
  15.         <?PHP if (login_check($mysqli) == true) : ?>
  16.             <p>Welcome <?PHP echo htmlentities($_SESSION['username']); ?>!</p>
  17.             <p>
  18.                 This is an example protected page.  To access this page, users
  19.                 the user, so pages will be able to determine the type of user
  20.                 must be logged in.  At some stage, we'll also check the role of
  21.                 authorised to access the page.
  22.             </p>
  23.             <p>Return to <a href="index.php">login page</a></p>
  24.         <?PHP else : ?>
  25.             <p>
  26.                 <span class="error">You are not authorized to access this page.</span> Please <a href="index.php">login</a>.
  27.             </p>
  28.         <?PHP endif; ?>
  29.     </body>
  30. </html>

(Добавление)
Функция login_check:
PHP:
скопировать код в буфер обмена
  1. function login_check($mysqli) {
  2.     // Check if all session variables are set
  3.     if (isset($_SESSION['user_id'],
  4.                         $_SESSION['username'],
  5.                         $_SESSION['login_string'])) {
  6.                                                 echo 1;
  7.  
  8.         $user_id = $_SESSION['user_id'];
  9.         $login_string = $_SESSION['login_string'];
  10.         $username = $_SESSION['username'];
  11.  
  12.         // Get the user-agent string of the user.
  13.         $user_browser = $_SERVER['HTTP_USER_AGENT'];
  14.  
  15.         if ($stmt = $mysqli->prepare("SELECT password
  16.                                      FROM members
  17.                                      WHERE id = ? LIMIT 1")) {
  18.             // Bind "$user_id" to parameter.
  19.             $stmt->bind_param('i', $user_id);
  20.             $stmt->execute();   // Execute the prepared query.
  21.             $stmt->store_result();
  22.  
  23.             if ($stmt->num_rows == 1) {
  24.                 // If the user exists get variables from result.
  25.                 $stmt->bind_result($password);
  26.                 $stmt->fetch();
  27.                 $login_check = hash('sha512', $password . $user_browser);
  28.  
  29.                 if ($login_check == $login_string) {
  30.                     // Logged In!!!!
  31.                     return true;
  32.                 } else {
  33.                     // Not logged in
  34.                     return false;
  35.                 }
  36.             } else {
  37.                 // Not logged in
  38.                 return false;
  39.             }
  40.         } else {
  41.             // Not logged in
  42.             return false;
  43.         }
  44.     } else {
  45.         echo 2;
  46.         // Not logged in
  47.         return false;
  48.     }
  49. }
  50.  
9. kotyara1979 - 02 Января, 2015 - 21:38:41 - перейти к сообщению
А у вас вывод ошибок включен?
error_reporting, какой уровень?
10. jaroslav.tavgen - 02 Января, 2015 - 21:42:40 - перейти к сообщению
Насчёт $_SESSION, конечно, перепутал: она действительно всегда существует, но на странице /includes/process_login.php в ней есть значения, а на странице protected_page.php она пустая...

kotyara1979 пишет:
А у вас вывод ошибок включен?
error_reporting, какой уровень?

Какой уровень error_reporting не знаю (узнаю чуть позже), но ошибки выводятся.
11. jaroslav.tavgen - 03 Января, 2015 - 21:49:55 - перейти к сообщению
echo error_reporting() даёт ответ 30711

 

Powered by ExBB FM 1.0 RC1