Более безопасный вход в систему и управление сеансами


я работаю над логином, чтобы немного приватизировать веб-приложение, которое я делаю. Мои знания не то чтобы базовые, но и не самые лучшие, и мне нужна помощь.

нет метода регистрации. Запись Я сделаю лично из базы данных. Что мне нужно, это советы или способы, чтобы сделать этот логин, а затем, сеанс управления, безопаснее, надежнее, лучше структура документов. php в каталоге корень...

на данный момент единственное, что я применяю, это PDO и оператор prepare, чтобы избежать SQL-инъекций.

структура документов:

  • Login.php (вот форма, и где выполняются функции.) Это PHP код, который есть перед заголовком для управления логином:

    if (isset($_POST['entrar'])) {
        require "functions.php";
        $error = [];
        $user = ValidUser($error);
        if(empty($error)){
            logearUsuario($user);
            header("Location: application.php");
        }
    }
    

    имена переменных, которые будут собраны form: user (пользователь), pass (password) и Enter(submit)

  • Conn.php (В этот документ необходим для подключения к базе данных, в этом случае MySQL, но в будущем он изменится на PostgreSQL. Это функция, которая включает в себя все, что нужно для подключения)

    function connection(){
    
        try{
    
            $dsn = 'mysql:host=localhost; dbname=controlusuarios';
            $userBBDD = 'root';
            $passBBDD = '';
            $conn  = new PDO($dsn, $userBBDD, $passBBDD);
            return $conn;
    
        }catch(Exception $e){
    
            die('Error: ' . $e->GetMessage());
    
        }
    }
    
  • Functions.php (он содержит несколько функций. Один для проверки пользователя, а другой для его входа. Условие logeo возникает в документе login.php)

    function validUser(&$error){
    
        if((!isset($_POST['user'])) || (!isset($_POST['pass']))){
            $error[0] = "Usuario y/o contraseña incorrectos.";
            return null;
        }
        $user = $_POST['user'];
        $pass = $_POST['pass'];
        if(($user == '') || ($pass == '')){
            $error[0] = "Usuario y/o contraseña incorrectos.";
            return null;
        }else{
    
            $con = connection();
            $sql = "SELECT name FROM usuarios WHERE name = :user AND password = :pass";
            $query = $con->prepare($sql);
            $query-> bindParam(':user', $user);
            $query-> bindParam(':pass', $pass);
            $query-> execute();
            $contador = $query -> rowCount();
            if($contador != 1){
                $error[0] = "Usuario y/o contraseña incorrectos.";
                return null;
            }
            $con = null;
            return $user;
        }
    
     }
    
     function logearUsuario($user){
    
        session_start();
        $_SESSION['name'] = $user;
    
     }
    
Author: Alvaro Montoro, 2018-02-01

1 answers

Я не эксперт по безопасности, но, основываясь на коде, которым вы поделились, я вижу некоторые проблемы/моменты, которые можно улучшить:

  1. Идентификатор сеанса не изменяется после изменения состояния в логине

    На самом деле не так много видно, как вы относитесь к сеансу, но невооруженным глазом кажется, что вы открываете его, когда пользователь входит в систему (я не знаю, открывается ли он раньше или нет), и сохраняете имя пользователя, не выглядя так, как будто ничего не делается.

    Регенерировать идентификатор сеанса каждый раз, когда происходит изменение уровня привилегий пользователя (например, при входе в систему или при отключении), является рекомендуемой практикой OWASP, которая служит для предотвращения нескольких атак, таких как захват сеанса, фиксация сеанса или верховая езда сеанса (известный под аббревиатурой CSRF или XSRF).

    В PHP вы можете восстановить идентификатор сеанса, используя session_regenerate_id(), что применяется к вашему коду будет выглядеть что-то так:

    function logearUsuario($user){
    
        session_start();
        session_regenerate_id();
        $_SESSION['name'] = $user;
    
    }
    

  2. Сеанс, похоже, не истекает

    Опять же, на самом деле не так много, как вы относитесь к сеансу, но когда вы входите в систему, кажется, что вы просто сохраняете имя пользователя, не имея ничего другого.

    Было бы идеально, если бы вы сохранили дату входа, а затем каждый раз, когда выполняется операция или загружается страница, проверяли дату и проверяли, что она находится в соответствующем диапазоне ,чтобы выполнить соответствующее действие (обновить или закрыть сессия).

    Например, если прошло более 10 минут без действий, истечь сеанс (путем регенерации идентификатора с изложенным в предыдущем пункте) и отправить пользователя на логин. И если прошло не более этих 10 минут, то обновите счетчик снова, чтобы дать ему еще 10 минут.

    Как указано на странице OWASP об истечении срока действия сеансов (мой перевод):

    Чтобы свести к минимуму время, в течение которого злоумышленник может начать атаку в вашем сеансе активируйте и захватите их, обязательно установите время истечения срока действия для каждого сеанса, установив время, в течение которого сеанс будет оставаться активным.

    Необходимо принять меры для выхода из системы по истечении срока действия как на стороне клиента, так и на стороне сервера (хотя здесь мы видим только часть PHP).


  3. Вы не наказываете неудачи

    Когда пользователь неправильно вводит свой пароль, вы просто показываете ему сообщение об ошибке, и все готово. Что происходит если пользователь не совершил ошибку, а является злоумышленником, проверяющим, есть ли удача и правильный пароль?

    Не наказывая ошибки при входе в систему, код уязвим для атак грубой силы. Злоумышленник (который может быть программой / ботом) просто должен отправить много попыток паролей, пока один из них не сработает и не получит доступ к привилегированной учетной записи.

    Решение атаки грубой силы в логине было бы добавить какой-то блокировка после нескольких попыток. Например: после X сбоев, заблокировать учетную запись на М минут. И если по истечении этого времени он снова терпит неудачу, увеличьте значение M, следуя некоторой схеме серьезности.

    Другим возможным решением было бы потребовать CAPTCHA после X неудачных попыток и каждый раз, когда он снова терпит неудачу.


  4. Информация о подключении к базе данных находится в самом коде

    Как указано это страница OWASP и также в этом другом (мой перевод):

    Наличие паролей, записанных в код, может поставить под угрозу безопасность системы способами, которые не могут быть легко исправлены.

    Никогда не рекомендуется иметь пароль, написанный непосредственно в коде. Это не только позволяет всем разработчикам проекта видеть пароль, но и делает решение проблемы довольно сложной. Как только код в производстве этот пароль не может быть изменен без исправления программного обеспечения. Если учетная запись, защищенная этим паролем, была скомпрометирована, владельцы системы будут вынуждены выбирать между безопасностью или доступностью.

    Также, если по какой-либо причине сервер перестает правильно обрабатывать PHP-код и отображается в виде простого текста (что-то редкое, но может произойти), данные соединения будут видны любому.

    В идеале, информация о подключении к база данных будет находиться в отдельном файле и вне корня веб-сайта. Таким образом, он не будет доступен извне сервера и не будет доступен для потенциальных шпионов (внешних или внутренних).


  5. Ключи не хэшируются

    Это проблема, если кому-то удается взломать вашу систему и получить доступ к базе данных: системы входа должны быть разработаны с учетом возможности того, что в какой-то момент они могут сбой и данные в конечном итоге скомпрометированы (, как указано в OWASP).

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

    Для этого вам нужно хэшировать пароль, сохранив его в базе данных, а затем проверить пароль, переданный в форме, с хэшем, чтобы сделать проверка (в PHP может быть использована password_verify).

    Преимущество использования хеширования над алгоритмами шифрования заключается в том, что путем шифрования пароля могут быть способы его описания; вместо этого с хешированием нет пути назад. Если бы база данных была скомпрометирована, по крайней мере, пароли пользователя не были бы потеряны (я знаю, что для вас это не может быть большим утешением, но для пользователя это может быть, учитывая, что многие используют одни и те же пароли с сайта на другое).


Кроме того, можно сделать некоторые комментарии о том, как соединения с базой данных управляются (подключаясь и отключаясь с каждым запросом), хотя это было бы больше на уровне производительности, чем безопасности.

И вы также должны были бы оценить некоторые другие вещи, которые вы не можете увидеть в общем коде. Например: используете ли вы HTTPS для входа? как данные сохраняются в базе данных?

Вы можете найти больше рекомендации по безопасности на странице OWASP (и, в частности, для сессий).

 8
Author: Alvaro Montoro, 2018-02-02 17:17:31